@ckanner/flywheel 0.33.0 → 0.34.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.
- package/CHANGELOG.md +32 -0
- package/README.md +1 -0
- package/README.zh-CN.md +2 -0
- package/THIRD_PARTY_NOTICES.md +5 -1
- package/bin/flywheel-kimi-native-worker.js +5 -0
- package/bin/flywheel.js +8 -1
- package/bin/runtime.js +5 -1
- package/dist/bridge.mjs +89 -7
- package/dist/claude-code-pro-bridge.mjs +55 -6
- package/dist/client.js +107 -10
- package/dist/codex-pro-bridge.mjs +12 -5
- package/dist/control.mjs +1 -1
- package/dist/kimi-native-bridge.mjs +429 -0
- package/dist/kimi-native-runtime.mjs +233 -0
- package/dist/kimi-native-worker.mjs +77 -0
- package/dist/kimi-tower-candidate.mjs +227 -0
- package/dist/machine-worker.mjs +39 -5
- package/dist/managed-lcu.mjs +223 -0
- package/dist/native-doctor.mjs +36 -0
- package/dist/native-jobs.mjs +72 -0
- package/dist/native-policy.mjs +371 -0
- package/dist/native-resources.mjs +144 -0
- package/dist/native.mjs +251 -0
- package/dist/policy.mjs +13 -3
- package/dist/prewarm.mjs +4 -1
- package/dist/protocol.mjs +8 -1
- package/dist/worker.mjs +16 -9
- package/docs/README.md +9 -0
- package/docs/README.zh-CN.md +3 -0
- package/docs/design.md +34 -12
- package/docs/en/claude-code-pro.md +2 -2
- package/docs/en/configuration.md +17 -5
- package/docs/en/contributing.md +5 -3
- package/docs/en/flow-console.md +1 -1
- package/docs/en/getting-started.md +2 -2
- package/docs/en/model-policy.md +2 -2
- package/docs/en/native-capabilities.md +185 -0
- package/docs/en/releasing.md +2 -2
- package/docs/en/session-recovery.md +2 -2
- package/docs/plans/2026-11-13-native-harness-capabilities.en.md +258 -0
- package/docs/plans/2026-11-13-native-harness-capabilities.md +276 -0
- package/docs/plans/README.md +1 -0
- package/docs/validation/2026-11-14-desktop-native-configuration.md +128 -0
- package/docs/validation/2026-11-14-native-harness-implementation.md +215 -0
- package/docs/validation/2026-11-14-published-companions.md +15 -0
- package/docs/validation/2026-11-14-release-0.33.0.md +49 -0
- package/docs/validation/2026-11-14-release-0.33.1.md +78 -0
- package/docs/validation/README.md +4 -0
- package/docs/validation/evidence/2026-11-14-native-harness-candidate.json +255 -0
- package/docs/validation/evidence/2026-11-14-native-harness-sessions.json +6009 -0
- package/docs/validation/evidence/2026-11-14-native-harness-tower-candidate.json +192 -0
- package/docs/zh-CN/claude-code-pro.md +2 -2
- package/docs/zh-CN/configuration.md +21 -8
- package/docs/zh-CN/contributing.md +5 -3
- package/docs/zh-CN/flow-console.md +1 -1
- package/docs/zh-CN/getting-started.md +2 -2
- package/docs/zh-CN/model-policy.md +2 -2
- package/docs/zh-CN/native-capabilities.md +184 -0
- package/docs/zh-CN/releasing.md +2 -2
- package/docs/zh-CN/session-recovery.md +1 -1
- package/native/darwin-amd64/flywheel +0 -0
- package/native/darwin-arm64/flywheel +0 -0
- package/native/linux-amd64/flywheel +0 -0
- package/native/linux-arm64/flywheel +0 -0
- package/native/manifest.json +9 -9
- package/node_modules/dsh-preset-generator/CHANGELOG.md +77 -0
- package/node_modules/dsh-preset-generator/LICENSE +21 -0
- package/node_modules/dsh-preset-generator/README.md +149 -0
- package/node_modules/dsh-preset-generator/docs/README.zh.md +95 -0
- package/node_modules/dsh-preset-generator/package.json +43 -0
- package/node_modules/dsh-preset-generator/src/composition.mjs +150 -0
- package/node_modules/dsh-preset-generator/src/gen-presets.mjs +367 -0
- package/node_modules/dsh-preset-generator/src/policy.mjs +17 -0
- package/node_modules/dsh-subagent-codex-pro/CHANGELOG.md +16 -1
- package/node_modules/dsh-subagent-codex-pro/README.md +57 -4
- package/node_modules/dsh-subagent-codex-pro/assets/native-client.js +118 -0
- package/node_modules/dsh-subagent-codex-pro/cordis.patch.yml +6 -0
- package/node_modules/dsh-subagent-codex-pro/docs/README.zh.md +49 -2
- package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle-validation.md +1 -1
- package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.md +1 -1
- package/node_modules/dsh-subagent-codex-pro/docs/machine-lifecycle.zh.md +1 -1
- package/node_modules/dsh-subagent-codex-pro/docs/machine.md +2 -2
- package/node_modules/dsh-subagent-codex-pro/docs/native-capabilities.md +254 -0
- package/node_modules/dsh-subagent-codex-pro/docs/native-capabilities.zh.md +180 -0
- package/node_modules/dsh-subagent-codex-pro/lib/config.js +56 -0
- package/node_modules/dsh-subagent-codex-pro/lib/config.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/desktop-native.js +109 -0
- package/node_modules/dsh-subagent-codex-pro/lib/desktop-native.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js +3 -4
- package/node_modules/dsh-subagent-codex-pro/lib/dsh-types.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/index.js +64 -15
- package/node_modules/dsh-subagent-codex-pro/lib/index.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/jobs.js +6 -2
- package/node_modules/dsh-subagent-codex-pro/lib/jobs.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js +2 -2
- package/node_modules/dsh-subagent-codex-pro/lib/machine-cli.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js +5 -2
- package/node_modules/dsh-subagent-codex-pro/lib/machine-local.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js +11 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervision.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/machine-supervisor.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/machine.js +20 -3
- package/node_modules/dsh-subagent-codex-pro/lib/machine.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/native.js +297 -0
- package/node_modules/dsh-subagent-codex-pro/lib/native.js.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js +11 -1
- package/node_modules/dsh-subagent-codex-pro/lib/process-guardian.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/run.js +19 -1
- package/node_modules/dsh-subagent-codex-pro/lib/run.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/tool.js +123 -57
- package/node_modules/dsh-subagent-codex-pro/lib/tool.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/config.d.ts +31 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/config.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/desktop-native.d.ts +30 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/desktop-native.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts +7 -5
- package/node_modules/dsh-subagent-codex-pro/lib/types/dsh-types.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts +31 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/index.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts +2 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/jobs.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-local.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine-supervision.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts +7 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/machine.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/native.d.ts +120 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/native.d.ts.map +1 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts +11 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/run.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts +11 -0
- package/node_modules/dsh-subagent-codex-pro/lib/types/tool.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts +7 -1
- package/node_modules/dsh-subagent-codex-pro/lib/types/wire.d.ts.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/lib/wire.js +34 -6
- package/node_modules/dsh-subagent-codex-pro/lib/wire.js.map +1 -1
- package/node_modules/dsh-subagent-codex-pro/package.json +28 -4
- package/npm/install.js +2 -2
- package/package.json +25 -10
- package/plugins/dsh/KIMI_NATIVE_PROTOCOL.en.md +76 -0
- package/plugins/dsh/KIMI_NATIVE_PROTOCOL.md +76 -0
- package/plugins/dsh/PROTOCOL.md +151 -17
- package/plugins/dsh/README.md +15 -12
- package/plugins/dsh/README.zh-CN.md +8 -8
- package/plugins/dsh/THIRD_PARTY_NOTICES.md +5 -1
- package/plugins/dsh/vendor/README.md +40 -11
- package/plugins/dsh/vendor/chatgpt.json +21 -0
- package/plugins/dsh/vendor/claude-code-pro.json +21 -0
- package/plugins/dsh/vendor/codex-pro.json +13 -8
- package/plugins/dsh/vendor/lcu.json +21 -0
- package/plugins/dsh/vendor/preset-generator.json +16 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ results are recorded separately in the [release runbook](docs/en/releasing.md)
|
|
|
5
5
|
and [validation index](docs/validation/README.md). Historical entries retain
|
|
6
6
|
their original language.
|
|
7
7
|
|
|
8
|
+
## 0.34.0 — Native harness capabilities
|
|
9
|
+
|
|
10
|
+
- Align native companion fixtures and provenance with published Codex 0.10.0, Claude 0.5.0, LCU 0.5.0 and ChatGPT 0.1.20; verify the exact registry Claude tarball in CI and release jobs. Document separate desktop, worker and SDK dependency trees.
|
|
11
|
+
|
|
12
|
+
- Add versioned native profiles across loops, routes, model profiles, second
|
|
13
|
+
opinions and allowed execution bindings, including workbench selection,
|
|
14
|
+
frozen history identity, durable native receipts and import-only diagnostics.
|
|
15
|
+
- Run DSH PTC composition from the shared generator with actual behavior probes,
|
|
16
|
+
native subagents/Team/Workflow and managed LCU. Serialize desktop ownership,
|
|
17
|
+
retain epoch-safe handles and durable media, and prove journal/physical cleanup.
|
|
18
|
+
- Add an owned Kimi Server worker for Agent/Swarm/Tower. Use independent Tower
|
|
19
|
+
Git candidates, preserve dirty/untracked/binary changes and transfer only after
|
|
20
|
+
completion, cleanup and source/contract checks.
|
|
21
|
+
- Integrate Codex Pro 0.10.0 and Claude Code Pro 0.5.0 native controls, child events
|
|
22
|
+
and truthful accounting. Add independent Review/interactive Team job commands;
|
|
23
|
+
unknown cloud work, child usage and cleanup never become inferred success.
|
|
24
|
+
- Preserve role independence, explicit accounts/permissions and existing JEV
|
|
25
|
+
controls. Keep one complete npm package, bundle generator 0.4.0 and record the
|
|
26
|
+
reviewed companion source artifacts without claiming registry publication.
|
|
27
|
+
- Refresh the bundled generator to create a profile's first preset patch or a
|
|
28
|
+
new output file, preserving existing settings and concurrent file creation.
|
|
29
|
+
|
|
30
|
+
## 0.33.1 — Strict desktop read codecs
|
|
31
|
+
|
|
32
|
+
- Fix task discovery and configuration reads rejected by the actual DSH Client
|
|
33
|
+
Gateway. Supply strict schema factories for session identity, read requests and
|
|
34
|
+
result envelopes; consume the dynamic namespace through an owned injected
|
|
35
|
+
scope, use the host Agent registry's `agentId` wire field, and preserve session
|
|
36
|
+
isolation, teardown and silent reads.
|
|
37
|
+
- Exercise the shipped Client descriptor through the real public Client and Host
|
|
38
|
+
Gateway on both supported host fixtures instead of mocking Remote mounting.
|
|
39
|
+
|
|
8
40
|
## 0.33.0 — One complete npm distribution
|
|
9
41
|
|
|
10
42
|
- Consolidate the CLI, DSH host/client, workers, embedded skills and four native
|
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@ retries, budgets, workspaces, and delivery. Use it from the DeepSeek Harness
|
|
|
27
27
|
- **Coordinates bounded parallel execution.** Packets with explicit
|
|
28
28
|
dependencies and non-overlapping write scopes can execute concurrently;
|
|
29
29
|
review and integration remain coordinated by the engine.
|
|
30
|
+
- **Uses native harness capabilities.** Select PTC Agents/Teams, Kimi Swarm/Tower, Codex agents, Claude Workflows or managed LCU per role; see [native capabilities](docs/en/native-capabilities.md).
|
|
30
31
|
- **Provides a desktop workbench.** Inspect task progress, evidence, sessions,
|
|
31
32
|
run history, and configuration from DSH's native Flywheel view.
|
|
32
33
|
- **Makes failures visible.** Unknown execution, usage, or cleanup stays
|
package/README.zh-CN.md
CHANGED
|
@@ -22,6 +22,8 @@ Flywheel 是面向 coding agent 的确定性 Go 编排器。模型负责规划
|
|
|
22
22
|
- **提供桌面工作台。** 在 DSH 原生 Flywheel 视图中查看任务进度、证据、会话、运行记录和配置。
|
|
23
23
|
- **明确呈现失败。** 未知执行结果、用量或清理状态保持未知;无法安全继续时保留成果并停止。
|
|
24
24
|
|
|
25
|
+
原生能力可以按阶段配置:DSH PTC/Team、Kimi Swarm/Tower、Codex agents、Claude Workflow 和受管 LCU。入口、依赖和实际运行边界见[原生能力指南](docs/zh-CN/native-capabilities.md)。
|
|
26
|
+
|
|
25
27
|
## 安装
|
|
26
28
|
|
|
27
29
|
使用桌面入口前,请准备 **Node.js 22.18.0 或更高版本**、npm、Git,以及带可用 `dsh` 命令的受支持 DSH 桌面。插件采用 **DSH 0.2 兼容系列**范围,从 **0.2.1-rc.5** 起,到 **0.3.0 的任何预发布版之前**;范围内常规 rc/补丁升级无需重新发布 Flywheel。还需准备所选模型路由使用的账号和 CLI 工具。DSH 自身可能要求更高版本的 Node;DSH 0.2.2 SDK 要求 Node 24.9 或更高。
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -39,4 +39,8 @@ SOFTWARE.
|
|
|
39
39
|
|
|
40
40
|
## Bundled Codex Pro public package
|
|
41
41
|
|
|
42
|
-
This distribution bundles `dsh-subagent-codex-pro@0.
|
|
42
|
+
This distribution bundles `dsh-subagent-codex-pro@0.10.0`, Copyright (c) 2026 ckanner, under the MIT License. Its complete license is retained at `node_modules/dsh-subagent-codex-pro/LICENSE` inside the complete package. Source identity and tarball integrity are recorded in `plugins/dsh/vendor/README.md` and `plugins/dsh/vendor/codex-pro.json` in the source repository. The bundled package is the upstream public machine API implementation, including its compiled supervisor; it contains no native Codex executable or user credentials.
|
|
43
|
+
|
|
44
|
+
## Bundled PTC composition source
|
|
45
|
+
|
|
46
|
+
This distribution also bundles `dsh-preset-generator@0.4.0`, Copyright (c) 2026 ckanner, under the MIT License. Its original license remains at `node_modules/dsh-preset-generator/LICENSE`. The public composition module shares the desktop daily/heavy policy with the owned SDK worker. Source identity and actual tarball integrity are recorded in `plugins/dsh/vendor/preset-generator.json`; no DSH application resources, native executable or credentials are bundled.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
const { loadKimiNativeWorkerPath, runChild } = require('./runtime.js');
|
|
4
|
+
runChild(process.execPath, [loadKimiNativeWorkerPath(), ...process.argv.slice(2)], { label: 'flywheel-kimi-native-worker' })
|
|
5
|
+
.then(code => { process.exitCode = code; }).catch(error => { console.error(`flywheel-kimi-native-worker: ${error.message}`); process.exitCode = 1; });
|
package/bin/flywheel.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright (c) 2026 ckanner. SPDX-License-Identifier: MIT
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { loadNativePath, loadWorkerPath, loadCodexProWorkerPath, loadClaudeCodeProWorkerPath, assertSupportedNode, runChild } = require("./runtime.js");
|
|
5
|
+
const { loadNativePath, loadWorkerPath, loadCodexProWorkerPath, loadClaudeCodeProWorkerPath, loadKimiNativeWorkerPath, assertSupportedNode, runChild } = require("./runtime.js");
|
|
6
6
|
|
|
7
7
|
async function main() {
|
|
8
8
|
const args = process.argv.slice(2);
|
|
@@ -11,6 +11,10 @@ async function main() {
|
|
|
11
11
|
}
|
|
12
12
|
assertSupportedNode();
|
|
13
13
|
|
|
14
|
+
if (args[0] === 'native') {
|
|
15
|
+
return (await import('../dist/native-jobs.mjs')).main(args.slice(1));
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
const env = { ...process.env };
|
|
15
19
|
// An npm dependency's bin is not necessarily on a desktop application's
|
|
16
20
|
// PATH. Resolve this installation's worker without changing an explicit
|
|
@@ -24,6 +28,9 @@ async function main() {
|
|
|
24
28
|
if (env.FLYWHEEL_CLAUDE_CODE_PRO_WORKER === undefined) {
|
|
25
29
|
env.FLYWHEEL_CLAUDE_CODE_PRO_WORKER = loadClaudeCodeProWorkerPath();
|
|
26
30
|
}
|
|
31
|
+
if (env.FLYWHEEL_KIMI_NATIVE_WORKER === undefined) {
|
|
32
|
+
env.FLYWHEEL_KIMI_NATIVE_WORKER = loadKimiNativeWorkerPath();
|
|
33
|
+
}
|
|
27
34
|
return runChild(loadNativePath(), args, { env });
|
|
28
35
|
}
|
|
29
36
|
|
package/bin/runtime.js
CHANGED
|
@@ -53,6 +53,10 @@ function loadClaudeCodeProWorkerPath() {
|
|
|
53
53
|
return packageFile('dist/claude-code-pro-worker.mjs');
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
function loadKimiNativeWorkerPath() {
|
|
57
|
+
return packageFile('dist/kimi-native-worker.mjs');
|
|
58
|
+
}
|
|
59
|
+
|
|
56
60
|
function assertSupportedNode(version = process.versions.node) {
|
|
57
61
|
const match = /^(\d+)\.(\d+)\.(\d+)(?:$|-)/.exec(version);
|
|
58
62
|
if (!match || Number(match[1]) < 22 || (Number(match[1]) === 22 && Number(match[2]) < 18)) {
|
|
@@ -97,4 +101,4 @@ function runChild(command, args, { env = process.env, cwd, label = "flywheel" }
|
|
|
97
101
|
});
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
module.exports = { loadNativePath, loadWorkerPath, loadCodexProWorkerPath, loadClaudeCodeProWorkerPath, assertSupportedNode, runChild };
|
|
104
|
+
module.exports = { loadNativePath, loadWorkerPath, loadCodexProWorkerPath, loadClaudeCodeProWorkerPath, loadKimiNativeWorkerPath, assertSupportedNode, runChild };
|
package/dist/bridge.mjs
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
-
import { mkdtemp, realpath, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { mkdtemp, realpath, rm, writeFile, readFile, open } from 'node:fs/promises';
|
|
4
|
+
import { constants } from 'node:fs';
|
|
4
5
|
import { tmpdir } from 'node:os';
|
|
5
6
|
import { join } from 'node:path';
|
|
6
7
|
import { fileURLToPath } from 'node:url';
|
|
7
8
|
import { validatePrepare, matchWarmStart, writeWarmReceipt } from './prewarm.mjs';
|
|
8
9
|
import { BridgeError, MAX_FRAME_BYTES, normalizedError, readPolicyReceipt, record, SESSION_PROTOCOL, SessionFold, validateStart } from './protocol.mjs';
|
|
10
|
+
import { nativeOverlay } from './native-policy.mjs';
|
|
11
|
+
import { NativeTree } from './native.mjs';
|
|
12
|
+
import { acquireGuiLease, settleGuiLease } from './native-resources.mjs';
|
|
9
13
|
|
|
10
14
|
export function makeOverlay(request, policyPath = fileURLToPath(new URL('./policy.mjs', import.meta.url)), admission = {}, historyRoot) {
|
|
15
|
+
const native = request.native ? nativeOverlay(request, admission.runtimeProfile ?? 'sdk') : null;
|
|
11
16
|
// Each patch replaces an entire config row. Pin the checked rc.5/rc.1 enforcement
|
|
12
17
|
// implementations, not the user's mutable permission dropdown defaults.
|
|
13
18
|
const disable = ['permission', 'tool-plugin-manager', 'tool-working-directory',
|
|
@@ -17,6 +22,7 @@ export function makeOverlay(request, policyPath = fileURLToPath(new URL('./polic
|
|
|
17
22
|
'session-title-llm', 'tool-web', 'compaction-basic', 'command-compact', 'hmr'];
|
|
18
23
|
return [
|
|
19
24
|
...disable.map(id => ({ id, disabled: true })),
|
|
25
|
+
...(native?.overlay ?? []),
|
|
20
26
|
...(historyRoot ? [{ id: 'session-persistence-jsonl', config: { root: historyRoot } }] : []),
|
|
21
27
|
{ id: 'sandbox', name: '@deepseek-ai/dsh-sandbox-local', disabled: false, config: {} },
|
|
22
28
|
{ id: 'sandbox-policy', name: '@deepseek-ai/dsh-sandbox-policy', disabled: false,
|
|
@@ -28,6 +34,8 @@ export function makeOverlay(request, policyPath = fileURLToPath(new URL('./polic
|
|
|
28
34
|
{ id: 'sdk-jsonrpc-server', config: { maxTokensAsSuccess: false } },
|
|
29
35
|
{ insert: [{ id: 'flywheel-worker-policy', name: policyPath,
|
|
30
36
|
config: { permissionMode: request.permissionMode, cwd: request.cwd,
|
|
37
|
+
...(native ? { native: request.native, managed: request.managed, composition: native.composition,
|
|
38
|
+
provider: request.provider, model: request.model, reasoningEffort: request.reasoningEffort, resuming: Boolean(request.sessionId) } : {}),
|
|
31
39
|
...(request.workspaceCwd ? { workspaceCwd: request.workspaceCwd } : {}),
|
|
32
40
|
...(!request.sessionId && request.sessionTitle ? { sessionTitle: request.sessionTitle } : {}), ...admission } }] },
|
|
33
41
|
];
|
|
@@ -55,6 +63,26 @@ async function abortable(promise, signal) {
|
|
|
55
63
|
}
|
|
56
64
|
}
|
|
57
65
|
|
|
66
|
+
export async function readNativeEvents(directory, identity, summary) {
|
|
67
|
+
const file = await open(join(directory, 'native-events.jsonl'), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
68
|
+
let events;
|
|
69
|
+
try {
|
|
70
|
+
const stat = await file.stat();
|
|
71
|
+
if (!stat.isFile() || stat.size > 2 * 1024 * 1024) throw new Error('native runtime evidence exceeds its bounded receipt');
|
|
72
|
+
events = await file.readFile('utf8');
|
|
73
|
+
} finally { await file.close(); }
|
|
74
|
+
const bytes = Buffer.byteLength(events);
|
|
75
|
+
if (bytes > 2 * 1024 * 1024 || (bytes && !events.endsWith('\n'))) throw new Error('native runtime evidence is incomplete or oversized');
|
|
76
|
+
const values = events.split('\n').filter(Boolean).map(line => JSON.parse(line));
|
|
77
|
+
if (values.length > 4096 || values.some((value, index) => !record(value) || value.version !== 1 ||
|
|
78
|
+
value.journalSequence !== index + 1 || value.requestId !== identity.requestId || value.nonce !== identity.nonce ||
|
|
79
|
+
value.rootSessionId !== identity.rootSessionId)) throw new Error('native runtime evidence has invalid sequence or invocation ownership');
|
|
80
|
+
if (summary !== undefined && (!record(summary) || summary.complete !== true || summary.events !== values.length || summary.bytes !== bytes)) {
|
|
81
|
+
throw new Error('native runtime journal did not confirm complete durable evidence');
|
|
82
|
+
}
|
|
83
|
+
return values;
|
|
84
|
+
}
|
|
85
|
+
|
|
58
86
|
/** A bounded JSON-RPC transport. It does not own a new process group. */
|
|
59
87
|
export class Runtime {
|
|
60
88
|
constructor(bin, args, options, notify) {
|
|
@@ -144,7 +172,7 @@ export class Runtime {
|
|
|
144
172
|
});
|
|
145
173
|
}
|
|
146
174
|
|
|
147
|
-
async close() {
|
|
175
|
+
async close({ graceMs = 2000 } = {}) {
|
|
148
176
|
// The Go watchdog owns the whole inherited process group. We request the
|
|
149
177
|
// SDK's child-first drain and bound the leader wait; Go performs the final
|
|
150
178
|
// group sweep even on normal exit. A child must not detach/setsid.
|
|
@@ -154,7 +182,7 @@ export class Runtime {
|
|
|
154
182
|
// SDK shutdown includes persistent history flush and plugin disposal.
|
|
155
183
|
// Keep this bounded below Go's default 5s cancellation grace, while
|
|
156
184
|
// allowing a normal fsync to complete under concurrent local workloads.
|
|
157
|
-
await bounded(this.exited,
|
|
185
|
+
await bounded(this.exited, graceMs);
|
|
158
186
|
}
|
|
159
187
|
if (!this.exit) {
|
|
160
188
|
forced = true;
|
|
@@ -184,6 +212,10 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
184
212
|
let temp;
|
|
185
213
|
let sessionId;
|
|
186
214
|
let fold;
|
|
215
|
+
let nativeTree, guiLease, nativeCleanup, nativeAdmission, policyIdentity;
|
|
216
|
+
let nativeRuntimeEvents = [];
|
|
217
|
+
let completionAtRootEnd;
|
|
218
|
+
let nativeAttempted = false;
|
|
187
219
|
let outcome;
|
|
188
220
|
let failure;
|
|
189
221
|
let cancelled = false;
|
|
@@ -232,9 +264,24 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
232
264
|
sessionId = prepared ? undefined : request.sessionId ?? `flywheel-${randomUUID()}`;
|
|
233
265
|
const admission = { receiptPath: join(temp, 'policy.json'), requestId: prepared ? prepared.warmId : request.requestId,
|
|
234
266
|
...(prepared ? { deferredAdmissionPath: join(temp, 'admission.json') } : { sessionId }), nonce: randomUUID() };
|
|
267
|
+
policyIdentity = { requestId: admission.requestId, nonce: admission.nonce };
|
|
268
|
+
if (!prepared && request.native?.lcu?.enabled) {
|
|
269
|
+
guiLease = await acquireGuiLease(request.managed, { env, signal: controller.signal });
|
|
270
|
+
request = { ...request, managed: { ...request.managed, lease: guiLease } };
|
|
271
|
+
}
|
|
272
|
+
if (request.native) admission.runtimeProfile = profile;
|
|
235
273
|
await writeFile(patch, JSON.stringify(makeOverlay(request, undefined, admission, doctor ? join(temp, 'probe-history') : undefined)), { mode: 0o600 });
|
|
236
274
|
controller.signal.throwIfAborted();
|
|
237
275
|
if (!prepared) fold = new SessionFold(sessionId, { strict: request.protocol === 2 });
|
|
276
|
+
const observeNative = event => {
|
|
277
|
+
const eventFrame = { type: 'native-event', sessionId, event };
|
|
278
|
+
if (readySent) frame(eventFrame);
|
|
279
|
+
else {
|
|
280
|
+
beforeReady.push(eventFrame);
|
|
281
|
+
if (beforeReady.length > 256) throw new BridgeError('TRANSPORT', 'excessive native events before readiness');
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
if (!prepared && request.native) nativeTree = new NativeTree(sessionId, request.native, observeNative);
|
|
238
285
|
runtime = new Runtime(bin, ['--profile', profile, '--patch', patch], {
|
|
239
286
|
cwd: request.cwd,
|
|
240
287
|
env: { ...env, DSH_PERMISSION_MODE: request.permissionMode,
|
|
@@ -252,7 +299,8 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
252
299
|
if (beforeReady.length > 256) throw new BridgeError('TRANSPORT', 'excessive SDK events before readiness');
|
|
253
300
|
}
|
|
254
301
|
}
|
|
255
|
-
if (
|
|
302
|
+
if (nativeTree) nativeTree.notify(method, params);
|
|
303
|
+
else if (method === 'subagent.started' && params?.parentSessionId === sessionId) {
|
|
256
304
|
throw new BridgeError('INVALID_REQUEST', 'DSH child delegation is disabled: the Go engine owns workers');
|
|
257
305
|
}
|
|
258
306
|
});
|
|
@@ -284,12 +332,18 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
284
332
|
deadline = setTimeout(() => controller.abort(new BridgeError('TIMEOUT', 'DSH worker lifecycle deadline exceeded')), formalBudget);
|
|
285
333
|
request = await abortable(validateStart(next), controller.signal);
|
|
286
334
|
matchWarmStart(prepared, request);
|
|
335
|
+
if (request.native?.lcu?.enabled) {
|
|
336
|
+
guiLease = await acquireGuiLease(request.managed, { env, signal: controller.signal });
|
|
337
|
+
request = { ...request, managed: { ...request.managed, lease: guiLease } };
|
|
338
|
+
}
|
|
287
339
|
sessionId = request.sessionId ?? `flywheel-${randomUUID()}`;
|
|
288
340
|
fold = new SessionFold(sessionId, { strict: request.protocol === 2 });
|
|
341
|
+
if (request.native) nativeTree = new NativeTree(sessionId, request.native, observeNative);
|
|
289
342
|
await writeFile(admission.deferredAdmissionPath, JSON.stringify({ requestId: admission.requestId,
|
|
290
|
-
nonce: admission.nonce, sessionId, ...(!request.sessionId && request.sessionTitle ? { sessionTitle: request.sessionTitle } : {}) }),
|
|
343
|
+
nonce: admission.nonce, sessionId, ...(request.native ? { managed: request.managed, resuming: Boolean(request.sessionId) } : {}), ...(!request.sessionId && request.sessionTitle ? { sessionTitle: request.sessionTitle } : {}) }),
|
|
291
344
|
{ mode: 0o600, flag: 'wx' });
|
|
292
345
|
}
|
|
346
|
+
nativeAttempted = Boolean(request.native);
|
|
293
347
|
if (request.sessionId !== undefined) {
|
|
294
348
|
// Public SDK resume restores exactly this identity, without a new input
|
|
295
349
|
// and without a replacement on failure. A generic RPC error cannot tell
|
|
@@ -314,6 +368,8 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
314
368
|
throw new BridgeError('INVALID_REQUEST', 'DSH session project workspace differs from the requested project');
|
|
315
369
|
}
|
|
316
370
|
fold.verifiedPolicy(request);
|
|
371
|
+
nativeAdmission = fold.policy.native;
|
|
372
|
+
if (request.native && nativeAdmission?.matched !== true) throw new BridgeError('INVALID_REQUEST', 'native runtime did not attest its effective capabilities');
|
|
317
373
|
frame({ type: 'ready', sessionId, cwd: request.cwd, ...(request.workspaceCwd ? { workspaceCwd: request.workspaceCwd } : {}), provider: request.provider, model: request.model,
|
|
318
374
|
...(request.reasoningEffort === undefined ? {} : { reasoningEffort: request.reasoningEffort }),
|
|
319
375
|
permissionMode: request.permissionMode, approvalPolicy: 'never',
|
|
@@ -347,13 +403,19 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
347
403
|
}
|
|
348
404
|
waited = true;
|
|
349
405
|
outcome = fold.finish(receipt.messageId);
|
|
406
|
+
if (nativeTree) {
|
|
407
|
+
nativeRuntimeEvents = await readNativeEvents(temp, { ...policyIdentity, rootSessionId: sessionId });
|
|
408
|
+
nativeTree.observeRuntime(nativeRuntimeEvents);
|
|
409
|
+
completionAtRootEnd = nativeTree.completion();
|
|
410
|
+
if (!completionAtRootEnd.confirmed) throw new BridgeError('TRANSPORT', 'Native children remain active at root completion');
|
|
411
|
+
}
|
|
350
412
|
}
|
|
351
413
|
} catch (error) {
|
|
352
414
|
if (!warmClosed) failure = normalizedError(error);
|
|
353
415
|
} finally {
|
|
354
416
|
if (runtime) {
|
|
355
417
|
try {
|
|
356
|
-
const exit = await runtime.close();
|
|
418
|
+
const exit = await runtime.close({ graceMs: request?.native?.lcu?.enabled ? 135000 : request?.native ? 15000 : 2000 });
|
|
357
419
|
if (exit.spawned && (exit.forced || exit.code !== 0 || exit.signal || !exit.graceful)) {
|
|
358
420
|
settled = false;
|
|
359
421
|
failure ??= { code: 'TRANSPORT', message: 'DSH runtime did not prove graceful shutdown of its managed processes' };
|
|
@@ -376,6 +438,23 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
376
438
|
if (request && Date.now() - started > request.timeoutMs && !cancelled) {
|
|
377
439
|
failure = { code: 'TIMEOUT', message: 'DSH worker lifecycle deadline exceeded (including cleanup)' };
|
|
378
440
|
}
|
|
441
|
+
if (temp && nativeAttempted) {
|
|
442
|
+
try {
|
|
443
|
+
nativeCleanup = JSON.parse(await readFile(join(temp, 'native-cleanup.json'), 'utf8'));
|
|
444
|
+
if (nativeCleanup.version !== 1 || nativeCleanup.requestId !== policyIdentity.requestId || nativeCleanup.nonce !== policyIdentity.nonce ||
|
|
445
|
+
nativeCleanup.error !== undefined || nativeCleanup.journal?.complete !== true ||
|
|
446
|
+
(request.native?.lcu?.enabled && (!Array.isArray(nativeCleanup.cleanup) || nativeCleanup.cleanup.length < 1 ||
|
|
447
|
+
nativeCleanup.cleanup.some(value => value.cleanup !== 'confirmed' || !value.runtimeExitConfirmed || !value.turnCleanupConfirmed)))) {
|
|
448
|
+
throw new Error('native runtime did not confirm complete owned cleanup');
|
|
449
|
+
}
|
|
450
|
+
nativeRuntimeEvents = await readNativeEvents(temp, { ...policyIdentity, rootSessionId: sessionId }, nativeCleanup.journal);
|
|
451
|
+
nativeTree.observeRuntime(nativeRuntimeEvents);
|
|
452
|
+
} catch (error) { settled = false; failure ??= normalizedError(error); }
|
|
453
|
+
}
|
|
454
|
+
if (guiLease) {
|
|
455
|
+
try { await settleGuiLease(guiLease, settled && (!nativeAttempted || Boolean(nativeCleanup)), nativeCleanup ?? null); }
|
|
456
|
+
catch (error) { settled = false; failure ??= normalizedError(error); }
|
|
457
|
+
}
|
|
379
458
|
if (temp) await rm(temp, { recursive: true, force: true }).catch(error => {
|
|
380
459
|
failure ??= { code: 'TRANSPORT', message: `could not remove worker overlay: ${error.message}` };
|
|
381
460
|
});
|
|
@@ -395,7 +474,10 @@ export async function runWorker(input, { emit, env = process.env, signal, doctor
|
|
|
395
474
|
type: 'result', status: cancelled ? 'cancelled' : failure ? 'error' : 'ok', settled,
|
|
396
475
|
...(sessionId ? { sessionId } : {}),
|
|
397
476
|
text: outcome?.text ?? fold?.text ?? '',
|
|
398
|
-
usage: outcome?.usage ?? null, costUsd: null,
|
|
477
|
+
usage: nativeTree ? nativeTree.addUsage(outcome?.usage ?? null) : outcome?.usage ?? null, costUsd: null,
|
|
478
|
+
...(nativeTree ? { native: { ...nativeTree.receipt(nativeAdmission ?? { matched: false, observed: null },
|
|
479
|
+
{ confirmed: settled, scope: 'owned-sdk-tree', gui: nativeCleanup?.lcu ?? null }), runtimeEvents: nativeRuntimeEvents,
|
|
480
|
+
completion: completionAtRootEnd ?? { confirmed: false, pendingIds: [] } } } : {}),
|
|
399
481
|
...(failure ? { error: failure } : {}),
|
|
400
482
|
};
|
|
401
483
|
if ((formalStarted ? request.protocol : input?.protocol) === 2) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// Claude Code is an independent harness, not a DSH native model provider.
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { isAbsolute } from 'node:path';
|
|
4
|
+
import { validateNativeAdmission } from './machine-worker.mjs';
|
|
4
5
|
|
|
5
|
-
export const ADAPTER = Object.freeze({ package: 'dsh-subagent-claude-code-pro', version: '0.
|
|
6
|
+
export const ADAPTER = Object.freeze({ package: 'dsh-subagent-claude-code-pro', version: '0.5.0', protocol: 1 });
|
|
6
7
|
export const LIMITS = Object.freeze({ requestBytes: 1024 * 1024, machineOutputBytes: 1024 * 1024,
|
|
7
8
|
progressBytes: 1024 * 1024, receiptFrameBytes: 8 * 1024 * 1024, admissionMs: 10000 });
|
|
8
9
|
const require = createRequire(import.meta.url);
|
|
@@ -19,9 +20,9 @@ export async function loadAdapter() {
|
|
|
19
20
|
}
|
|
20
21
|
let manifest, api;
|
|
21
22
|
try { manifest = require('dsh-subagent-claude-code-pro/package.json'); }
|
|
22
|
-
catch { throw new WorkerError('ADAPTER_UNAVAILABLE', 'Install dsh-subagent-claude-code-pro@0.
|
|
23
|
+
catch { throw new WorkerError('ADAPTER_UNAVAILABLE', 'Install dsh-subagent-claude-code-pro@0.5.0 alongside @ckanner/flywheel; the optional adapter is not installed'); }
|
|
23
24
|
if (manifest.name !== ADAPTER.package || manifest.version !== ADAPTER.version) {
|
|
24
|
-
throw new WorkerError('ADAPTER_MISMATCH', 'Claude Code Pro package identity or version does not match the pinned 0.
|
|
25
|
+
throw new WorkerError('ADAPTER_MISMATCH', 'Claude Code Pro package identity or version does not match the pinned 0.5.0 machine contract');
|
|
25
26
|
}
|
|
26
27
|
try { api = await import('dsh-subagent-claude-code-pro/machine'); }
|
|
27
28
|
catch { throw new WorkerError('ADAPTER_UNAVAILABLE', 'The pinned Claude Code Pro public machine API could not be imported'); }
|
|
@@ -29,7 +30,12 @@ export async function loadAdapter() {
|
|
|
29
30
|
typeof api.runMachine !== 'function' || typeof api.MachineInputError !== 'function' ||
|
|
30
31
|
api.MACHINE_LIFECYCLE_VERSION !== 1 || typeof api.recoverMachine !== 'function' ||
|
|
31
32
|
api.MACHINE_LIFECYCLE_CAPABILITIES?.durableJournal !== true || api.MACHINE_LIFECYCLE_CAPABILITIES?.readOnlyRecovery !== true ||
|
|
32
|
-
api.MACHINE_LIFECYCLE_CAPABILITIES?.threadReadyBeforeDispatch !== false
|
|
33
|
+
api.MACHINE_LIFECYCLE_CAPABILITIES?.threadReadyBeforeDispatch !== false ||
|
|
34
|
+
api.MACHINE_NATIVE_VERSION !== 1 || api.MACHINE_NATIVE_CAPABILITIES?.version !== 1 ||
|
|
35
|
+
api.MACHINE_NATIVE_CAPABILITIES?.agents !== true || api.MACHINE_NATIVE_CAPABILITIES?.workflows !== true ||
|
|
36
|
+
typeof api.validateNativeReviewRequest !== 'function' || typeof api.validateInteractiveTeamRequest !== 'function' ||
|
|
37
|
+
typeof api.runNativeReview !== 'function' || typeof api.runInteractiveTeam !== 'function' ||
|
|
38
|
+
typeof api.recoverNativeJob !== 'function' || typeof api.controlInteractiveTeam !== 'function') {
|
|
33
39
|
throw new WorkerError('ADAPTER_MISMATCH', 'Claude Code Pro does not expose the pinned public machine API');
|
|
34
40
|
}
|
|
35
41
|
return api;
|
|
@@ -39,8 +45,9 @@ export async function loadAdapter() {
|
|
|
39
45
|
export function machineRequest(value, api, env) {
|
|
40
46
|
const lifecycle = value?.protocol === 3;
|
|
41
47
|
const persistent = value?.protocol === 2 || (lifecycle && value.threadMode === 'persistent');
|
|
42
|
-
const keys = new Set(['type', 'protocol', 'requestId', 'cwd', 'model', 'reasoningEffort', 'permissionMode', 'prompt', 'timeoutMs',
|
|
48
|
+
const keys = new Set(['type', 'protocol', 'requestId', 'cwd', 'model', 'reasoningEffort', 'permissionMode', 'prompt', 'timeoutMs', 'native', 'managed', 'images', 'outputSchema', 'maxBudgetUsd',
|
|
43
49
|
...(persistent || lifecycle ? ['threadMode', 'threadId'] : []), ...(lifecycle ? ['recoveryDirectory'] : [])]);
|
|
50
|
+
if (lifecycle) keys.add('nativeOperation');
|
|
44
51
|
if (value === null || typeof value !== 'object' || Array.isArray(value) || value.type !== 'start' ||
|
|
45
52
|
![1, 2, 3].includes(value.protocol) || Object.keys(value).some(key => !keys.has(key)) ||
|
|
46
53
|
typeof value.requestId !== 'string' || !value.requestId.trim() || value.requestId.length > 256 || value.requestId.includes('\0') ||
|
|
@@ -56,18 +63,60 @@ export function machineRequest(value, api, env) {
|
|
|
56
63
|
if (value.timeoutMs !== undefined && (!Number.isSafeInteger(value.timeoutMs) || value.timeoutMs < 1 || value.timeoutMs > 2147483647)) {
|
|
57
64
|
throw new WorkerError('INVALID_REQUEST', 'timeoutMs must be a positive safe integer no greater than 2147483647');
|
|
58
65
|
}
|
|
66
|
+
validateNativeAdmission(value.managed, value.requestId, WorkerError);
|
|
59
67
|
try {
|
|
68
|
+
if (value.nativeOperation !== undefined) return nativeJobRequest(value, api, env);
|
|
60
69
|
return api.parseMachineRequest({ protocol: 1, requestId: value.requestId, cwd: value.cwd, prompt: value.prompt,
|
|
61
70
|
model: value.model, effort: value.reasoningEffort, permissionMode: 'bypassPermissions',
|
|
62
71
|
sessionMode: persistent ? 'persistent' : 'ephemeral',
|
|
63
72
|
...(persistent && value.threadId !== undefined ? { sessionId: value.threadId } : {}),
|
|
64
73
|
...(value.timeoutMs === undefined ? {} : { timeoutMs: value.timeoutMs }),
|
|
74
|
+
...(value.native === undefined ? {} : { native: value.native }),
|
|
75
|
+
...(value.images === undefined ? {} : { images: value.images }),
|
|
76
|
+
...(value.outputSchema === undefined ? {} : { outputSchema: value.outputSchema }),
|
|
77
|
+
...(value.maxBudgetUsd === undefined ? {} : { maxBudgetUsd: value.maxBudgetUsd }),
|
|
65
78
|
command: env.FLYWHEEL_CLAUDE_BIN || 'claude', maxOutputBytes: LIMITS.machineOutputBytes });
|
|
66
79
|
} catch (error) {
|
|
67
80
|
throw new WorkerError('INVALID_REQUEST', error instanceof api.MachineInputError ? error.message : 'Invalid Claude Code Pro machine request');
|
|
68
81
|
}
|
|
69
82
|
}
|
|
70
83
|
|
|
84
|
+
/** Independent operations have their own public API, fresh identity and journal. */
|
|
85
|
+
function nativeJobRequest(value, api, env) {
|
|
86
|
+
const op = value.nativeOperation;
|
|
87
|
+
const common = { protocol: 1, requestId: value.requestId, cwd: value.cwd,
|
|
88
|
+
command: env.FLYWHEEL_CLAUDE_BIN || 'claude', ...(value.timeoutMs === undefined ? {} : { timeoutMs: value.timeoutMs }) };
|
|
89
|
+
if (!op || typeof op !== 'object' || Array.isArray(op) || value.threadMode !== 'ephemeral' || value.threadId !== undefined ||
|
|
90
|
+
value.images !== undefined || value.outputSchema !== undefined || value.maxBudgetUsd !== undefined) {
|
|
91
|
+
throw new api.MachineInputError('native operations require a fresh independent request without query-only media, schema or budget controls');
|
|
92
|
+
}
|
|
93
|
+
let request;
|
|
94
|
+
if (op.kind === 'remote-review') {
|
|
95
|
+
if (Object.keys(op).some(key => !['kind', 'target', 'consent', 'trustWorkspace', 'timeoutMinutes'].includes(key)) || value.native !== undefined) {
|
|
96
|
+
throw new api.MachineInputError('remote review accepts only its native target, consent, trust and timeout controls');
|
|
97
|
+
}
|
|
98
|
+
const { kind, ...review } = op;
|
|
99
|
+
request = { ...common, ...review, maxOutputBytes: LIMITS.machineOutputBytes };
|
|
100
|
+
api.validateNativeReviewRequest(request);
|
|
101
|
+
} else if (op.kind === 'interactive-team') {
|
|
102
|
+
if (Object.keys(op).some(key => !['kind', 'tmuxCommand', 'columns', 'rows'].includes(key))) throw new api.MachineInputError('unsupported interactive team control');
|
|
103
|
+
const { kind, ...team } = op;
|
|
104
|
+
request = { ...common, ...team, prompt: value.prompt, model: value.model, effort: value.reasoningEffort,
|
|
105
|
+
permissionMode: 'bypassPermissions', ...(value.native === undefined ? {} : { native: value.native }) };
|
|
106
|
+
api.validateInteractiveTeamRequest(request);
|
|
107
|
+
} else throw new api.MachineInputError('unsupported independent native operation');
|
|
108
|
+
return { requestId: value.requestId, nativeJob: { kind: op.kind, request } };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function invokeAdapter(api, request, options) {
|
|
112
|
+
if (request.nativeJob?.kind === 'remote-review') return api.runNativeReview(request.nativeJob.request, options);
|
|
113
|
+
if (request.nativeJob?.kind === 'interactive-team') return api.runInteractiveTeam(request.nativeJob.request, options);
|
|
114
|
+
return api.runMachine(request, options);
|
|
115
|
+
}
|
|
116
|
+
export function recoverAdapter(api, request, original) {
|
|
117
|
+
return original.nativeOperation === undefined ? api.recoverMachine(request) : api.recoverNativeJob(request);
|
|
118
|
+
}
|
|
119
|
+
|
|
71
120
|
// Go has already filtered its child's environment: credentials only enter via
|
|
72
121
|
// the explicitly selected channel, never from the orchestrator's ambient env.
|
|
73
122
|
export function runtimeOptions(env) {
|
|
@@ -78,5 +127,5 @@ export function runtimeOptions(env) {
|
|
|
78
127
|
|
|
79
128
|
export function doctorResult() {
|
|
80
129
|
return { protocol: 1, type: 'doctor', package: ADAPTER.package, version: ADAPTER.version,
|
|
81
|
-
machineProtocol: ADAPTER.protocol, available: true, inferenceTested: false };
|
|
130
|
+
machineProtocol: ADAPTER.protocol, nativeVersion: 1, available: true, inferenceTested: false };
|
|
82
131
|
}
|