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
@@ -0,0 +1,192 @@
1
+ /**
2
+ * The plugin's own Remote: "which engine does this session run?" and "move this
3
+ * session to another engine", both answered from the plugin's own per-session
4
+ * record, the session's live agent, and the durable log through one shared read.
5
+ *
6
+ * The browser half cannot answer the first question honestly from what the
7
+ * harness hands a page. The client Session list carries `projectionValues`
8
+ * computed by `@deepseek-ai/dsh-api-session-controller`'s `projectionsFor()`,
9
+ * which returns a `SessionProjectionHints` snapshot — "every currently cached
10
+ * wire value", and partial by its own documentation: a cell the page's cache has
11
+ * not folded yet is simply absent. The engine a session ACTUALLY runs is not a
12
+ * cache fact at all, so the plugin becomes its own authority:
13
+ *
14
+ * - node half (here): a Typert Remote service, discovered by the host Gateway
15
+ * through its visible `typertRemote` binding and its `@Remote` method marks
16
+ * (`bindTypertRemote` / `@Remote` in `@deepseek-ai/dsh-typert-protocol`, the
17
+ * same mechanism `@deepseek-ai/dsh-agent-presets` uses for its own roster).
18
+ * Both endpoints go through {@link engineReportOfSession} /
19
+ * {@link RouterLoop.reportEngine} / {@link RouterLoop.selectEngine} — the very
20
+ * reads the router routes on — so what a session is driven by and what a
21
+ * session is shown as running cannot disagree, because there is one answer.
22
+ * The report carries the ONE case in which a session has two facts (a live
23
+ * agent and a record that did not displace it) as two fields rather than
24
+ * blending them; see {@link SessionEngineReport}.
25
+ * - browser half (`src/client/session-engine.ts`): mounts these endpoints as
26
+ * `remote.loopEngine.engine({ sessionId })` and
27
+ * `remote.loopEngine.select({ sessionId, engine })`, and renders only what
28
+ * they answer.
29
+ *
30
+ * Both methods take a PLAIN object parameter rather than an identity the Gateway
31
+ * resolves: typert resolves a parameter named `agent`/`session` into a LIVE
32
+ * object through its lookup providers, and these endpoints must answer for any
33
+ * PERSISTED session — including one no process has loaded.
34
+ *
35
+ * Wire contract (no codegen is involved; the Gateway derives the signature from
36
+ * the live method):
37
+ *
38
+ * - endpoint `loopEngine/engine`;
39
+ * - endpoint `loopEngine/select`;
40
+ * - one `src-json` argument per endpoint whose wire name is the method's own
41
+ * parameter name (`request`) — REQUIRED for the browser half to be
42
+ * understood, so the parameter name is part of the contract and must not be
43
+ * renamed or destructured (see the Gateway's `methodParameterNames`);
44
+ * - `engine` results in the plain-JSON {@link SessionEngineReport} — the engine
45
+ * the session ACTUALLY runs, plus (only while a live agent the record did not
46
+ * displace keeps running) the one the record names; `select` results in the
47
+ * plain-JSON {@link LoopEngineSelectResult} — a refusal is a VALUE, so a
48
+ * predictable "no" travels as data the surface can render (a
49
+ * {@link LoopEngineRefusalCode} plus the host's own sentence as detail, which
50
+ * is what lets the browser half show localized copy instead of a raw English
51
+ * one-liner), while only a malformed request is a `RemoteError`, and an
52
+ * outcome carrying `reload` tells the browser half to reload the page, because
53
+ * the switch was made to land by releasing the session's agent.
54
+ *
55
+ * @module dsh-loop-engine-allinone/engine-remote
56
+ */
57
+ import type { Context } from '@deepseek-ai/cordis';
58
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
59
+ import { SessionId } from '@deepseek-ai/dsh-session';
60
+ import { type LoopEngineId, type SessionEngine, type SessionEngineReport, type LoopEngineSelectResult } from './agent-preset-ids.ts';
61
+ /** Cordis service key AND wire namespace of the plugin's own Remote. */
62
+ export declare const LOOP_ENGINE_REMOTE_KEY = "loopEngine";
63
+ /** Endpoint method reporting one session's engine. */
64
+ export declare const LOOP_ENGINE_REMOTE_METHOD = "engine";
65
+ /** Endpoint method moving one session to another engine. */
66
+ export declare const LOOP_ENGINE_REMOTE_SELECT_METHOD = "select";
67
+ /** The wire request the reporting endpoint accepts. */
68
+ export interface LoopEngineRequest {
69
+ /** The session to report on. A plain string, never a resolved live object. */
70
+ readonly sessionId: string;
71
+ }
72
+ /**
73
+ * The wire request the switching endpoint accepts. The engine is typed as a
74
+ * string because that is what the wire carries; the endpoint validates it
75
+ * against {@link LOOP_ENGINE_IDS} before anything acts on it.
76
+ */
77
+ export interface LoopEngineSelectRequest {
78
+ /** The session to move. A plain string, never a resolved live object. */
79
+ readonly sessionId: string;
80
+ /** The engine that session should run. */
81
+ readonly engine: string;
82
+ }
83
+ /**
84
+ * The engine one session runs, read from the plugin's own record and the durable
85
+ * log (`engineOfSession`).
86
+ *
87
+ * The FALLBACK answer, not the whole one: it knows nothing about a live agent, so
88
+ * the endpoint uses it only while no router is mounted
89
+ * ({@link RouterSurfaceHolder}) — the mount window, in which no session is driven
90
+ * by this plugin anyway.
91
+ */
92
+ export type SessionEngineResolver = (sessionId: SessionId) => Promise<SessionEngine>;
93
+ /** Move one session to another engine, refusing with a reason rather than throwing. */
94
+ export type SessionEngineSelector = (sessionId: SessionId, engine: LoopEngineId) => Promise<LoopEngineSelectResult>;
95
+ /**
96
+ * The mounted loop router, as these two endpoints need it: the reporting read
97
+ * and the move, both of which only a live router can make.
98
+ *
99
+ * Structural rather than the class itself, so this module takes no build-time
100
+ * dependency on `./router-loop.ts` (which drags in the harness loop and every
101
+ * engine driver) and a test can stand in for it.
102
+ */
103
+ export interface RouterSurface {
104
+ /** Report what one session actually runs, plus the recorded engine when the two differ. */
105
+ reportEngine(sessionId: SessionId): Promise<SessionEngineReport>;
106
+ /** Move one session to another engine, or answer why it was not moved. */
107
+ selectEngine(sessionId: SessionId, engine: LoopEngineId): Promise<LoopEngineSelectResult>;
108
+ }
109
+ /**
110
+ * Where the two endpoints find the mounted router.
111
+ *
112
+ * A holder rather than a fixed reference because the router is mounted
113
+ * asynchronously — and not at all until the harness's live patch reload drops the
114
+ * base bundle's `agent-loop` row (`src/index.ts` `mountRouter`). Until then both
115
+ * endpoints answer from what a router-less process still knows: the record and
116
+ * the log. A session that is not driven by this plugin has no live agent to
117
+ * report anyway, so the answers agree.
118
+ */
119
+ export interface RouterSurfaceHolder {
120
+ /** The mounted router, or undefined while there is no router. */
121
+ current: RouterSurface | undefined;
122
+ }
123
+ /**
124
+ * `remote.loopEngine`: report one session's engine, and move it to another.
125
+ *
126
+ * Registered as a Cordis service under {@link LOOP_ENGINE_REMOTE_KEY} on the
127
+ * plugin's own fiber, so the binding and the method marks disappear with the
128
+ * plugin: a profile that mounts no Gateway never discovers it, and unmounting
129
+ * the plugin withdraws both.
130
+ */
131
+ export declare class LoopEngineRemote extends TypertRemoteService {
132
+ private readonly resolve;
133
+ private readonly router;
134
+ private readonly warn;
135
+ /**
136
+ * @param ctx - the context the service (and its lifetime) belongs to.
137
+ * @param resolve - the router-less read; normally
138
+ * `engineOfSession(ctx, sessionId, records)`.
139
+ * @param router - where both endpoints find the mounted loop router.
140
+ * @param warn - diagnostic sink for a session that could not be read.
141
+ */
142
+ constructor(ctx: Context, resolve: SessionEngineResolver, router: RouterSurfaceHolder, warn: (message: string) => void);
143
+ /**
144
+ * Report what one session runs — and, when its own record names a different
145
+ * engine than the live agent, that fact separately.
146
+ *
147
+ * The router answers when it is mounted, because the live agent outranks every
148
+ * record: only the router knows which engine built the agent driving this
149
+ * session now, and only the router can tell a record whose release did not take
150
+ * from one that already landed. Without a router (the mount-retry window) no
151
+ * session is driven by this plugin, so the record — i.e.
152
+ * {@link SessionEngineResolver} — is the whole answer.
153
+ *
154
+ * A session that cannot be read answers `unset` rather than throwing: a
155
+ * surface that asked about a session the durable log does not know must render
156
+ * "engine not recorded", not break the page it is rendered in. Failures are
157
+ * reported once on the host's log instead.
158
+ *
159
+ * A malformed REQUEST is a caller fault, not an unreadable session, and is
160
+ * refused the way every typert endpoint refuses one.
161
+ * @param request - the wire request carrying the session id.
162
+ * @returns the engine driving that session, plus the recorded engine it is not
163
+ * running when the two differ.
164
+ * @throws {RemoteError} with `gateway/bad-request` when no session id was sent.
165
+ */
166
+ engine(request: LoopEngineRequest): Promise<SessionEngineReport>;
167
+ /**
168
+ * Move one session to another engine.
169
+ *
170
+ * The move owns no policy of its own: the router decides whether this session
171
+ * can be moved right now and answers with a reason when it cannot, because
172
+ * only it knows the session's live agent, its turn state, and the teardown it
173
+ * would have to perform. This endpoint's job is the boundary — reject a
174
+ * malformed request the way every typert endpoint does, and hand a well-formed
175
+ * one to the selector.
176
+ * @param request - the wire request carrying the session id and target engine.
177
+ * @returns the engine now recorded for the session — with `reload: true` when
178
+ * its agent had to be released for the change to land, which the browser half
179
+ * acts on by reloading the page — or, as `ok: false`, the
180
+ * {@link LoopEngineRefusalCode} of the branch that refused it together with the
181
+ * host's own sentence about this session (`router-unmounted` is this
182
+ * endpoint's own, `session-closed` / `turn-running` / `subagent-session` /
183
+ * `not-driven` / `record-failed` / `rebuild-failed` come from the router's
184
+ * checks). The browser half localizes from the code and keeps the sentence as
185
+ * detail, so the code is part of this endpoint's contract even though the
186
+ * shape allows it to be absent.
187
+ * @throws {RemoteError} with `gateway/bad-request` when the session id is not
188
+ * a non-empty string or the engine is not an installed engine id.
189
+ */
190
+ select(request: LoopEngineSelectRequest): Promise<LoopEngineSelectResult>;
191
+ }
192
+ //# sourceMappingURL=engine-remote.d.ts.map
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Per-session command and skill surface of the hosted engines.
3
+ *
4
+ * A hosted engine owns its session's slash-command menu and skill catalog: the
5
+ * engine expands `/name` itself and reads its own instruction files, so the
6
+ * plugin bridges both into the session the engine serves and nothing more.
7
+ *
8
+ * The registrations are made through the AGENT's own context, which is what
9
+ * makes them session-scoped: `commands.register` and
10
+ * `skills.registerProvider` file a definition into the layer of the calling
11
+ * context's scope (`packages/core/scope/src/store.ts` `effect()` keys the layer
12
+ * by `scopeOf(ctx)`), and an agent's scope key is the agent itself
13
+ * (`createScope(loopCtx, this)` in the default loop; the hosted drivers do the
14
+ * same). Two sessions running different engines therefore never see each
15
+ * other's menus, and the whole surface disappears with the agent's scope — no
16
+ * plugin-side bookkeeping, no leak across an engine switch.
17
+ *
18
+ * @module dsh-loop-engine-allinone/engine-surface
19
+ */
20
+ import type { Agent } from '@deepseek-ai/dsh-agent';
21
+ import type { HostedEngineId } from './settings.ts';
22
+ /**
23
+ * Bridge one hosted engine's commands and skills into the session it serves.
24
+ *
25
+ * Best-effort like the rest of the plugin's host-service use: a profile without
26
+ * the commands or skills registry simply has no surface to extend. A name that
27
+ * collides with an already-registered command in the same layer is skipped with
28
+ * a warning rather than failing the agent: the engine expands the raw `/name`
29
+ * line itself, so a shyer menu beats an agent that refuses to start.
30
+ *
31
+ * @param agent - the freshly built agent whose scope owns the registrations.
32
+ * @param engine - the hosted engine driving that agent.
33
+ * @param warn - sink for the skip diagnostics.
34
+ */
35
+ export declare function registerEngineSurface(agent: Agent, engine: HostedEngineId, warn: (message: string) => void): void;
36
+ //# sourceMappingURL=engine-surface.d.ts.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * ZCode agent: one `zcode -p "prompt"` child per dsh step, with the durable
3
+ * session log as the sole source of model context.
4
+ *
5
+ * Like the Hermes driver this reads stdout as a finished answer, and the reason
6
+ * is the same shape of fact recorded in `./process.ts`: the structured
7
+ * app-server surface exists but its request parameter shape could not be probed,
8
+ * so the driver uses the surface that is verified to reach the model rather than
9
+ * guessing a protocol.
10
+ *
11
+ * ZCode additionally needs its provider catalog located: run outside the desktop
12
+ * app the bundled CLI refuses to start a turn until
13
+ * `ZCODE_BUILTIN_PROVIDER_CONFIG_FILE` points at the app's own copy. The driver
14
+ * supplies the discovered default; a deployment's explicit `env` wins.
15
+ *
16
+ * @module dsh-loop-engine-allinone/engine-zcode/agent
17
+ */
18
+ import type { AgentOptions } from '@deepseek-ai/dsh-agent';
19
+ import type { Session, SessionId, UserMessage } from '@deepseek-ai/dsh-session';
20
+ import type { Context } from '@deepseek-ai/cordis';
21
+ import type { HostedEngineId } from '../engine-registry.ts';
22
+ import { CliHostedAgent } from '../driver-cli/cli-agent.ts';
23
+ import type { SinkPosition } from '../driver-cli/session-sink.ts';
24
+ import type { CliSpawnCapability } from '../driver-cli/transport.ts';
25
+ import { zcodeArgvPrefix, zcodeBuiltinProviderConfig } from './process.ts';
26
+ /** Deployment-resolved configuration for the ZCode engine. */
27
+ export interface ResolvedZcodeConfig {
28
+ /** The argv prefix ending in the entrypoint. */
29
+ readonly prefix: readonly string[];
30
+ /** Explicit environment entries layered over the scrubbed parent environment. */
31
+ readonly env: Record<string, string>;
32
+ /** Pinned model. */
33
+ readonly model: string | undefined;
34
+ /** The discovered bundled provider catalog, when present. */
35
+ readonly providerConfig: string | undefined;
36
+ }
37
+ /** The engine id this driver registers under. */
38
+ export declare const ZCODE_ENGINE: HostedEngineId;
39
+ /** Drives one session through turn and step boundaries on ZCode. */
40
+ export declare class ZcodeAgent extends CliHostedAgent {
41
+ private readonly config;
42
+ private readonly spawn;
43
+ constructor(loopCtx: Context, id: SessionId, options: AgentOptions, session: Session, config: ResolvedZcodeConfig, spawn: CliSpawnCapability);
44
+ protected runStep(messages: readonly UserMessage[], position: SinkPosition, signal: AbortSignal): Promise<{
45
+ kind: 'completed';
46
+ } | null>;
47
+ }
48
+ /** Re-exported so `./loop.ts` does not have to know how the prefix is built. */
49
+ export { zcodeArgvPrefix, zcodeBuiltinProviderConfig };
50
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * ZCode loop engine module: drives every session it is handed through one
3
+ * `zcode -p "prompt"` child per dsh step, with the durable session log as the
4
+ * sole source of model context. The router routes a session here on the plugin's
5
+ * own engine record, else its agent preset; this module is a library, not a
6
+ * Cordis plugin entry.
7
+ *
8
+ * See `./process.ts` for why this driver uses ZCode's one-shot print surface
9
+ * rather than its JSON-RPC app-server, and what was and was not verified.
10
+ *
11
+ * @module dsh-loop-engine-allinone/engine-zcode
12
+ */
13
+ import type { Context } from '@deepseek-ai/cordis';
14
+ import z from '@deepseek-ai/schemastery';
15
+ import type { AgentOptions } from '@deepseek-ai/dsh-agent';
16
+ import type { Session, SessionId } from '@deepseek-ai/dsh-session';
17
+ import { CliEngineRuntime } from '../driver-cli/cli-loop.ts';
18
+ import { ZcodeAgent, type ResolvedZcodeConfig } from './agent.ts';
19
+ /** Deployment-owned configuration for the ZCode engine. */
20
+ export interface Config {
21
+ /** Model label (`--model`); ZCode's own settings own the model when omitted. */
22
+ model?: string;
23
+ /** Explicit environment entries passed to the child; these win over the discovered ones. */
24
+ env?: Record<string, string>;
25
+ /** The `zcode` entrypoint (a `.cjs` bundle or a native binary); auto-discovered when not pinned. */
26
+ bin?: string;
27
+ }
28
+ /** Schema of the ZCode engine configuration. */
29
+ export declare const Config: z<Config>;
30
+ /** Host-face ctx key this engine's runtime is registered under. */
31
+ export declare const ZCODE_ENGINE_LABEL = "agentLoopZcode";
32
+ declare module '@deepseek-ai/cordis' {
33
+ interface Context {
34
+ agentLoopZcode: ZcodeLoop;
35
+ }
36
+ }
37
+ /**
38
+ * Creation/resume machinery for the ZCode engine. The process-wide AgentFactory
39
+ * slot belongs to the router, which delegates each session to the engine its
40
+ * preset names; this class is that engine's driver, not a plugin.
41
+ */
42
+ export declare class ZcodeLoop extends CliEngineRuntime<ResolvedZcodeConfig, ZcodeAgent> {
43
+ constructor(ctx: Context, config: Config);
44
+ /** Construct the ZCode driver for one prepared session. */
45
+ protected buildAgent(loopCtx: Context, id: SessionId, options: AgentOptions, session: Session): ZcodeAgent;
46
+ }
47
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1,111 @@
1
+ /**
2
+ * ZCode CLI process projection.
3
+ *
4
+ * ZCode is the Z.AI (GLM) coding CLI. It ships as a Node bundle at
5
+ * `resources/glm/zcode.cjs` inside the ZCode desktop app, so `argv[0]` is
6
+ * usually `process.execPath` and `argv[1]` the script — which is why the
7
+ * resolver returns an argv PREFIX rather than a single path.
8
+ *
9
+ * ## Why this driver uses the one-shot `-p` surface
10
+ *
11
+ * ZCode advertises two machine-facing surfaces, and they are not equally ready:
12
+ *
13
+ * 1. **`zcode app-server`** — a JSON-RPC stdio server. The probe
14
+ * (`docs/probes/zcode.md`) confirmed the transport and captured its method
15
+ * surface (`startup/*`, `session/create`, `session/send`,
16
+ * `session/subscribe`, `session/events`, `session/event`, `session/stop`,
17
+ * `session/setModel`, `session/setMode`, `session/resume`, `session/list`,
18
+ * `session/compact`, `session/messages`, `session/read`, …) and its
19
+ * server-initiated `startup/storageState` notifications. What the probe could
20
+ * NOT obtain is the REQUEST parameter shape: `initialize` drew no response
21
+ * frame at all, and every `session/create` attempt ended the run before a
22
+ * reply. Writing a request shape from the method names alone would be
23
+ * guessing, which the probe-first rule forbids.
24
+ * 2. **`zcode -p "prompt"`** — the documented one-shot print mode. The probe
25
+ * confirmed it runs and produces a result, but every run stopped at
26
+ * `ProviderBusinessError [1309] … GLM Coding Plan 已到期` (the machine's GLM
27
+ * Coding Plan subscription has lapsed), so the SUCCESS output shape is also
28
+ * unverified.
29
+ *
30
+ * So this driver takes the surface that is verified to at least reach the model,
31
+ * treats stdout as the answer, and declares `protocol: 'text'` /
32
+ * `streaming: false` in the registry — an honest statement of what the DRIVER
33
+ * does, not of what the CLI could do. Upgrading it to the app-server protocol is
34
+ * the recorded next step (`docs/engine-registry.md` §6, TODO).
35
+ *
36
+ * @module dsh-loop-engine-allinone/engine-zcode/process
37
+ */
38
+ import type { CliSpawnRequest } from '../driver-cli/transport.ts';
39
+ /** Grace in milliseconds for ZCode process-tree termination. */
40
+ export declare const ZCODE_DISPOSE_GRACE_MS = 3000;
41
+ /** The `--mode` values the CLI accepts. */
42
+ export declare const ZCODE_MODES: readonly ["build", "edit", "plan", "yolo"];
43
+ /** One ZCode permission mode. */
44
+ export type ZcodeMode = (typeof ZCODE_MODES)[number];
45
+ /**
46
+ * Resolve the argv prefix that launches ZCode.
47
+ *
48
+ * Three shapes, and the difference is why this returns an array: a pinned `.cjs`
49
+ * path runs under the current node (the bundled form), a pinned native binary is
50
+ * spawned directly, and with nothing pinned the well-known bundle is used before
51
+ * falling back to a `zcode` on PATH.
52
+ * @param configBin - an operator-pinned executable or script, if any.
53
+ * @returns the argv prefix ending in the ZCode entrypoint.
54
+ */
55
+ export declare function zcodeArgvPrefix(configBin?: string): string[];
56
+ /**
57
+ * The environment entry the bundled ZCode needs to find its own provider
58
+ * catalog.
59
+ *
60
+ * Discovered by the probe: run outside the desktop app, the bundle reports
61
+ * `无法定位 CLI ZCode Built-in Provider Config` and refuses to start a turn until
62
+ * this variable points at the app's own `zcode-builtin.json`. The driver sets it
63
+ * only when the deployment has not — an explicit deployment value always wins.
64
+ */
65
+ export declare const ZCODE_PROVIDER_CONFIG_ENV = "ZCODE_BUILTIN_PROVIDER_CONFIG_FILE";
66
+ /** The bundled provider catalog inside the desktop app, when it exists. */
67
+ export declare function zcodeBuiltinProviderConfig(): string | undefined;
68
+ /**
69
+ * Map the session's dsh knobs onto ZCode's `--mode`.
70
+ *
71
+ * Fail-closed like the other engines: full access is the only thing that earns
72
+ * `yolo`; everything else, including "no knobs at all", gets the CLI's own
73
+ * `build` mode, and the subprocess sandbox remains the real boundary.
74
+ * @param sandbox - the session's durable sandbox mode, if any.
75
+ * @returns the mode to pass.
76
+ */
77
+ export declare function zcodeMode(dangerFullAccess: boolean): ZcodeMode;
78
+ /** Everything one step's ZCode child needs. */
79
+ export interface ZcodeSpawnSpec {
80
+ /** The argv prefix ending in the entrypoint. */
81
+ readonly prefix: readonly string[];
82
+ /** The prompt, passed as an argv argument. */
83
+ readonly prompt: string;
84
+ /** The session's working directory. */
85
+ readonly cwd: string;
86
+ /** Explicit environment entries layered over the scrubbed parent environment. */
87
+ readonly env: Record<string, string>;
88
+ /** Pinned model (`--model` is not a flag; ZCode selects a model per session). */
89
+ readonly model: string | undefined;
90
+ /** Resolved permission mode. */
91
+ readonly mode: ZcodeMode;
92
+ /** Cancellation. */
93
+ readonly signal: AbortSignal;
94
+ }
95
+ /**
96
+ * Build the argv for one non-interactive ZCode step.
97
+ * @param spec - the step's spawn spec.
98
+ * @returns the argv.
99
+ */
100
+ export declare function zcodeArgv(spec: ZcodeSpawnSpec): string[];
101
+ /**
102
+ * Project one step's spawn spec onto the transport request.
103
+ *
104
+ * The provider-catalog variable is merged UNDER the deployment's own entries, so
105
+ * an explicit `env` always wins over the discovered default.
106
+ * @param spec - the step's spawn spec.
107
+ * @param providerConfig - the discovered catalog path, if any.
108
+ * @returns the transport's request shape.
109
+ */
110
+ export declare function zcodeSpawnRequest(spec: ZcodeSpawnSpec, providerConfig: string | undefined): CliSpawnRequest;
111
+ //# sourceMappingURL=process.d.ts.map
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Per-session agent loop engines, node half.
3
+ *
4
+ * Hosts the non-default agent-loop engines (Claude Code, Codex, Pi, Kimi Code)
5
+ * and routes each session to the engine it runs. The engine is the PLUGIN's own
6
+ * per-session fact (`session-engine-store.ts`), read first and over the recorded
7
+ * agent preset; a session the plugin has no record for keeps the preset answer,
8
+ * which is what makes every pre-existing session behave exactly as before.
9
+ * The harness admits exactly one AgentFactory per process, so "session A on
10
+ * Codex while session B runs Kimi" is realized by a single router factory
11
+ * ({@link RouterLoop}, which extends the harness's own `AgentLoop`) dispatching
12
+ * to one driver runtime per engine; `in-process` sessions keep the harness loop
13
+ * through that same router.
14
+ *
15
+ * Because the router owns the slot, the plugin keeps the base bundle's
16
+ * `agent-loop` row disabled for as long as it is composed. That managed block
17
+ * lives in the profile's `cordis.patch.yml` (see `patch-manager.ts`) and is the
18
+ * plugin's only footprint in the harness's configuration alongside the preset
19
+ * rows below; the block names no engine, because the engine is a per-session
20
+ * decision.
21
+ *
22
+ * The plugin authors one preset per hosted engine — each a copy of `standard`
23
+ * minus the dsh-native command and skill rows an external engine replaces — and
24
+ * it serves every hosted engine's provider route label in the llm registry
25
+ * (`provider-route.ts`): an engine logs its own label into each session's
26
+ * request/header, and the web host refuses a turn whose session selection names
27
+ * a provider no adapter serves. WHERE that copy lives depends on the harness
28
+ * generation — a directory under `$DSH_HOME/.agent-presets/loop-engine-<engine>`
29
+ * on the 0.1.5 line, a `@deepseek-ai/dsh-agent-preset` insert row in the profile
30
+ * patch on the 0.1.7 line, which stopped reading the directory (see
31
+ * `preset.ts`, {@link authorHostedPresets}). The preset is now only the
32
+ * session's agent-plane composition (and the engine's own default for a session
33
+ * with no record) — it is no longer the thing that decides a running session's
34
+ * engine.
35
+ *
36
+ * The plugin's own live `engine` Config field carries the DEFAULT engine for new
37
+ * sessions — which preset the roster's default points at — not a process-wide
38
+ * switch: existing sessions keep the engine they run, and nothing is torn down or
39
+ * reloaded by it. (A PER-SESSION switch is a different thing: it is made from the
40
+ * chat composer, and when it involves the harness loop it releases that session's
41
+ * agent and reloads the page — `router-loop.ts` `move`, `client/reload.ts`.)
42
+ *
43
+ * @module dsh-loop-engine-allinone
44
+ */
45
+ import type { Context, Volatile } from '@deepseek-ai/cordis';
46
+ import z from '@deepseek-ai/schemastery';
47
+ import type { EngineDriverConfig } from './engine-drivers.ts';
48
+ import type { CodexApprovalPolicy, CodexSandboxMode } from './engine-codex/types.ts';
49
+ import type { SummarizerTarget } from './preset.ts';
50
+ import { type LoopEngineId } from './settings.ts';
51
+ export declare const name = "loop-engine";
52
+ /**
53
+ * Services the plugin's own fiber requires. The plugin declares none of its
54
+ * own: the optional host services it reads (`commands`, `skills`, `agentPresets`,
55
+ * `llm`) are resolved lazily via `ctx.get` and may be absent, and the router
56
+ * declares the harness loop's own dependency set when it mounts. Empty keeps
57
+ * the plugin from demanding a service that a minimal profile does not provide.
58
+ */
59
+ export declare const inject: never[];
60
+ /** Composition entry for the loop engine selection and the hosted engine drivers. */
61
+ export interface Config extends EngineDriverConfig {
62
+ /** Profile whose `cordis.patch.yml` carries the managed block; defaults to `web`. */
63
+ profile?: string;
64
+ /** Patch file name inside the profile; defaults to `cordis.patch.yml`. */
65
+ patchFilename?: string;
66
+ /** Explicit absolute path to the patch file, overriding profile + filename. */
67
+ patchPath?: string;
68
+ /** Pinned sandbox mode for the Codex and Pi children; falls back to the session's dsh permission knobs. */
69
+ sandboxMode?: CodexSandboxMode;
70
+ /** Pinned Codex approval policy; falls back to the session's dsh permission knobs. */
71
+ approvalPolicy?: CodexApprovalPolicy;
72
+ /**
73
+ * Idle window in milliseconds after which a hosted session's PERSISTENT child
74
+ * process (Kimi's `kimi acp`, Codex's app-server) is shut down and spawned
75
+ * again by the next step. Zero or omitted keeps the child for the session's
76
+ * whole life. Only these two engines hold a child between steps: the Pi and
77
+ * Claude Code drivers spawn per step, so the knob does not reach them.
78
+ */
79
+ childIdleMs?: number;
80
+ /**
81
+ * Context window (in tokens) dsh assumes for the hosted provider route.
82
+ *
83
+ * A hosted engine reports no capacity to dsh — each owns its model inside its
84
+ * own child process — so this is the number dsh's auto-compaction sizes its
85
+ * pressure threshold from (default threshold ratio `0.8` of it, so compaction
86
+ * fires once a hosted session's replayed transcript crosses 80% of this). It
87
+ * is declared on the placeholder route (`src/provider-route.ts`
88
+ * `resolveModel`); without it the pressure path warns once and compaction
89
+ * never fires. A deployment running several engines should set it to the
90
+ * SMALLEST engine window in use, so the threshold that fires is safe for
91
+ * every engine. Defaults to
92
+ * {@link DEFAULT_ENGINE_CONTEXT_WINDOW} (262144).
93
+ */
94
+ engineContextWindow?: number;
95
+ /**
96
+ * Dsh provider route a hosted session's compaction SUMMARIZES through; set
97
+ * together with {@link Config.summarizerModel}, or not at all.
98
+ *
99
+ * The pair is only needed because a hosted engine's own model cannot serve
100
+ * that call: compaction summarizes with an ordinary llm request, and a hosted
101
+ * session's routed model is this plugin's placeholder route
102
+ * (`external/default`), whose `stream()` fails loud. Without the pair the
103
+ * plugin leaves the composition it authors untouched, and every compaction
104
+ * attempt logs a warning and lets the turn continue — the safe degraded mode,
105
+ * in which the session log is never folded. The plugin writes the pair into
106
+ * its own hosted presets (`src/preset.ts` `applySummarizerTarget`) because a
107
+ * profile-patch row replaces its target's whole `config`, and the patch index
108
+ * does not descend into a preset's `config.plugins` — the nested
109
+ * `compaction-basic` row is reachable only from the composition the plugin
110
+ * authors, never from the deployment's profile patch.
111
+ */
112
+ summarizerProvider?: string;
113
+ /**
114
+ * Dsh model id on {@link Config.summarizerProvider} that hosted sessions
115
+ * summarize through; must be set together with it.
116
+ */
117
+ summarizerModel?: string;
118
+ /**
119
+ * Default engine NEW sessions are created on. A live, profile-backed field:
120
+ * the settings shell edits it and the running plugin reads it through this
121
+ * volatile reference (`config.engine.get()`).
122
+ */
123
+ engine: Volatile<LoopEngineId>;
124
+ /** Whether the chat composer shows the engine picker; a live, profile-backed field. */
125
+ showInComposer: Volatile<boolean>;
126
+ /** Whether the conversation header shows the engine badge; a live, profile-backed field. */
127
+ showEngineBadge: Volatile<boolean>;
128
+ }
129
+ /** Rejected input of the composition entry: live fields arrive as plain values and resolve to references. */
130
+ type ConfigInput = Omit<Config, 'engine' | 'showInComposer' | 'showEngineBadge'> & {
131
+ engine?: LoopEngineId;
132
+ showInComposer?: boolean;
133
+ showEngineBadge?: boolean;
134
+ };
135
+ /**
136
+ * Schema of the loop engine composition entry.
137
+ *
138
+ * A schemastery object validates each field only when it is present and lets
139
+ * an absent key fall through as `undefined`, so omitted knobs are accepted —
140
+ * matching the permissive interface and read path (`resolvePatchPath` defaults
141
+ * the patch path; each engine driver resolves only the knobs it owns and
142
+ * omitted deployment tunables fall back to the session). The composition entry
143
+ * is an engine-agnostic superset: every hosted engine's knobs live here at
144
+ * once, because any session may select any engine.
145
+ *
146
+ * On the 0.1.7 line `engine`, `showInComposer`, and `showEngineBadge` are the
147
+ * entry's live fields: `.volatile()` makes them profile-backed settings the
148
+ * settings shell projects as form fields, and the runtime reads each one through
149
+ * its reference (`config.engine.get()`). On the 0.1.5 line there are no live
150
+ * Config fields — the selection is a settings section
151
+ * (`LOOP_ENGINE_SETTINGS_SCHEMA`), whose provider owns the storage — so the
152
+ * entry is the engine knobs alone.
153
+ */
154
+ export declare const Config: z<ConfigInput, Config>;
155
+ /** Resolve the managed patch file from configuration, defaulting to the web profile. */
156
+ export declare function resolvePatchPath(config: Config): string;
157
+ /**
158
+ * Resolve the summarization model the plugin writes into every hosted preset,
159
+ * or `undefined` when the deployment names none.
160
+ *
161
+ * The two knobs are one decision — a provider route without a model (or the
162
+ * reverse) cannot be resolved to a call — so a half-set pair is a
163
+ * misconfiguration rather than a usable half, and it fails loud here instead of
164
+ * being dropped on the floor. This runs as the plugin applies, i.e. at compose
165
+ * time, and it runs before anything is written, so a bad profile never leaves a
166
+ * half-authored patch file behind.
167
+ *
168
+ * Schemastery has no cross-field check, so the schema keeps the two fields
169
+ * permissive and the rule is enforced here (the same compose-time posture the
170
+ * engine loops take for their own resolved config).
171
+ * @param config - the composition entry's static knobs.
172
+ * @returns the summarization target, or undefined when neither field is set.
173
+ * @throws when exactly one field is set, or either one is an empty string.
174
+ */
175
+ export declare function resolveSummarizerTarget(config: Config): SummarizerTarget | undefined;
176
+ /** Atomically replace the patch file (same-directory temp + rename). */
177
+ export declare function writePatchFile(path: string, text: string): Promise<void>;
178
+ /**
179
+ * Synchronously atomically replace the patch file. The settings onChange that
180
+ * commits a default-engine change is a synchronous hook with no await, and the
181
+ * write MUST land before the caller is told the change committed — otherwise a
182
+ * user who restarts `dsh web` immediately reads the stale file.
183
+ * @param path - the profile's patch file.
184
+ * @param text - the next file content.
185
+ */
186
+ export declare function writePatchFileSync(path: string, text: string): void;
187
+ /**
188
+ * Ensure the profile's patch file carries the plugin's managed block, which
189
+ * disables the base bundle's `agent-loop` row so this plugin's router owns the
190
+ * single AgentFactory slot. Idempotent: a file already carrying a block and no
191
+ * legacy block is left untouched.
192
+ * @param path - the profile's patch file.
193
+ * @returns whether a write occurred.
194
+ */
195
+ export declare function syncManagedBlock(path: string): Promise<boolean>;
196
+ /**
197
+ * Apply the plugin: own the profile's managed block, mount the routing factory,
198
+ * author the per-engine presets, and serve every hosted engine's provider
199
+ * route. The settings section carries the deployment's default engine.
200
+ * @param ctx - the composing context.
201
+ * @param config - composition entry for the managed patch file and engine knobs.
202
+ */
203
+ export declare function apply(ctx: Context, config: Config): void;
204
+ export {};
205
+ //# sourceMappingURL=index.d.ts.map