feat: expand DeepSeek Harness compatibility

This commit is contained in:
lofyer
2026-08-14 12:38:01 +08:00
parent 36e05d45fa
commit 45aeecb6dd
32 changed files with 554 additions and 193 deletions
+3 -3
View File
@@ -177,10 +177,10 @@ async function run() {
config: {
workspace,
dshHome,
baseUrl: 'https://api.deepseek.com',
baseUrl: 'https://gateway.example/openai/v1',
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-chat',
model: 'qwen-plus',
harnessVersion: '0.1.0-rc.6',
sandbox: {
provider:
@@ -192,7 +192,7 @@ async function run() {
enforcement:
process.platform === 'win32' ? 'partial' : 'full'
},
credentialRefs: ['GOODBUDDY_DEEPSEEK_API_KEY'],
credentialRefs: ['GOODBUDDY_HARNESS_MODEL_API_KEY'],
skillPackages: [],
maxFrameBytes: 1024 * 1024
}
+12 -8
View File
@@ -77,7 +77,7 @@ GoodBuddy 不急于把该 Runtime 包装成标准 DSH 插件,也不以进入
- 支持多会话、同会话串行、跨会话并行。
- 支持按请求取消、超时、会话释放和应用退出时完整回收。
- 输出文本、推理、工具参数、工具结果、stderr 和协议队列全部有界。
- 使用真实 DeepSeek 模型验证调用,而不在日志、测试产物或提交中暴露凭据。
- 使用真实 OpenAI 兼容 Chat Completions 模型验证调用,而不在日志、测试产物或提交中暴露凭据。
- 保留 Windows、macOS、Linux 的 x64 和 arm64 发布能力。
### 4.2 首版非目标
@@ -153,7 +153,7 @@ Electron utilityProcess
└─ 最小工具集
│ HTTPS
用户选择的 DeepSeek 兼容模型连接
用户选择的 OpenAI 兼容模型连接
```
### 6.1 信任边界
@@ -369,7 +369,7 @@ Windows ACL 和旧 Linux Landlock 可能只报告 `partial`。界面和诊断必
- Agent、Session、LLM 和 Tool Registry 基础服务。
- GoodBuddy Harness Control Plane。
- DeepSeek 兼容 LLM 适配器。
- OpenAI 兼容 Chat Completions LLM 适配器。
- Sandbox Policy 与平台 Sandbox Provider。
- 平台对应的受沙箱 Shell。
- 受沙箱 Filesystem。
@@ -396,11 +396,13 @@ Windows ACL 和旧 Linux Landlock 可能只报告 `partial`。界面和诊断必
### 12.1 配置来源
DeepSeek Harness 首版只使用 GoodBuddy 模型连接:
DeepSeek Harness 首版只使用符合下列边界的 GoodBuddy 模型连接:
- 协议必须是 `openai-chat-completions`
- 认证必须是 API Key。
- 服务地址必须`https://api.deepseek.com`,且不得包含用户信息
- 公网服务地址必须使用 HTTPS`localhost``127.0.0.1``::1` 回环地址可以使用 HTTP
- 服务地址可以使用自定义主机、端口和部署路径,但不得包含用户名、密码、查询参数或片段。
- 模型名称不限制为 DeepSeek 品牌,由所选 OpenAI 兼容服务决定。
- 模型名称和服务地址由 Main 传入受控 Host。
- API Key 继续保存在 GoodBuddy 加密设置中。
- 启动环境提供的部署连接只由 Main 自动解析,不在 Renderer 中显示为可选来源。
@@ -458,7 +460,7 @@ Runtime 的概览、模型配置和检测信息放在同一张详情卡中。当
```text
Runtime GoodBuddy 内置 DeepSeek Harness
模型配置: 跟随 GoodBuddy · dsv4flashdeepseek-v4-flash
模型配置: 跟随 GoodBuddy · 企业网关(qwen-plus
状态: 已就绪
路径: <受控 Host 路径>
版本: 0.1.0-rc.6
@@ -528,6 +530,7 @@ Renderer 只接收脱敏状态。任何凭据、完整环境、启动参数或
- 确认这些模块不会被加载。
- 评估它们带来的 audit 和体积风险。
- 在后续上游版本允许时改为最小包族。
- 确认 `tests/fixtures` 以及 Web3D 测试 Skill/MCP 不进入正式发布资源。
### 16.4 漏洞门禁
@@ -549,6 +552,7 @@ Renderer 只接收脱敏状态。任何凭据、完整环境、启动参数或
- 平台原生 Sandbox/PTY 依赖架构正确。
- Harness、ACP SDK 和其他新增第三方许可证已打包。
- `app.asar` 外需要执行或动态加载的资源位于预期目录。
- Web3D Skill/MCP 等测试 fixture 不在 `app.asar``extraResources` 中。
## 17. 测试策略
@@ -582,7 +586,7 @@ Renderer 只接收脱敏状态。任何凭据、完整环境、启动参数或
### 17.3 真实模型测试
真实测试已经获得用户授权,但必须由显式环境门禁启用。至少验证:
真实测试已经获得用户授权,但必须由显式环境门禁启用。Web3D Skill 和 MCP 仅作为 `tests/fixtures` 下的测试资产使用,不属于内置发布能力。至少验证:
1. 文本问答成功,并记录正确 Runtime 和模型用量。
2. Ask 可以读取工作区,但写入被拒绝,且不会弹出权限对话框。
@@ -625,7 +629,7 @@ npm run build
- 用户 DSH 配置、`.env`、遥测和 Web UI 未被加载。
- API Key 不进入 Renderer、配置文件、日志、错误文本或测试产物。
- 全量测试、类型检查、Lint 和生产构建通过。
- 真实 DeepSeek 请求成功。
- 真实 OpenAI 兼容 Chat Completions 请求成功。
- 真实请求调用已分配 Skill 和 MCP,并生成、启动和实际游玩一个可用的 3D 游戏项目。
- 新增第三方许可证和发布校验完整。
+28 -1
View File
@@ -99,10 +99,37 @@ describe('createAgentRuntime model compatibility', () => {
{ deepseekHarnessLauncher: vi.fn() }
)
).toThrow(
'DeepSeek Harness 需要 api.deepseek.com 的 OpenAI Chat Completions 模型连接'
'DeepSeek Harness 需要使用 API Key 的安全 OpenAI 兼容 Chat Completions 模型连接'
)
})
it('creates DeepSeek Harness with a compatible HTTPS gateway profile', async () => {
const profile = {
id: '00000000-0000-4000-8000-000000000006',
name: 'OpenAI-compatible gateway',
baseUrl: 'https://gateway.example/openai/v1',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions' as const,
authentication: 'api-key' as const,
imageGenerationQuality: 'auto' as const,
apiKey: 'gateway-key'
}
const runtime = createAgentRuntime(
process.cwd(),
settings({
provider: 'deepseek-harness',
modelProfiles: [profile],
defaultModelProfileId: profile.id,
deepseekHarnessModelProfile: profile,
runtimeSandboxMode: 'auto'
}),
{ deepseekHarnessLauncher: vi.fn() }
)
expect(runtime.runtimeId).toBe('deepseek-harness')
await runtime.dispose()
})
it('creates an available direct runtime for a no-auth model', async () => {
const runtime = createAgentRuntime(process.cwd(), settings())
+2 -2
View File
@@ -113,7 +113,7 @@ export function createAgentRuntime(
const profile = settings?.deepseekHarnessModelProfile
if (!profile || !isDeepSeekHarnessModelProfile(profile)) {
throw new Error(
'DeepSeek Harness 需要 api.deepseek.com 的 OpenAI Chat Completions 模型连接'
'DeepSeek Harness 需要使用 API Key 的安全 OpenAI 兼容 Chat Completions 模型连接'
)
}
if (!profile.apiKey) {
@@ -131,7 +131,7 @@ export function createAgentRuntime(
model: profile.modelName,
launch: capabilities.deepseekHarnessLauncher,
credentialRefs: {
GOODBUDDY_DEEPSEEK_API_KEY: profile.apiKey
GOODBUDDY_HARNESS_MODEL_API_KEY: profile.apiKey
},
requiredSandboxEnforcement:
sandboxMode === 'strict' ? 'full' : 'partial',
@@ -26,7 +26,7 @@ import {
import { GOODBUDDY_HARNESS_MAX_STEP_TOKENS } from './goodbuddy-harness-control-plane'
const MAX_FRAME_BYTES = 1024 * 1024
const CREDENTIAL_REF = 'GOODBUDDY_DEEPSEEK_API_KEY'
const CREDENTIAL_REF = 'GOODBUDDY_HARNESS_MODEL_API_KEY'
const SKILL_CALL_ID = 'e2e-skill-call'
const MCP_CALL_ID = 'e2e-mcp-call'
const ASK_MCP_CALL_ID = 'e2e-ask-mcp-call'
@@ -536,9 +536,9 @@ describe('DeepSeek Harness real ACP control-plane E2E', () => {
{
id: 'web-3d-game',
directory: resolve(
'resources',
'skills',
'web-3d-game'
'tests',
'fixtures',
'web-3d-game-skill'
)
}
],
@@ -0,0 +1,118 @@
import type childProcess from 'node:child_process'
import { describe, expect, it, vi } from 'vitest'
import { installHarnessChildProcessWindowGuard } from './deepseek-harness-child-process'
type HarnessChildProcessModule = Pick<
typeof childProcess,
'execFileSync' | 'spawn' | 'spawnSync'
>
function fakeChildProcessModule(): {
target: HarnessChildProcessModule
execFileSync: ReturnType<typeof vi.fn>
spawn: ReturnType<typeof vi.fn>
spawnSync: ReturnType<typeof vi.fn>
} {
const execFileSync = vi.fn(() => 'output')
const spawn = vi.fn(() => ({ pid: 1 }))
const spawnSync = vi.fn(() => ({ status: 0 }))
return {
target: {
execFileSync:
execFileSync as unknown as HarnessChildProcessModule['execFileSync'],
spawn: spawn as unknown as HarnessChildProcessModule['spawn'],
spawnSync:
spawnSync as unknown as HarnessChildProcessModule['spawnSync']
},
execFileSync,
spawn,
spawnSync
}
}
describe('DeepSeek Harness child process window guard', () => {
it('does not alter child process launches outside Windows', () => {
const { target, spawn } = fakeChildProcessModule()
const originalSpawn = target.spawn
const syncExports = vi.fn()
const restore = installHarnessChildProcessWindowGuard(
'linux',
target,
syncExports
)
expect(target.spawn).toBe(originalSpawn)
expect(syncExports).not.toHaveBeenCalled()
restore()
expect(spawn).not.toHaveBeenCalled()
expect(syncExports).not.toHaveBeenCalled()
})
it('forces hidden Windows launches and restores the original functions', () => {
const { target, execFileSync, spawn, spawnSync } =
fakeChildProcessModule()
const originals = { ...target }
const syncExports = vi.fn()
const restore = installHarnessChildProcessWindowGuard(
'win32',
target,
syncExports
)
target.spawn('runner.exe', ['--probe'], {
cwd: 'C:\\workspace',
windowsHide: false
})
target.spawnSync('taskkill.exe', {
stdio: 'ignore'
})
target.spawnSync('where.exe', undefined, {
encoding: 'utf8'
})
target.execFileSync('where.exe', ['pwsh.exe'], {
encoding: 'utf8',
windowsHide: false
})
expect(spawn).toHaveBeenCalledWith(
'runner.exe',
['--probe'],
expect.objectContaining({
cwd: 'C:\\workspace',
windowsHide: true
})
)
expect(spawnSync).toHaveBeenCalledWith(
'where.exe',
undefined,
expect.objectContaining({
encoding: 'utf8',
windowsHide: true
})
)
expect(spawnSync).toHaveBeenCalledWith(
'taskkill.exe',
expect.objectContaining({
stdio: 'ignore',
windowsHide: true
})
)
expect(execFileSync).toHaveBeenCalledWith(
'where.exe',
['pwsh.exe'],
expect.objectContaining({
encoding: 'utf8',
windowsHide: true
})
)
expect(syncExports).toHaveBeenCalledTimes(1)
restore()
restore()
expect(target).toMatchObject(originals)
expect(syncExports).toHaveBeenCalledTimes(2)
})
})
@@ -0,0 +1,82 @@
import childProcess from 'node:child_process'
import { syncBuiltinESMExports } from 'node:module'
type HarnessChildProcessModule = Pick<
typeof childProcess,
'execFileSync' | 'spawn' | 'spawnSync'
>
type SyncBuiltinExports = () => void
function withHiddenWindow(args: unknown[]): unknown[] {
const next = [...args]
const optionsIndex =
Array.isArray(next[1]) ||
(next[1] === undefined && next.length >= 3)
? 2
: 1
const options = next[optionsIndex]
next[optionsIndex] = {
...(options && typeof options === 'object' ? options : {}),
windowsHide: true
}
return next
}
/**
* DeepSeek Harness 0.1.0-rc.6 omits `windowsHide` when its local subprocess
* service starts the ACL runner and PowerShell. In an Electron GUI process
* that can briefly create a visible console window. Keep this override scoped
* to the isolated Harness UtilityProcess and synchronize the built-in ESM
* bindings already captured by the bundled Harness modules.
*/
export function installHarnessChildProcessWindowGuard(
platform: NodeJS.Platform = process.platform,
target: HarnessChildProcessModule = childProcess,
syncExports: SyncBuiltinExports = syncBuiltinESMExports
): () => void {
if (platform !== 'win32') {
return () => undefined
}
const originals = {
execFileSync: target.execFileSync,
spawn: target.spawn,
spawnSync: target.spawnSync
}
const guardedExecFileSync = ((...args: unknown[]) =>
Reflect.apply(
originals.execFileSync,
target,
withHiddenWindow(args)
)) as typeof target.execFileSync
const guardedSpawn = ((...args: unknown[]) =>
Reflect.apply(
originals.spawn,
target,
withHiddenWindow(args)
)) as typeof target.spawn
const guardedSpawnSync = ((...args: unknown[]) =>
Reflect.apply(
originals.spawnSync,
target,
withHiddenWindow(args)
)) as typeof target.spawnSync
target.execFileSync = guardedExecFileSync
target.spawn = guardedSpawn
target.spawnSync = guardedSpawnSync
syncExports()
let restored = false
return () => {
if (restored) {
return
}
restored = true
target.execFileSync = originals.execFileSync
target.spawn = originals.spawn
target.spawnSync = originals.spawnSync
syncExports()
}
}
@@ -49,8 +49,8 @@ async function fixture() {
launchOptions: {
cwd: workspace,
signal: new AbortController().signal,
baseUrl: 'https://api.deepseek.com',
model: 'deepseek-chat',
baseUrl: 'https://gateway.example/openai/v1',
model: 'qwen-plus',
credentialRefs: [DEEPSEEK_HARNESS_CREDENTIAL_REF],
skillPackages: []
}
@@ -97,7 +97,8 @@ describe('DeepSeek Harness utility launcher', () => {
expect(utility.messages[0]).toMatchObject({
type: 'start',
config: {
baseUrl: 'https://api.deepseek.com',
baseUrl: 'https://gateway.example/openai/v1',
model: 'qwen-plus',
credentialRefs: [DEEPSEEK_HARNESS_CREDENTIAL_REF]
}
})
@@ -144,4 +145,24 @@ describe('DeepSeek Harness utility launcher', () => {
await expect(launching).rejects.toThrow('启动协议无效')
expect(terminateProcess).toHaveBeenCalledOnce()
})
it.each([
'http://gateway.example/v1',
'https://user:secret@gateway.example/v1',
'https://gateway.example/v1?api-version=2025-01-01'
])('rejects unsafe endpoint %s before forking', async (baseUrl) => {
const { dshHome, hostPath, launchOptions } = await fixture()
const fork = vi.fn()
const launcher = createDeepSeekHarnessUtilityLauncher({
bundledHostPath: hostPath,
dshHome,
environment: {},
fork
})
await expect(
launcher({ ...launchOptions, baseUrl })
).rejects.toThrow('HTTPS')
expect(fork).not.toHaveBeenCalled()
})
})
@@ -3,6 +3,7 @@ import { realpath, stat } from 'node:fs/promises'
import { isAbsolute } from 'node:path'
import type { UtilityProcess } from 'electron'
import { z } from 'zod'
import { isDeepSeekHarnessCompatibleBaseUrl } from '../../shared/deepseek-harness-compatibility'
import type {
DeepSeekHarnessChild,
DeepSeekHarnessLaunchOptions
@@ -14,7 +15,7 @@ export const DEEPSEEK_HARNESS_CONTROL_PROTOCOL =
export const DEEPSEEK_HARNESS_CONTROL_VERSION = 1
export const DEEPSEEK_HARNESS_HOST_VERSION = '0.1.0-rc.6'
export const DEEPSEEK_HARNESS_CREDENTIAL_REF =
'GOODBUDDY_DEEPSEEK_API_KEY'
'GOODBUDDY_HARNESS_MODEL_API_KEY'
const sandboxSchema = z
.object({
@@ -41,15 +42,7 @@ export const controlledHarnessHostConfigSchema = z
baseUrl: z
.url()
.max(2_048)
.refine((value) => {
const url = new URL(value)
return (
url.protocol === 'https:' &&
url.hostname.toLowerCase() === 'api.deepseek.com' &&
!url.username &&
!url.password
)
}),
.refine(isDeepSeekHarnessCompatibleBaseUrl),
api: z.literal('openai-completions'),
provider: z.literal('goodbuddy'),
model: z.string().min(1).max(128),
@@ -240,12 +233,9 @@ export function createDeepSeekHarnessUtilityLauncher(
'DeepSeek Harness 当前平台只能提供部分沙箱强制'
)
}
if (
options.baseUrl !== 'https://api.deepseek.com' &&
options.baseUrl !== 'https://api.deepseek.com/'
) {
if (!isDeepSeekHarnessCompatibleBaseUrl(options.baseUrl)) {
throw new Error(
'DeepSeek Harness 仅允许 api.deepseek.com'
'DeepSeek Harness 模型地址必须使用 HTTPS 或本机回环 HTTP,且不得包含凭据、查询参数或片段'
)
}
if (
+19 -19
View File
@@ -10,7 +10,7 @@ const defaultProfileId = '00000000-0000-4000-8000-000000000001'
const secondProfileId = '00000000-0000-4000-8000-000000000002'
const responsesProfileId = '00000000-0000-4000-8000-000000000003'
const imageProfileId = '00000000-0000-4000-8000-000000000004'
const deepseekProfileId = '00000000-0000-4000-8000-000000000005'
const harnessProfileId = '00000000-0000-4000-8000-000000000005'
function settings(
overrides: Partial<ResolvedRuntimeSettings> = {}
@@ -65,10 +65,10 @@ function settings(
apiKey: 'image-key'
},
{
id: deepseekProfileId,
name: 'DeepSeek',
baseUrl: 'https://api.deepseek.com',
modelName: 'deepseek-chat',
id: harnessProfileId,
name: 'OpenAI-compatible gateway',
baseUrl: 'https://gateway.example/openai/v1',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions',
authentication: 'api-key',
imageGenerationQuality: 'auto',
@@ -165,31 +165,31 @@ describe('runtime selection', () => {
).toThrow('自动启动')
})
it('selects DeepSeek Harness only with an official compatible profile', () => {
it('selects DeepSeek Harness with a compatible gateway profile', () => {
const selected = applyRuntimeSelection(settings(), {
provider: 'deepseek-harness',
profileId: deepseekProfileId
profileId: harnessProfileId
})
expect(selected.target).toBe('deepseek-harness')
expect(selected.settings).toMatchObject({
provider: 'deepseek-harness',
deepseekHarnessModelProfile: { id: deepseekProfileId }
deepseekHarnessModelProfile: { id: harnessProfileId }
})
expect(() =>
applyRuntimeSelection(settings(), {
provider: 'deepseek-harness',
profileId: secondProfileId
})
).toThrow('api.deepseek.com')
).toThrow('API Key')
})
it('keeps the controlled platform DeepSeek profile when selected without a profile ID', () => {
it('keeps the controlled platform Harness profile when selected without a profile ID', () => {
const base = settings()
const platformProfile = {
...base.modelProfiles[4]!,
id: 'goodbuddy-platform-deepseek',
name: '平台 DeepSeek',
modelName: 'deepseek-v4-flash'
id: 'goodbuddy-platform-harness',
name: '管理员预置模型',
modelName: 'qwen-plus'
}
const selected = applyRuntimeSelection(
settings({ deepseekHarnessModelProfile: platformProfile }),
@@ -199,8 +199,8 @@ describe('runtime selection', () => {
expect(selected.settings).toMatchObject({
provider: 'deepseek-harness',
deepseekHarnessModelProfile: {
id: 'goodbuddy-platform-deepseek',
modelName: 'deepseek-v4-flash'
id: 'goodbuddy-platform-harness',
modelName: 'qwen-plus'
}
})
})
@@ -219,7 +219,7 @@ describe('runtime selection', () => {
})
).toEqual({
provider: 'deepseek-harness',
profileId: deepseekProfileId
profileId: harnessProfileId
})
expect(
resolveConfiguredAgentRuntimeSelection(configured, {
@@ -249,13 +249,13 @@ describe('runtime selection', () => {
})
})
it('keeps the controlled platform DeepSeek source profile-free across configured selection repair', () => {
it('keeps the controlled platform Harness source profile-free across configured selection repair', () => {
const base = settings()
const configured = settings({
deepseekHarnessModelProfile: {
...base.modelProfiles[4]!,
id: 'goodbuddy-platform-deepseek',
name: '平台 DeepSeek'
id: 'goodbuddy-platform-harness',
name: '管理员预置模型'
}
})
+1 -1
View File
@@ -139,7 +139,7 @@ export function applyRuntimeSelection(
!isDeepSeekHarnessModelProfile(selectedProfile)
) {
throw new Error(
'DeepSeek Harness 独立模型连接仅支持 api.deepseek.com 的 OpenAI Chat Completions 协议'
'DeepSeek Harness 仅支持使用 API Key 的安全 OpenAI 兼容 Chat Completions 连接'
)
}
return {
+5 -9
View File
@@ -63,12 +63,8 @@ describe('bundled skills', () => {
expect(snapshot.skills.map((skill) => skill.id)).toContain(
'product-marketing'
)
expect(snapshot.skills).toContainEqual(
expect.objectContaining({
id: 'web-3d-game',
name: 'Web 3D Game',
assignments: expect.arrayContaining(['deepseek-harness'])
})
expect(snapshot.skills.map((skill) => skill.id)).not.toContain(
'web-3d-game'
)
})
@@ -84,7 +80,7 @@ describe('bundled skills', () => {
}
})
it('exposes the 3D game Skill as a native Harness package', async () => {
it('exposes bundled Skills as native Harness packages', async () => {
const service = await createService()
await expect(
@@ -92,8 +88,8 @@ describe('bundled skills', () => {
).resolves.toMatchObject({
packages: expect.arrayContaining([
{
id: 'web-3d-game',
directory: join(builtinSkillsRoot, 'web-3d-game')
id: 'product-marketing',
directory: join(builtinSkillsRoot, 'product-marketing')
}
])
})
@@ -12,9 +12,12 @@ import {
startControlledDeepSeekHarnessHost,
type ControlledHarnessHost
} from './deepseek-harness-host'
import { installHarnessChildProcessWindowGuard } from './agent/deepseek-harness-child-process'
const parentPort = process.parentPort
const restoreDiagnostics = installHarnessDiagnosticGuard()
const restoreChildProcessWindowGuard =
installHarnessChildProcessWindowGuard()
// The Windows ACL sandbox launches its JavaScript runner through
// `process.execPath`. Inside an Electron UtilityProcess that path is Electron,
// so descendants must opt into Electron's supported Node execution mode.
@@ -41,6 +44,7 @@ async function close(): Promise<void> {
closed = true
await host?.dispose().catch(() => undefined)
transport?.dispose()
restoreChildProcessWindowGuard()
restoreDiagnostics()
}
+3 -3
View File
@@ -46,7 +46,7 @@ describe('controlled DeepSeek Harness host', () => {
dshHome: 'C:\\controlled-dsh-home',
skillPackages: []
})
).rejects.toThrow('trusted HTTPS DeepSeek endpoint')
).rejects.toThrow('secure OpenAI-compatible')
})
it('suppresses console payloads instead of contaminating stdout', () => {
@@ -84,10 +84,10 @@ describe('controlled DeepSeek Harness host', () => {
const host = await startControlledDeepSeekHarnessHost({
workspace: root,
dshHome: root,
baseUrl: 'https://api.deepseek.com',
baseUrl: 'https://gateway.example/openai/v1',
api: 'openai-completions',
provider: 'goodbuddy',
model: 'deepseek-test',
model: 'qwen-plus',
harnessVersion: '0.1.0-rc.6',
sandbox: expectedSandbox,
credentialRefs: ['GOODBUDDY_API_KEY'],
+3 -9
View File
@@ -30,6 +30,7 @@ import {
} from './agent/goodbuddy-harness-control-plane'
import type { Stream } from '@agentclientprotocol/sdk'
import type { SandboxEnforcement } from '@deepseek-ai/dsh-sandbox'
import { isDeepSeekHarnessCompatibleBaseUrl } from '../shared/deepseek-harness-compatibility'
const DEFAULT_MAX_FRAME_BYTES = 1024 * 1024
const MAX_DIAGNOSTIC_BYTES = 64 * 1024
@@ -133,19 +134,12 @@ type PluginSpec = {
function validateHostConfig(
config: ControlledHarnessHostConfig
): void {
const endpoint = URL.canParse(config.baseUrl)
? new URL(config.baseUrl)
: undefined
if (
config.api !== 'openai-completions' ||
!endpoint ||
endpoint.protocol !== 'https:' ||
endpoint.hostname.toLowerCase() !== 'api.deepseek.com' ||
endpoint.username ||
endpoint.password
!isDeepSeekHarnessCompatibleBaseUrl(config.baseUrl)
) {
throw new Error(
'Controlled Harness requires the trusted HTTPS DeepSeek endpoint'
'Controlled Harness requires a secure OpenAI-compatible Chat Completions endpoint'
)
}
if (!config.credentialRefs.length) {
+34 -31
View File
@@ -104,7 +104,7 @@ describe('RuntimeSettingsStore', () => {
})
})
it('migrates DeepSeek Harness to controlled platform mode and stores an official profile', async () => {
it('migrates DeepSeek Harness to controlled platform mode and stores a compatible profile', async () => {
const { filePath, store } = await createStore()
await store.update(settings())
const versionFourteen = JSON.parse(
@@ -127,9 +127,9 @@ describe('RuntimeSettingsStore', () => {
modelProfiles: [
{
id: profileId,
name: 'DeepSeek',
baseUrl: 'https://api.deepseek.com',
modelName: 'deepseek-chat',
name: 'OpenAI-compatible gateway',
baseUrl: 'https://gateway.example/openai/v1',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions',
authentication: 'api-key',
imageGenerationQuality: 'auto',
@@ -149,21 +149,22 @@ describe('RuntimeSettingsStore', () => {
})
})
it('resolves a controlled platform DeepSeek profile without exposing its credential', async () => {
const apiKey = 'platform-deepseek-secret'
it('resolves a controlled platform Harness profile without exposing its credential', async () => {
const apiKey = 'platform-harness-secret'
const { store } = await createStore({
GOODBUDDY_MODEL_API_KEY: apiKey,
GOODBUDDY_MODEL_BASE_URL: 'https://api.deepseek.com/',
GOODBUDDY_MODEL_NAME: 'deepseek-v4-flash'
GOODBUDDY_MODEL_BASE_URL:
'https://gateway.example/openai/v1',
GOODBUDDY_MODEL_NAME: 'qwen-plus'
})
await expect(store.getResolvedSettings()).resolves.toMatchObject({
modelProtocol: 'anthropic-messages',
deepseekHarnessModelProfile: {
id: 'goodbuddy-platform-deepseek',
name: '平台 DeepSeek',
baseUrl: 'https://api.deepseek.com/',
modelName: 'deepseek-v4-flash',
id: 'goodbuddy-platform-harness',
name: '管理员预置模型',
baseUrl: 'https://gateway.example/openai/v1',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions',
authentication: 'api-key',
supportsImageInput: false,
@@ -179,37 +180,39 @@ describe('RuntimeSettingsStore', () => {
it.each([
[
'a non-DeepSeek endpoint',
'an insecure public endpoint',
{
GOODBUDDY_MODEL_API_KEY: 'platform-key',
GOODBUDDY_MODEL_BASE_URL: 'https://deepseek.example',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
GOODBUDDY_MODEL_BASE_URL: 'http://gateway.example/v1',
GOODBUDDY_MODEL_NAME: 'qwen-plus'
}
],
[
'an insecure DeepSeek endpoint',
'an endpoint with embedded credentials',
{
GOODBUDDY_MODEL_API_KEY: 'platform-key',
GOODBUDDY_MODEL_BASE_URL: 'http://api.deepseek.com',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
GOODBUDDY_MODEL_BASE_URL:
'https://user:secret@gateway.example/v1',
GOODBUDDY_MODEL_NAME: 'qwen-plus'
}
],
[
'a DeepSeek endpoint path',
'an endpoint with a query string',
{
GOODBUDDY_MODEL_API_KEY: 'platform-key',
GOODBUDDY_MODEL_BASE_URL: 'https://api.deepseek.com/v1',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
GOODBUDDY_MODEL_BASE_URL:
'https://gateway.example/v1?api-version=1',
GOODBUDDY_MODEL_NAME: 'qwen-plus'
}
],
[
'a missing API key',
{
GOODBUDDY_MODEL_BASE_URL: 'https://api.deepseek.com',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
GOODBUDDY_MODEL_BASE_URL: 'https://gateway.example/v1',
GOODBUDDY_MODEL_NAME: 'qwen-plus'
}
]
])('does not resolve platform DeepSeek from %s', async (_, environment) => {
])('does not resolve platform Harness from %s', async (_, environment) => {
const { store } = await createStore(environment)
await expect(store.getResolvedSettings()).resolves.toMatchObject({
@@ -253,7 +256,7 @@ describe('RuntimeSettingsStore', () => {
)
})
it('rejects incompatible DeepSeek Harness model profiles', () => {
it('accepts compatible gateways and rejects incompatible Harness profiles', () => {
const profileId = '00000000-0000-4000-8000-000000000045'
expect(
runtimeSettingsInputSchema.safeParse(
@@ -261,9 +264,9 @@ describe('RuntimeSettingsStore', () => {
modelProfiles: [
{
id: profileId,
name: 'Other compatible API',
name: 'Compatible API',
baseUrl: 'https://other.example/v1',
modelName: 'deepseek-chat',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions',
authentication: 'api-key',
imageGenerationQuality: 'auto',
@@ -274,16 +277,16 @@ describe('RuntimeSettingsStore', () => {
deepseekHarnessModelSource: { kind: 'profile', profileId }
})
).success
).toBe(false)
).toBe(true)
expect(
runtimeSettingsInputSchema.safeParse(
settings({
modelProfiles: [
{
id: profileId,
name: 'DeepSeek without API key',
baseUrl: 'https://api.deepseek.com',
modelName: 'deepseek-chat',
name: 'Gateway without API key',
baseUrl: 'https://other.example/v1',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions',
authentication: 'none',
imageGenerationQuality: 'auto',
+13 -21
View File
@@ -263,7 +263,7 @@ const embeddingCredentialPayloadSchema = z.object({
})
const rerankCredentialPayloadSchema = embeddingCredentialPayloadSchema
const platformDeepSeekProfileId = 'goodbuddy-platform-deepseek'
const platformHarnessProfileId = 'goodbuddy-platform-harness'
export type CredentialCipher = SettingsCredentialCipher
@@ -1041,33 +1041,25 @@ export class RuntimeSettingsStore {
)
}
private resolvePlatformDeepSeekProfile(): ResolvedModelProfile | undefined {
private resolvePlatformHarnessProfile(): ResolvedModelProfile | undefined {
const apiKey = this.environment.GOODBUDDY_MODEL_API_KEY?.trim()
const baseUrl = this.environment.GOODBUDDY_MODEL_BASE_URL?.trim()
const modelName = this.environment.GOODBUDDY_MODEL_NAME?.trim()
if (!apiKey || !baseUrl || !modelName) {
return undefined
}
try {
const endpoint = new URL(baseUrl)
if (
endpoint.protocol !== 'https:' ||
endpoint.hostname.toLowerCase() !== 'api.deepseek.com' ||
endpoint.port ||
endpoint.pathname !== '/' ||
endpoint.search ||
endpoint.hash ||
endpoint.username ||
endpoint.password
) {
return undefined
}
} catch {
if (
!isDeepSeekHarnessModelProfile({
baseUrl,
protocol: 'openai-chat-completions',
authentication: 'api-key'
})
) {
return undefined
}
return {
id: platformDeepSeekProfileId,
name: '平台 DeepSeek',
id: platformHarnessProfileId,
name: '管理员预置模型',
baseUrl,
modelName,
protocol: 'openai-chat-completions',
@@ -1406,7 +1398,7 @@ export class RuntimeSettingsStore {
? profilesById.get(
settings.deepseekHarnessModelSource.profileId
)
: this.resolvePlatformDeepSeekProfile()
: this.resolvePlatformHarnessProfile()
return {
provider: settings.provider,
modelBaseUrl: effective.baseUrl,
@@ -1726,7 +1718,7 @@ export class RuntimeSettingsStore {
}
if (!isDeepSeekHarnessModelProfile(profile)) {
throw new Error(
'DeepSeek Harness 模型连接仅支持 api.deepseek.com 的 OpenAI Chat Completions 协议'
'DeepSeek Harness 仅支持使用 API Key 的安全 OpenAI 兼容 Chat Completions 连接'
)
}
}
@@ -503,7 +503,7 @@ describe('ChannelSettingsSection', () => {
).toBeInTheDocument()
expect(
within(backend).getByRole('option', {
name: 'DeepSeek Harness(预览 · 仅 DeepSeek'
name: 'DeepSeek Harness(预览 · OpenAI 兼容'
})
).toBeInTheDocument()
+17 -15
View File
@@ -1372,7 +1372,7 @@ describe('SettingsPanel runtime files', () => {
)
})
it('configures DeepSeek Harness with a compatible GoodBuddy connection', async () => {
it('configures DeepSeek Harness with an OpenAI-compatible gateway', async () => {
const harnessProfileId =
'00000000-0000-4000-8000-000000000051'
getRuntime.mockResolvedValueOnce({
@@ -1382,9 +1382,9 @@ describe('SettingsPanel runtime files', () => {
{
...runtimeSettings.modelProfiles[0]!,
id: harnessProfileId,
name: 'DeepSeek Chat',
baseUrl: 'https://api.deepseek.com/v1',
modelName: 'deepseek-chat',
name: 'Compatible Gateway',
baseUrl: 'https://gateway.example/openai/v1',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions'
}
],
@@ -1409,10 +1409,10 @@ describe('SettingsPanel runtime files', () => {
})
)
expect(
screen.getByText('开发者预览 · 仅支持 DeepSeek')
screen.getByText('开发者预览 · OpenAI 兼容')
).toBeInTheDocument()
expect(
screen.getByText(/当前仅支持 DeepSeek 模型/)
screen.getByText(/公网地址必须使用 HTTPS/)
).toBeInTheDocument()
const harnessOverview = screen
.getByText('GoodBuddy 内置 DeepSeek Harness')
@@ -1451,17 +1451,19 @@ describe('SettingsPanel runtime files', () => {
})
).not.toBeInTheDocument()
const source = screen.getByLabelText(
'DeepSeek Harness DeepSeek 模型连接'
'DeepSeek Harness OpenAI 兼容模型连接'
)
expect(screen.queryByRole('radio')).not.toBeInTheDocument()
expect(
screen.queryByText('使用平台 DeepSeek 环境配置')
screen.queryByText('使用管理员预置模型连接')
).not.toBeInTheDocument()
expect(
within(source).getByRole('option', { name: '默认模型(不兼容)' })
).toBeDisabled()
expect(
within(source).getByRole('option', { name: 'DeepSeek Chat' })
within(source).getByRole('option', {
name: 'Compatible Gateway'
})
).not.toBeDisabled()
fireEvent.click(screen.getByRole('button', { name: '保存设置' }))
@@ -1480,14 +1482,14 @@ describe('SettingsPanel runtime files', () => {
it('keeps an environment-managed source compatible without exposing it as an option', async () => {
getRuntime.mockResolvedValueOnce({
...runtimeSettings,
modelBaseUrl: 'https://api.deepseek.com',
modelName: 'deepseek-chat',
modelBaseUrl: 'https://gateway.example/openai/v1',
modelName: 'qwen-plus',
modelProtocol: 'openai-chat-completions',
modelProfiles: [
{
...runtimeSettings.modelProfiles[0]!,
baseUrl: 'https://api.deepseek.com',
modelName: 'deepseek-chat',
baseUrl: 'https://gateway.example/openai/v1',
modelName: 'qwen-plus',
protocol: 'openai-chat-completions',
credentialSource: 'environment'
}
@@ -1531,10 +1533,10 @@ describe('SettingsPanel runtime files', () => {
)
expect(screen.queryByRole('radio')).not.toBeInTheDocument()
expect(
screen.getByText('管理员预置的 DeepSeek 连接')
screen.getByText('管理员预置的 OpenAI 兼容连接')
).toBeInTheDocument()
const source = screen.getByLabelText(
'DeepSeek Harness DeepSeek 模型连接'
'DeepSeek Harness OpenAI 兼容模型连接'
)
expect(source).toHaveValue('')
fireEvent.change(source, {
+1 -1
View File
@@ -1973,7 +1973,7 @@ export function SettingsPanel({
</div>
</div>
<p className="settings-notice">
{t('runtime.deepseekHarness.deepseekOnlyNotice')}
{t('runtime.deepseekHarness.compatibilityNotice')}
</p>
<RuntimeOverviewCard
detection={detection?.deepseekHarness}
+1 -1
View File
@@ -118,7 +118,7 @@ export const app = {
picker: 'Runtime and model',
directModels: 'Direct models',
deepseekHarnessGroup:
'DeepSeek Harness (Developer preview · DeepSeek only)',
'DeepSeek Harness (Developer preview · OpenAI-compatible)',
manage: 'Manage Runtime and model connections',
errors: {
readStatus: 'Failed to read Agent Runtime status',
@@ -32,7 +32,7 @@ export const integrations = {
missingProfile: 'The previous direct model no longer exists',
noTextModels: 'No text models are available',
deepseekHarnessOption:
'DeepSeek Harness (Preview · DeepSeek only)',
'DeepSeek Harness (Preview · OpenAI-compatible)',
missingSelection:
'The selected direct model no longer exists. Choose another model.',
imageOnlySelection:
@@ -237,16 +237,18 @@ export const settings = {
deepseekHarness: {
selectorLabel: 'DeepSeek Harness (Preview)',
title: 'DeepSeek Harness',
previewDescription: 'Developer preview · DeepSeek only',
deepseekOnlyNotice:
'DeepSeek Harness currently supports DeepSeek models only and is not intended for other model providers.',
previewDescription: 'Developer preview · OpenAI-compatible',
compatibilityNotice:
'Supports OpenAI-compatible Chat Completions connections with an API key. Public endpoints must use HTTPS; loopback endpoints may use HTTP.',
description:
'GoodBuddy maintains the fixed Host and control protocol internally and uses pinned Harness libraries underneath. Execute tool calls receive automatic one-time authorization, Ask remains read-only, and cancellation and workspace safety boundaries remain in place. It does not integrate with the DSH plugin or marketplace mechanisms.',
managedSource: 'Administrator-provided DeepSeek connection',
connection: 'DeepSeek model connection',
connectionPlaceholder: 'Select a DeepSeek model connection',
managedSource:
'Administrator-provided OpenAI-compatible connection',
connection: 'OpenAI-compatible model connection',
connectionPlaceholder:
'Select an OpenAI-compatible model connection',
connectionDescription:
'Choose a GoodBuddy model connection. Only OpenAI-compatible Chat Completions connections that point to DeepSeek are supported.',
'Choose a GoodBuddy model connection. It must use OpenAI Chat Completions with API-key authentication.',
advancedDescription:
'This Runtime always uses GoodBuddys bundled, version-pinned Host. It does not load external DSH plugins, marketplace packages, user profiles, or custom Hosts.'
}
@@ -504,7 +506,7 @@ export const settings = {
incompatibleImageProtocol:
'Incompatible (image generation protocol is unsupported)',
incompatibleHarnessProtocol:
'Incompatible (Chat Completions only)',
'Incompatible (requires Chat Completions, an API key, and a secure endpoint)',
secureStorageWarning:
'Secure system key storage is unavailable. Use an environment variable to avoid storing an API Key in plaintext.'
},
+2 -1
View File
@@ -113,7 +113,8 @@ export const app = {
switching: '切换中…',
picker: 'Runtime 和模型',
directModels: '直连模型',
deepseekHarnessGroup: 'DeepSeek Harness(开发者预览 · 仅 DeepSeek',
deepseekHarnessGroup:
'DeepSeek Harness(开发者预览 · OpenAI 兼容)',
manage: '管理 Runtime 和模型连接',
errors: {
readStatus: 'Agent Runtime 状态读取失败',
@@ -26,7 +26,8 @@ export const integrations = {
unavailableProfile: '{{name}} · {{modelName}}(不可用)',
missingProfile: '原直连模型已不存在',
noTextModels: '暂无可用文本模型',
deepseekHarnessOption: 'DeepSeek Harness(预览 · 仅 DeepSeek',
deepseekHarnessOption:
'DeepSeek Harness(预览 · OpenAI 兼容)',
missingSelection: '所选直连模型已不存在,请重新选择。',
imageOnlySelection:
'所选连接仅支持图片生成,请选择文本模型或 Agent Runtime。',
@@ -215,16 +215,16 @@ export const settings = {
deepseekHarness: {
selectorLabel: 'DeepSeek Harness(预览)',
title: 'DeepSeek Harness',
previewDescription: '开发者预览 · 仅支持 DeepSeek',
deepseekOnlyNotice:
'DeepSeek Harness 当前仅支持 DeepSeek 模型,不适用于其他模型提供商。',
previewDescription: '开发者预览 · OpenAI 兼容',
compatibilityNotice:
'支持使用 API Key 的 OpenAI 兼容 Chat Completions 连接;公网地址必须使用 HTTPS,本机回环地址可使用 HTTP。',
description:
'由 GoodBuddy 内部维护固定 Host 与控制协议,复用锁定的 Harness 底层库;Execute 工具调用自动单次授权,Ask 保持只读,并保留取消和工作区安全边界;不接入 DSH 插件或市场机制。',
managedSource: '管理员预置的 DeepSeek 连接',
connection: 'DeepSeek 模型连接',
connectionPlaceholder: '选择 DeepSeek 模型连接',
managedSource: '管理员预置的 OpenAI 兼容连接',
connection: 'OpenAI 兼容模型连接',
connectionPlaceholder: '选择 OpenAI 兼容模型连接',
connectionDescription:
'从 GoodBuddy 模型连接中选择;仅支持指向 DeepSeek 的 OpenAI 兼容 Chat Completions 连接。',
'从 GoodBuddy 模型连接中选择;协议必须为 OpenAI Chat Completions,并使用 API Key。',
advancedDescription:
'该 Runtime 始终使用 GoodBuddy 内置并固定版本的 Host,不加载外部 DSH 插件、市场包、用户 profile 或自定义 Host。'
}
@@ -462,7 +462,7 @@ export const settings = {
incompatible: '不兼容',
incompatibleImageProtocol: '不兼容(不支持图像生成协议)',
incompatibleHarnessProtocol:
'不兼容(仅支持 Chat Completions',
'不兼容( Chat Completions、API Key 和安全地址',
secureStorageWarning:
'当前系统密钥服务不可用。为了避免明文落盘,请使用环境变量提供 API Key。'
},
+6 -21
View File
@@ -121,6 +121,11 @@ import {
agentRuntimeSelectionSchema,
type AgentRuntimeSelection
} from './runtime-selection-contracts'
import { isDeepSeekHarnessModelProfile } from './deepseek-harness-compatibility'
export {
isDeepSeekHarnessCompatibleBaseUrl,
isDeepSeekHarnessModelProfile
} from './deepseek-harness-compatibility'
export const workspaceRelativePathSchema = z
.string()
@@ -392,26 +397,6 @@ export const runtimeModelSourceSchema = z.discriminatedUnion('kind', [
.strict()
])
export function isDeepSeekHarnessModelProfile(
profile: Pick<
ModelConnectionSettings,
'baseUrl' | 'protocol' | 'authentication'
>
): boolean {
if (
profile.protocol !== 'openai-chat-completions' ||
profile.authentication !== 'api-key'
) {
return false
}
try {
return new URL(profile.baseUrl).hostname.toLowerCase() ===
'api.deepseek.com'
} catch {
return false
}
}
export const runtimeSettingsInputSchema = z
.object({
provider: runtimeProviderSchema,
@@ -590,7 +575,7 @@ export const runtimeSettingsInputSchema = z
code: 'custom',
path: ['deepseekHarnessModelSource'],
message:
'DeepSeek Harness 独立模型连接仅支持 api.deepseek.com 的 OpenAI Chat Completions 协议'
'DeepSeek Harness 仅支持使用 API Key 的安全 OpenAI 兼容 Chat Completions 连接'
})
}
}
@@ -0,0 +1,52 @@
import { describe, expect, it } from 'vitest'
import {
isDeepSeekHarnessCompatibleBaseUrl,
isDeepSeekHarnessModelProfile
} from './deepseek-harness-compatibility'
describe('DeepSeek Harness model compatibility', () => {
it.each([
'https://api.deepseek.com',
'https://gateway.example/openai/v1',
'https://gateway.example:8443/v1',
'http://127.0.0.1:11434/v1',
'http://localhost:1234/v1',
'http://[::1]:8080/v1'
])('accepts OpenAI-compatible base URL %s', (baseUrl) => {
expect(isDeepSeekHarnessCompatibleBaseUrl(baseUrl)).toBe(true)
expect(
isDeepSeekHarnessModelProfile({
baseUrl,
protocol: 'openai-chat-completions',
authentication: 'api-key'
})
).toBe(true)
})
it.each([
'http://gateway.example/v1',
'file:///private/config',
'https://user:secret@gateway.example/v1',
'https://gateway.example/v1?api-version=2025-01-01',
'https://gateway.example/v1#chat'
])('rejects unsafe or unsupported base URL %s', (baseUrl) => {
expect(isDeepSeekHarnessCompatibleBaseUrl(baseUrl)).toBe(false)
})
it('rejects other protocols and unauthenticated profiles', () => {
expect(
isDeepSeekHarnessModelProfile({
baseUrl: 'https://gateway.example/v1',
protocol: 'openai-responses',
authentication: 'api-key'
})
).toBe(false)
expect(
isDeepSeekHarnessModelProfile({
baseUrl: 'https://gateway.example/v1',
protocol: 'openai-chat-completions',
authentication: 'none'
})
).toBe(false)
})
})
@@ -0,0 +1,50 @@
type DeepSeekHarnessModelProfile = {
baseUrl: string
protocol: string
authentication: string
}
function isLoopbackHostname(hostname: string): boolean {
const normalized = hostname
.toLowerCase()
.replace(/^\[|\]$/gu, '')
return (
normalized === 'localhost' ||
normalized === '127.0.0.1' ||
normalized === '::1'
)
}
export function isDeepSeekHarnessCompatibleBaseUrl(
value: string
): boolean {
try {
const url = new URL(value)
if (
!url.hostname ||
url.username ||
url.password ||
url.search ||
url.hash
) {
return false
}
return (
url.protocol === 'https:' ||
(url.protocol === 'http:' &&
isLoopbackHostname(url.hostname))
)
} catch {
return false
}
}
export function isDeepSeekHarnessModelProfile(
profile: DeepSeekHarnessModelProfile
): boolean {
return (
profile.protocol === 'openai-chat-completions' &&
profile.authentication === 'api-key' &&
isDeepSeekHarnessCompatibleBaseUrl(profile.baseUrl)
)
}
+6 -6
View File
@@ -1,4 +1,5 @@
import { z } from 'zod'
import { isDeepSeekHarnessModelProfile } from './deepseek-harness-compatibility'
const runtimeSelectionProfileIdSchema = z.string().uuid()
@@ -82,12 +83,11 @@ function isDeepSeekHarnessRepairProfileUsable(
) {
return false
}
try {
return new URL(profile.baseUrl).hostname.toLowerCase() ===
'api.deepseek.com'
} catch {
return false
}
return isDeepSeekHarnessModelProfile({
baseUrl: profile.baseUrl,
protocol: profile.protocol,
authentication: profile.authentication
})
}
export function repairChannelRuntimeSelection(
+37
View File
@@ -295,6 +295,43 @@ describe('release build arguments', () => {
'@koromix/koffi-win32-x64': '3.1.4'
})
})
it('keeps Web3D test fixtures out of release resources', () => {
const packageJson = require('../package.json') as {
build: {
files: string[]
extraResources: Array<{ from: string }>
}
}
const resourceSources = packageJson.build.extraResources.map(
(entry) => entry.from
)
expect(packageJson.build.files).toEqual([
'out/**/*',
'package.json'
])
expect(resourceSources).toContain('resources/skills')
expect(
resourceSources.some((source) => source.startsWith('tests/'))
).toBe(false)
expect(
existsSync(join('resources', 'skills', 'web-3d-game'))
).toBe(false)
expect(
existsSync(join('resources', 'web-3d-game-mcp.mjs'))
).toBe(false)
expect(
existsSync(
join(
'tests',
'fixtures',
'web-3d-game-skill',
'SKILL.md'
)
)
).toBe(true)
})
})
describe('release binary architecture detection', () => {