@luchenglong/cli-bridge 0.2.6 → 0.2.8
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 +72 -0
- package/docs/HANDOVER.md +9 -0
- package/docs/audits/2026-10-18-preset-0.2.1-contract-fix.md +160 -0
- package/docs/audits/README.md +15 -0
- package/dynamic/codebuddy.host.js +204 -150
- package/dynamic/mimo.host.js +514 -616
- package/dynamic/opencode.host.js +584 -628
- package/home-plugin/cli-bridge-indicator/lib/preset-declarations.mjs +85 -6
- package/mcp/cli-bridge-mcp.mjs +2 -1
- package/package.json +5 -4
- package/preset/agy-first/agent.cordis.yml +0 -5
- package/preset/agy-first/plugin-list.mjs +4 -1
- package/preset/codebuddy-first/agent.cordis.yml +0 -5
- package/preset/mimo-first/agent.cordis.yml +1 -7
- package/preset/mimo-first/plugin-list.mjs +18 -12
- package/preset/mimo-member/plugin-list.mjs +49 -0
- package/preset/opencode-first/agent.cordis.yml +0 -5
- package/preset/opencode-first/plugin-list.mjs +4 -2
- package/preset/standard-base.mjs +18 -6
- package/providers/codebuddy-catalog.mjs +32 -38
- package/providers/codebuddy-consts.mjs +72 -0
- package/providers/codebuddy-models-tool.mjs +25 -25
- package/providers/codebuddy-schemas.mjs +46 -0
- package/providers/codebuddy.mjs +33 -91
- package/providers/mimo-pure.mjs +111 -0
- package/providers/mimo.mjs +517 -618
- package/providers/opencode-exe.mjs +63 -0
- package/providers/opencode.mjs +587 -629
|
@@ -27,6 +27,23 @@ export const PKG_NAME = '@luchenglong/cli-bridge'
|
|
|
27
27
|
// 三个旧包时代的遗留布局,provider id 不带 —— 这里不映射就永远找不到 plugin-list)。
|
|
28
28
|
const PRESET_DIRS = { agy: 'agy-first', codebuddy: 'codebuddy-first', mimo: 'mimo-first', opencode: 'opencode-first' }
|
|
29
29
|
|
|
30
|
+
// 【成员预设】0.2.1 起 dsh-tool-subagent 的 config 不再接受 persona/toolFilter(apply()
|
|
31
|
+
// 里显式 throw),角色人格只能作为独立 Agent Preset 存在、由委派行经 agentPreset 选择。
|
|
32
|
+
// key = provider id(决定它是否随该 provider 的启用面注册,与主预设的启用语义一致);
|
|
33
|
+
// value = { id: 预设身份(委派行按它选择), dir: preset/<dir>/plugin-list.mjs }。
|
|
34
|
+
// ⚠ 必须**先于**对应 provider 的主预设注册:主预设委派行的 validate() 会对每个
|
|
35
|
+
// agentPreset id 调 presets.readDocument(id),未注册即抛 agent-preset/not-found,
|
|
36
|
+
// 而 apply() 一抛就拖垮整组预设挂载(这正是 mimo 在 0.2.1 上挂载失败的根因链)。
|
|
37
|
+
const MEMBER_PRESETS = { mimo: { id: 'cordis-mimo-member', dir: 'mimo-member' } }
|
|
38
|
+
|
|
39
|
+
/** 只读视图:provider id → 成员预设 id(测试与诊断从它派生,避免第二处硬编码)。 */
|
|
40
|
+
export function memberPresetIds(ids) {
|
|
41
|
+
const list = ids || []
|
|
42
|
+
return Object.entries(MEMBER_PRESETS)
|
|
43
|
+
.filter(([providerId]) => list.includes(providerId))
|
|
44
|
+
.map(([, member]) => member.id)
|
|
45
|
+
}
|
|
46
|
+
|
|
30
47
|
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
31
48
|
const ROOT = join(HERE, '..', '..', '..')
|
|
32
49
|
|
|
@@ -46,26 +63,85 @@ function realize(v, seen) {
|
|
|
46
63
|
return out
|
|
47
64
|
}
|
|
48
65
|
|
|
49
|
-
|
|
50
|
-
|
|
66
|
+
/** 按 preset 目录名加载单源 plugin-list(provider 预设与成员预设共用)。 */
|
|
67
|
+
async function loadPluginListDir(dir) {
|
|
68
|
+
const abs = join(ROOT, 'preset', dir, 'plugin-list.mjs')
|
|
51
69
|
if (!existsSync(abs)) return null
|
|
52
70
|
const mod = await import(pathToFileURL(abs).href)
|
|
53
71
|
if (!mod || typeof mod.buildPlugins !== 'function' || !mod.meta) return null
|
|
54
72
|
return mod
|
|
55
73
|
}
|
|
56
74
|
|
|
75
|
+
async function loadPluginList(id) {
|
|
76
|
+
return loadPluginListDir(PRESET_DIRS[id] || id)
|
|
77
|
+
}
|
|
78
|
+
|
|
57
79
|
/**
|
|
58
|
-
*
|
|
80
|
+
* 按【目录名】生成 agentPresets 定义(真函数已落地;不含任何 DSH 活对象)。
|
|
81
|
+
* bridgeName 决定桥接行的入口子路径:provider 预设用 '/preset-<id>',成员预设用
|
|
82
|
+
* 其所属 provider 的同一入口(子 agent 要能调到该 provider 的 run 工具)。
|
|
59
83
|
* @returns {Promise<{id,name,description,order,plugins}|null>}
|
|
60
84
|
*/
|
|
61
|
-
|
|
62
|
-
const mod = await
|
|
85
|
+
async function buildDefinitionFromDir(dir, bridgeName) {
|
|
86
|
+
const mod = await loadPluginListDir(dir)
|
|
63
87
|
if (!mod) return null
|
|
64
88
|
const meta = mod.meta
|
|
65
|
-
const plugins = realize(mod.buildPlugins({ bridgeName
|
|
89
|
+
const plugins = realize(mod.buildPlugins({ bridgeName }) || [], [])
|
|
66
90
|
return { id: meta.id, name: meta.name || meta.id, description: meta.description || '', order: meta.order != null ? meta.order : 10, plugins }
|
|
67
91
|
}
|
|
68
92
|
|
|
93
|
+
/**
|
|
94
|
+
* 生成某 provider 的 agentPresets 定义。
|
|
95
|
+
* @returns {Promise<{id,name,description,order,plugins}|null>}
|
|
96
|
+
*/
|
|
97
|
+
export async function buildPresetDefinition(id) {
|
|
98
|
+
return buildDefinitionFromDir(PRESET_DIRS[id] || id, PKG_NAME + '/preset-' + id)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* 注册某 provider 的成员预设(先行注册)。只注册启用面里的 provider,与主预设一致。
|
|
103
|
+
* @param ctx - 指示灯插件的 context。
|
|
104
|
+
* @param out - 与主预设共用的诊断数组。
|
|
105
|
+
* @param ids - 已启用(按调度顺序)的 provider id 列表。
|
|
106
|
+
*/
|
|
107
|
+
function declareMemberPresets(ctx, out, ids) {
|
|
108
|
+
if (typeof ctx.inject !== 'function') return
|
|
109
|
+
for (const [providerId, member] of Object.entries(MEMBER_PRESETS)) {
|
|
110
|
+
if (!ids.includes(providerId)) continue
|
|
111
|
+
try {
|
|
112
|
+
ctx.inject(['agentPresets'], (child) => {
|
|
113
|
+
child.effect(() => {
|
|
114
|
+
let disposer = null
|
|
115
|
+
const registering = (async () => {
|
|
116
|
+
try {
|
|
117
|
+
const def = await buildDefinitionFromDir(member.dir, PKG_NAME + '/preset-' + providerId)
|
|
118
|
+
if (!def) { out.push({ id: member.id, ok: false, error: 'plugin-list missing' }); return }
|
|
119
|
+
disposer = await child.agentPresets.register(def)
|
|
120
|
+
out.push({ id: member.id, ok: true, member: true })
|
|
121
|
+
} catch (e) {
|
|
122
|
+
out.push({ id: member.id, ok: false, error: String(e && e.message || e) })
|
|
123
|
+
try {
|
|
124
|
+
if (child.logger && typeof child.logger.warn === 'function') {
|
|
125
|
+
child.logger.warn('cli-bridge: member preset ' + member.id + ' registration skipped: ' + (e && e.message || e))
|
|
126
|
+
}
|
|
127
|
+
} catch (_) { }
|
|
128
|
+
}
|
|
129
|
+
})()
|
|
130
|
+
return async () => {
|
|
131
|
+
try { await registering } catch (_) { }
|
|
132
|
+
if (typeof disposer === 'function') {
|
|
133
|
+
try { await disposer() } catch (_) { }
|
|
134
|
+
}
|
|
135
|
+
disposer = null
|
|
136
|
+
}
|
|
137
|
+
}, 'cli-bridge: member preset declaration ' + member.id)
|
|
138
|
+
})
|
|
139
|
+
} catch (e) {
|
|
140
|
+
out.push({ id: member.id, ok: false, error: String(e && e.message || e) })
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
69
145
|
/**
|
|
70
146
|
* 在 indicator 的 ctx 上挂「agentPresets 就绪 → 注册启用面的 preset」等待器。
|
|
71
147
|
* 返回每个 provider 的注册状态数组(诊断用);任何异常都不外抛。
|
|
@@ -89,6 +165,9 @@ export function declareBridgePresets(ctx, opts) {
|
|
|
89
165
|
}
|
|
90
166
|
const out = []
|
|
91
167
|
if (typeof ctx.inject !== 'function') return out
|
|
168
|
+
// 成员预设先注册:主预设委派行的 validate() 会经 presets.readDocument(id) 校验
|
|
169
|
+
// agentPreset 引用存在,未注册即抛 agent-preset/not-found。
|
|
170
|
+
declareMemberPresets(ctx, out, ids)
|
|
92
171
|
for (const id of ids) {
|
|
93
172
|
try {
|
|
94
173
|
ctx.inject(['agentPresets'], (child) => {
|
package/mcp/cli-bridge-mcp.mjs
CHANGED
|
@@ -31,7 +31,7 @@ import * as mimoMcp from './providers/mimo.mjs'
|
|
|
31
31
|
import * as opencodeMcp from './providers/opencode.mjs'
|
|
32
32
|
|
|
33
33
|
const SERVER_NAME = 'cli-bridge-mcp'
|
|
34
|
-
const SERVER_VERSION = '0.2.
|
|
34
|
+
const SERVER_VERSION = '0.2.8'
|
|
35
35
|
const PROTOCOL = '2024-11-05'
|
|
36
36
|
|
|
37
37
|
const PROVIDERS = [agyMcp, codebuddyMcp, mimoMcp, opencodeMcp]
|
|
@@ -183,3 +183,4 @@ process.stdin.on('data', (d) => {
|
|
|
183
183
|
process.stdin.on('end', () => { stdinClosed = true; maybeExit() })
|
|
184
184
|
process.on('SIGINT', () => process.exit(0))
|
|
185
185
|
process.on('SIGTERM', () => process.exit(0))
|
|
186
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luchenglong/cli-bridge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "CLI Bridge for DeepSeek Harness (DSH): one package bridging four local coding-CLI agents — agy (Google Antigravity CLI), Tencent CodeBuddy Code, Xiaomi MiMo (MiMoCode / MiMo Desktop), and OpenCode. Each provider keeps its own agent preset (cordis-agy / codebuddy-first / cordis-mimo / opencode-first), tools (agy_run / codebuddy_run / mimo_run / opencode_run + continue + status), rate-limit/network fallback dialog, and zero-dependency MCP server, unified under a single home-level status light, one settings file, and one bundle patch. Merges agy-first-bridge, codebuddy-first-bridge and mimo-first-bridge.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"url": "https://github.com/new-256/cli-bridge/issues"
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
- id: persona
|
|
5
5
|
name: '@deepseek-ai/dsh-persona'
|
|
6
6
|
config:
|
|
7
|
-
suffix: 'Your working directory is {{cwd}}.'
|
|
8
7
|
prefix: 'You are a coding agent powered by the {{model}} model.'
|
|
9
8
|
- id: agent-instructions
|
|
10
9
|
name: '@deepseek-ai/dsh-agent-instructions'
|
|
@@ -86,20 +85,17 @@
|
|
|
86
85
|
provider: spawn
|
|
87
86
|
toolName: subagent
|
|
88
87
|
modelSelectionSettings: true
|
|
89
|
-
backgroundMode: continuable
|
|
90
88
|
- id: tool-subagent-fork
|
|
91
89
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
92
90
|
config:
|
|
93
91
|
provider: fork
|
|
94
92
|
toolName: subagent_fork
|
|
95
|
-
backgroundMode: continuable
|
|
96
93
|
- id: tool-subagent-codex
|
|
97
94
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
98
95
|
disabled: true
|
|
99
96
|
config:
|
|
100
97
|
provider: codex
|
|
101
98
|
toolName: subagent_codex
|
|
102
|
-
backgroundMode: one-shot
|
|
103
99
|
maxDepth: provider-managed
|
|
104
100
|
- id: tool-subagent-claude-code
|
|
105
101
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
@@ -107,7 +103,6 @@
|
|
|
107
103
|
config:
|
|
108
104
|
provider: claude-code
|
|
109
105
|
toolName: subagent_claude_code
|
|
110
|
-
backgroundMode: one-shot
|
|
111
106
|
maxDepth: provider-managed
|
|
112
107
|
- id: workflow-ptc
|
|
113
108
|
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
@@ -16,10 +16,13 @@ export function buildPlugins(deps) {
|
|
|
16
16
|
const rows = standardPluginRows()
|
|
17
17
|
// 旧仓 agent.cordis.yml persona 段 verbatim(v1.5.15:dsh-persona 要求
|
|
18
18
|
// prefix 必填 + suffix 可选;旧单 text: 字段被 schema 拒绝)。
|
|
19
|
+
// 2026-10-18:不再设置 suffix —— 当前 DSH 只注册 provider/model 两个提示词变量,
|
|
20
|
+
// 工作目录由 working-directory 服务作为不插值的用户上下文提供,写 {{cwd}} 会让
|
|
21
|
+
// 本预设整轮组装失败(unknown prompt variable)。delete 兼防基座再引入 suffix。
|
|
19
22
|
const persona = rows.find((r) => r.id === 'persona')
|
|
20
23
|
if (persona && persona.config) {
|
|
21
24
|
persona.config.prefix = 'You are a coding agent powered by the {{model}} model.'
|
|
22
|
-
persona.config.suffix
|
|
25
|
+
delete persona.config.suffix
|
|
23
26
|
}
|
|
24
27
|
rows.push(bridgeRow('agy', deps && deps.bridgeName))
|
|
25
28
|
return rows
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
- id: persona
|
|
5
5
|
name: '@deepseek-ai/dsh-persona'
|
|
6
6
|
config:
|
|
7
|
-
suffix: 'Your working directory is {{cwd}}.'
|
|
8
7
|
prefix: 'You are a coding agent powered by the {{model}} model.'
|
|
9
8
|
- id: agent-instructions
|
|
10
9
|
name: '@deepseek-ai/dsh-agent-instructions'
|
|
@@ -86,20 +85,17 @@
|
|
|
86
85
|
provider: spawn
|
|
87
86
|
toolName: subagent
|
|
88
87
|
modelSelectionSettings: true
|
|
89
|
-
backgroundMode: continuable
|
|
90
88
|
- id: tool-subagent-fork
|
|
91
89
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
92
90
|
config:
|
|
93
91
|
provider: fork
|
|
94
92
|
toolName: subagent_fork
|
|
95
|
-
backgroundMode: continuable
|
|
96
93
|
- id: tool-subagent-codex
|
|
97
94
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
98
95
|
disabled: true
|
|
99
96
|
config:
|
|
100
97
|
provider: codex
|
|
101
98
|
toolName: subagent_codex
|
|
102
|
-
backgroundMode: one-shot
|
|
103
99
|
maxDepth: provider-managed
|
|
104
100
|
- id: tool-subagent-claude-code
|
|
105
101
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
@@ -107,7 +103,6 @@
|
|
|
107
103
|
config:
|
|
108
104
|
provider: claude-code
|
|
109
105
|
toolName: subagent_claude_code
|
|
110
|
-
backgroundMode: one-shot
|
|
111
106
|
maxDepth: provider-managed
|
|
112
107
|
- id: workflow-ptc
|
|
113
108
|
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
- id: persona
|
|
5
5
|
name: '@deepseek-ai/dsh-persona'
|
|
6
6
|
config:
|
|
7
|
-
suffix: 'Your working directory is {{cwd}}.'
|
|
8
7
|
prefix: 'You are a coding agent powered by the {{model}} model.'
|
|
9
8
|
- id: agent-instructions
|
|
10
9
|
name: '@deepseek-ai/dsh-agent-instructions'
|
|
@@ -86,22 +85,18 @@
|
|
|
86
85
|
provider: spawn
|
|
87
86
|
toolName: subagent
|
|
88
87
|
modelSelectionSettings: true
|
|
89
|
-
|
|
90
|
-
persona: 'Delegation directive: you are a child agent in a MiMo-first session. Before doing any coding, building, debugging, or multi-file investigation work yourself, check whether the mimo_run tool (or the MCP form mcp__mimo__mimo_run) is available to you; if it is, dispatch that work to mimo first per the MiMo-first policy, then verify its output with your own read-only tools. Reserve your own direct work for quick read-only lookups and final verification.'
|
|
88
|
+
agentPreset: cordis-mimo-member
|
|
91
89
|
- id: tool-subagent-fork
|
|
92
90
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
93
91
|
config:
|
|
94
92
|
provider: fork
|
|
95
93
|
toolName: subagent_fork
|
|
96
|
-
backgroundMode: continuable
|
|
97
|
-
persona: 'Delegation directive: you are a child agent in a MiMo-first session. Before doing any coding, building, debugging, or multi-file investigation work yourself, check whether the mimo_run tool (or the MCP form mcp__mimo__mimo_run) is available to you; if it is, dispatch that work to mimo first per the MiMo-first policy, then verify its output with your own read-only tools. Reserve your own direct work for quick read-only lookups and final verification.'
|
|
98
94
|
- id: tool-subagent-codex
|
|
99
95
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
100
96
|
disabled: true
|
|
101
97
|
config:
|
|
102
98
|
provider: codex
|
|
103
99
|
toolName: subagent_codex
|
|
104
|
-
backgroundMode: one-shot
|
|
105
100
|
maxDepth: provider-managed
|
|
106
101
|
- id: tool-subagent-claude-code
|
|
107
102
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
@@ -109,7 +104,6 @@
|
|
|
109
104
|
config:
|
|
110
105
|
provider: claude-code
|
|
111
106
|
toolName: subagent_claude_code
|
|
112
|
-
backgroundMode: one-shot
|
|
113
107
|
maxDepth: provider-managed
|
|
114
108
|
- id: workflow-ptc
|
|
115
109
|
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// preset/mimo-first/plugin-list.mjs — cordis-mimo 预设的单源插件清单(PROVIDER-CONTRACT §5)。
|
|
2
2
|
//
|
|
3
|
-
// = 官方 standard 基线(standard-base.mjs)+ mimo 桥接行 +
|
|
4
|
-
// preset/mimo-first/agent.cordis.yml 的 persona 与 tool-subagent 委派文案 verbatim)。
|
|
3
|
+
// = 官方 standard 基线(standard-base.mjs)+ mimo 桥接行 + 委派差异。
|
|
5
4
|
// preset id 'cordis-mimo' 是旧会话头引用,不可变。
|
|
6
5
|
import { standardPluginRows, bridgeRow } from '../standard-base.mjs'
|
|
7
6
|
|
|
@@ -12,26 +11,33 @@ export const meta = {
|
|
|
12
11
|
order: 10
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
/**
|
|
15
|
+
* 子 agent 所用的成员预设 id(人格与工具面在 preset/mimo-member/plugin-list.mjs)。
|
|
16
|
+
* 0.2.1 起角色人格不能再写在 dsh-tool-subagent 行上,只能由 agentPreset 指向独立预设。
|
|
17
|
+
*/
|
|
18
|
+
export const MEMBER_PRESET_ID = 'cordis-mimo-member'
|
|
18
19
|
|
|
19
20
|
export function buildPlugins(deps) {
|
|
20
21
|
const rows = standardPluginRows()
|
|
21
|
-
// persona
|
|
22
|
-
//
|
|
22
|
+
// persona 行:prefix 与官方 standard 逐字一致({{model}})。
|
|
23
|
+
// 2026-10-18:不再设置 suffix —— DSH 只注册 provider/model 两个变量,工作目录由
|
|
24
|
+
// working-directory 服务以不插值的用户上下文提供,{{cwd}} 会让本预设整轮组装失败。
|
|
23
25
|
const persona = rows.find((r) => r.id === 'persona')
|
|
24
26
|
if (persona && persona.config) {
|
|
25
27
|
persona.config.prefix = 'You are a coding agent powered by the {{model}} model.'
|
|
26
|
-
persona.config.suffix
|
|
28
|
+
delete persona.config.suffix
|
|
27
29
|
}
|
|
28
|
-
//
|
|
30
|
+
// 委派组:0.2.1 起人格与工具面属于【独立成员预设】,委派行只用 agentPreset 选择它。
|
|
29
31
|
const delegation = rows.find((r) => r.id === 'delegation')
|
|
30
32
|
if (delegation && Array.isArray(delegation.config)) {
|
|
31
33
|
for (const child of delegation.config) {
|
|
32
|
-
if (child
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
if (!child || child.name !== '@deepseek-ai/dsh-tool-subagent' || !child.config) continue
|
|
35
|
+
// persona/toolFilter 会被 dsh-tool-subagent 的 apply() 直接 throw,写进去就是
|
|
36
|
+
// 整个预设挂载失败 —— 一律删除(人格已迁到成员预设)。
|
|
37
|
+
delete child.config.persona
|
|
38
|
+
delete child.config.toolFilter
|
|
39
|
+
// agentPreset 只有 in-process spawn 支持;fork 与外部后端会拒绝它,故只给 spawn。
|
|
40
|
+
if (child.config.provider === 'spawn') child.config.agentPreset = MEMBER_PRESET_ID
|
|
35
41
|
}
|
|
36
42
|
}
|
|
37
43
|
rows.push(bridgeRow('mimo', deps && deps.bridgeName))
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// preset/mimo-member/plugin-list.mjs — cordis-mimo 的【成员预设】单源清单(PROVIDER-CONTRACT §5)。
|
|
2
|
+
//
|
|
3
|
+
// 为什么需要它(2026-10-18 实测结论):
|
|
4
|
+
// dsh-tool-subagent 0.2.1 起,config 里的 `persona` / `toolFilter` 会在 apply() 里
|
|
5
|
+
// **显式 throw**("tool-subagent: persona is no longer supported; configure persona
|
|
6
|
+
// and tool plugins in an Agent Preset and select it with agentPreset (spawn only)")。
|
|
7
|
+
// mimo 预设此前把委派指令写在 tool-subagent.config.persona 上 ⇒ 整个 preset 挂载失败
|
|
8
|
+
// (与 dsh-kexi-crypto v1.9.21 踩的是同一个坑)。
|
|
9
|
+
// 新契约:角色人格只能是**独立的 Agent Preset**,由委派行经 `agentPreset` 选择。
|
|
10
|
+
//
|
|
11
|
+
// 本预设就是那个成员预设:人格(旧委派指令 verbatim)+ mimo 桥接工具面(子 agent 必须
|
|
12
|
+
// 能调 mimo_run,否则"派活"无从谈起)+ 只读文件面(够做只读查询与最终验证)。
|
|
13
|
+
// 由 preset-declarations.mjs 在**主预设之前**注册 —— 委派行的 validate() 会对每个
|
|
14
|
+
// agentPreset id 调 presets.readDocument(id),未注册即抛 agent-preset/not-found。
|
|
15
|
+
//
|
|
16
|
+
// 它不是独立会话入口:直接选择它只会得到一个只能派活、不能自己改文件的子代理。
|
|
17
|
+
import { bridgeRow } from '../standard-base.mjs'
|
|
18
|
+
|
|
19
|
+
/** Preset identity —— 旧会话头不可引用它(成员预设是本次新增),但委派行按此 id 选择。 */
|
|
20
|
+
export const meta = {
|
|
21
|
+
id: 'cordis-mimo-member',
|
|
22
|
+
name: 'MiMo 子代理(内部预设·勿直接选择)',
|
|
23
|
+
description: 'MiMo-first 会话里被委派的子 agent 所用成员预设:只挂 mimo 桥接工具与只读文件面,人格要求把编码工作派给 mimo_run。仅供 cordis-mimo 的委派行经 agentPreset 选择,不是独立会话入口;直接选择它只会得到一个只能派活、不能自己改文件的子代理。',
|
|
24
|
+
order: 501
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** 旧 agent.cordis.yml 的 spawn/fork 委派指令文案 verbatim(0.2.1 起只能放进 persona)。 */
|
|
28
|
+
export const MIMO_DELEGATION_PERSONA = 'Delegation directive: you are a child agent in a MiMo-first session. Before doing any coding, building, debugging, or multi-file investigation work yourself, check whether the mimo_run tool (or the MCP form mcp__mimo__mimo_run) is available to you; if it is, dispatch that work to mimo first per the MiMo-first policy, then verify its output with your own read-only tools. Reserve your own direct work for quick read-only lookups and final verification.'
|
|
29
|
+
|
|
30
|
+
export function buildPlugins(deps) {
|
|
31
|
+
return [
|
|
32
|
+
// 人格:委派指令。prefix 必填;suffix 不设(DSH 只注册 provider/model 两个提示词变量,
|
|
33
|
+
// 工作目录由 working-directory 服务以不插值的用户上下文提供)。
|
|
34
|
+
{ id: 'persona', name: '@deepseek-ai/dsh-persona', config: {
|
|
35
|
+
prefix: MIMO_DELEGATION_PERSONA,
|
|
36
|
+
includeRuntimeContext: true,
|
|
37
|
+
} },
|
|
38
|
+
// 只读文件面:旧 toolFilter 白名单的新表达 —— 写/改工具直接不存在,比黑名单更严格
|
|
39
|
+
// (成员纪律:改文件一律经 mimo_run)。
|
|
40
|
+
{ id: 'tool-fs', name: '@deepseek-ai/dsh-tool-fs', config: {
|
|
41
|
+
read: true, readImage: true, write: false, edit: false,
|
|
42
|
+
} },
|
|
43
|
+
{ id: 'tool-fs-search', name: '@deepseek-ai/dsh-tool-fs-search', config: {
|
|
44
|
+
sampleOverCapGlobResults: false,
|
|
45
|
+
} },
|
|
46
|
+
// 桥接工具面:子 agent 必须能调 mimo_run/mimo_continue/ mimo_status。
|
|
47
|
+
bridgeRow('mimo', deps && deps.bridgeName),
|
|
48
|
+
]
|
|
49
|
+
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
- id: persona
|
|
5
5
|
name: '@deepseek-ai/dsh-persona'
|
|
6
6
|
config:
|
|
7
|
-
suffix: 'Your working directory is {{cwd}}.'
|
|
8
7
|
prefix: 'You are a coding agent powered by the {{model}} model.'
|
|
9
8
|
- id: agent-instructions
|
|
10
9
|
name: '@deepseek-ai/dsh-agent-instructions'
|
|
@@ -86,20 +85,17 @@
|
|
|
86
85
|
provider: spawn
|
|
87
86
|
toolName: subagent
|
|
88
87
|
modelSelectionSettings: true
|
|
89
|
-
backgroundMode: continuable
|
|
90
88
|
- id: tool-subagent-fork
|
|
91
89
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
92
90
|
config:
|
|
93
91
|
provider: fork
|
|
94
92
|
toolName: subagent_fork
|
|
95
|
-
backgroundMode: continuable
|
|
96
93
|
- id: tool-subagent-codex
|
|
97
94
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
98
95
|
disabled: true
|
|
99
96
|
config:
|
|
100
97
|
provider: codex
|
|
101
98
|
toolName: subagent_codex
|
|
102
|
-
backgroundMode: one-shot
|
|
103
99
|
maxDepth: provider-managed
|
|
104
100
|
- id: tool-subagent-claude-code
|
|
105
101
|
name: '@deepseek-ai/dsh-tool-subagent'
|
|
@@ -107,7 +103,6 @@
|
|
|
107
103
|
config:
|
|
108
104
|
provider: claude-code
|
|
109
105
|
toolName: subagent_claude_code
|
|
110
|
-
backgroundMode: one-shot
|
|
111
106
|
maxDepth: provider-managed
|
|
112
107
|
- id: workflow-ptc
|
|
113
108
|
name: '@deepseek-ai/dsh-workflow-ptc'
|
|
@@ -15,11 +15,13 @@ export const meta = {
|
|
|
15
15
|
|
|
16
16
|
export function buildPlugins(deps) {
|
|
17
17
|
const rows = standardPluginRows()
|
|
18
|
-
// persona
|
|
18
|
+
// persona 段:prefix 与三家旧 preset 同构(dsh-persona 要求 prefix 必填)。
|
|
19
|
+
// 2026-10-18:不再设置 suffix —— DSH 只注册 provider/model 两个变量,工作目录由
|
|
20
|
+
// working-directory 服务以不插值的用户上下文提供,{{cwd}} 会让本预设整轮组装失败。
|
|
19
21
|
const persona = rows.find((r) => r.id === 'persona')
|
|
20
22
|
if (persona && persona.config) {
|
|
21
23
|
persona.config.prefix = 'You are a coding agent powered by the {{model}} model.'
|
|
22
|
-
persona.config.suffix
|
|
24
|
+
delete persona.config.suffix
|
|
23
25
|
}
|
|
24
26
|
rows.push(bridgeRow('opencode', deps && deps.bridgeName))
|
|
25
27
|
return rows
|
package/preset/standard-base.mjs
CHANGED
|
@@ -26,13 +26,16 @@ export const PLAN_MODE_SECTION = [
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* 官方 standard preset 的插件行表(不含 persona 差异与桥接行)。
|
|
29
|
-
* persona 行返回【副本】供 provider 修改 prefix
|
|
29
|
+
* persona 行返回【副本】供 provider 修改 prefix;其余行按原样返回。
|
|
30
30
|
* @returns {object[]}
|
|
31
31
|
*/
|
|
32
32
|
export function standardPluginRows() {
|
|
33
33
|
return [
|
|
34
|
+
// persona 只留 prefix。DSH 的提示词循环只注册 provider/model 两个变量
|
|
35
|
+
// (dsh-agent-loop),工作目录由 working-directory 服务以「不执行插值的用户
|
|
36
|
+
// 上下文」提供。写 {{cwd}} 会在组装期抛 unknown prompt variable,导致整个
|
|
37
|
+
// 预设不可用(2026-10-18 实测)。官方 presets 全部不带 suffix。
|
|
34
38
|
{ id: 'persona', name: '@deepseek-ai/dsh-persona', config: {
|
|
35
|
-
suffix: 'Your working directory is {{cwd}}.',
|
|
36
39
|
prefix: 'You are a coding agent powered by the {{model}} model.',
|
|
37
40
|
} },
|
|
38
41
|
{ id: 'agent-instructions', name: '@deepseek-ai/dsh-agent-instructions', config: { maxBytes: 65536 } },
|
|
@@ -66,20 +69,29 @@ export function standardPluginRows() {
|
|
|
66
69
|
{
|
|
67
70
|
id: 'delegation', name: 'cordis:group', group: true,
|
|
68
71
|
isolate: { workflowEngine: true },
|
|
72
|
+
// 2026-10-18:移除 backgroundMode —— dsh-tool-subagent 0.2.1(当前 0.2.1-alpha.5)
|
|
73
|
+
// 已删除该字段。机制经实装包双路径实测更正:未知/已删键会**通过 schema 校验并被
|
|
74
|
+
// 原样保留**(`Config['~standard'].validate({provider,backgroundMode})` 无 issues,
|
|
75
|
+
// 值幸存;schemastery 根本没有 strict 开关),只是**无人读取**该键
|
|
76
|
+
// (全 DSH 树对 backgroundMode 0 命中)⇒ 属「静默**忽略**」,不是「静默丢弃」。
|
|
77
|
+
// 危害:表面声明 continuable/one-shot 却毫无效果,且**运行时不报错**,
|
|
78
|
+
// 只能靠静态闸门(tests/keystone/persona-prompt-vars.test.mjs)拦。
|
|
79
|
+
// 当前 schema 接受:provider / toolName / modelSelectionSettings /
|
|
80
|
+
// agentOptions / agentPreset / allowedAgentPresets / maxDepth。
|
|
69
81
|
config: [
|
|
70
82
|
{ id: 'tool-subagent-control', name: '@deepseek-ai/dsh-tool-subagent-control' },
|
|
71
83
|
{ id: 'tool-subagent-list-agents', name: '@deepseek-ai/dsh-tool-subagent-control/list-agents' },
|
|
72
84
|
{ id: 'tool-subagent', name: '@deepseek-ai/dsh-tool-subagent', config: {
|
|
73
|
-
provider: 'spawn', toolName: 'subagent', modelSelectionSettings: true,
|
|
85
|
+
provider: 'spawn', toolName: 'subagent', modelSelectionSettings: true,
|
|
74
86
|
} },
|
|
75
87
|
{ id: 'tool-subagent-fork', name: '@deepseek-ai/dsh-tool-subagent', config: {
|
|
76
|
-
provider: 'fork', toolName: 'subagent_fork',
|
|
88
|
+
provider: 'fork', toolName: 'subagent_fork',
|
|
77
89
|
} },
|
|
78
90
|
{ id: 'tool-subagent-codex', name: '@deepseek-ai/dsh-tool-subagent', disabled: true, config: {
|
|
79
|
-
provider: 'codex', toolName: 'subagent_codex',
|
|
91
|
+
provider: 'codex', toolName: 'subagent_codex', maxDepth: 'provider-managed',
|
|
80
92
|
} },
|
|
81
93
|
{ id: 'tool-subagent-claude-code', name: '@deepseek-ai/dsh-tool-subagent', disabled: true, config: {
|
|
82
|
-
provider: 'claude-code', toolName: 'subagent_claude_code',
|
|
94
|
+
provider: 'claude-code', toolName: 'subagent_claude_code', maxDepth: 'provider-managed',
|
|
83
95
|
} },
|
|
84
96
|
{ id: 'workflow-ptc', name: '@deepseek-ai/dsh-workflow-ptc', config: { provider: 'spawn' } },
|
|
85
97
|
{ id: 'tool-workflow', name: '@deepseek-ai/dsh-tool-workflow' },
|
|
@@ -339,6 +339,38 @@ export const BACKEND_ENUM = ['codebuddy', 'codebuddy-intl', 'codebuddy-ioa', 'co
|
|
|
339
339
|
return { ok: false, ids: [], mode: 'cli-help', error: lastErr || 'codebuddy CLI not found (set CODEBUDDY_BIN)' }
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
+
/**
|
|
343
|
+
* 同步版的账号探测(供设置面板用 —— 面板必须同步返回)。
|
|
344
|
+
* 走 spawnSync + 超时;结果进 5 分钟缓存,避免每次渲染都打一次网络。
|
|
345
|
+
*
|
|
346
|
+
* ⚠️ 为什么面板不能用 `--help` 名册顶替:实测本机 CLI 2.167.0 的 help 文本**本身
|
|
347
|
+
* 就是过时的** —— 它列 18 项且含已不存在的 `minimax-m3` / `kimi-k3-1`,缺真实的
|
|
348
|
+
* `glm-5.3-flashx` / `minimax-m3-pay` / `kimi-k3-2`;而账号探测给出 19 项且全部有效。
|
|
349
|
+
* 也就是说「CLI 声明」≠「服务端实际可用」,拿它当兜底会直接把错误清单展示给用户。
|
|
350
|
+
* 故这里宁可空列表 + 明确提示,也不展示已知错误的 roster。
|
|
351
|
+
* @returns {{ok:boolean, ids:string[], mode:string, error?:string}}
|
|
352
|
+
*/
|
|
353
|
+
export function probeAccountModelsSync(env, opts) {
|
|
354
|
+
const o = opts || {}
|
|
355
|
+
const cands = cbCatalogCliCandidates(env)
|
|
356
|
+
const extraEnv = o.envExtra || {}
|
|
357
|
+
const reasons = []
|
|
358
|
+
const timeout = Math.max(3000, Math.min(o.timeoutMs || 12000, 30000))
|
|
359
|
+
for (const exe of cands) {
|
|
360
|
+
const r = cliSpawnSync(exe, ['-p', 'hi', '--model', '__clb_probe_invalid__', '--output-format', 'text'], {
|
|
361
|
+
timeout,
|
|
362
|
+
env: Object.assign({}, (globalThis.process && globalThis.process.env) || {}, extraEnv)
|
|
363
|
+
})
|
|
364
|
+
if (!r || r.error) { reasons.push(exe + ': ' + String((r && r.error && (r.error.code || r.error.message)) || 'spawn failed')); continue }
|
|
365
|
+
const out = String(r.stdout || '') + String(r.stderr || '')
|
|
366
|
+
const ids = parseAccountModels(out)
|
|
367
|
+
if (ids && ids.length) return { ok: true, ids, mode: 'account-live', exe }
|
|
368
|
+
const head = String(out).replace(/\s+/g, ' ').trim().slice(0, 140)
|
|
369
|
+
reasons.push(exe + ': exit ' + r.status + ', no account roster' + (head ? ' — ' + head : ''))
|
|
370
|
+
}
|
|
371
|
+
return { ok: false, ids: [], mode: 'account-live', error: reasons.join('; ') || 'no CLI candidate to probe' }
|
|
372
|
+
}
|
|
373
|
+
|
|
342
374
|
/**
|
|
343
375
|
* 异步探测「该账号当前支持」的清单:用无效模型触发 CLI 的 400 报文。
|
|
344
376
|
* 对齐 workbuddy-auth 的权威白名单语义(服务器告诉我们这个账号能用什么)。
|
|
@@ -565,41 +597,3 @@ export const CREDENTIAL_KEYS = ['WORKBUDDY_TOKEN', 'WORKBUDDY_AI_TOKEN', 'CODEBU
|
|
|
565
597
|
return { token: null, source: null }
|
|
566
598
|
}
|
|
567
599
|
|
|
568
|
-
// ── 三工具 schema(旧 preset/codebuddy-first verbatim;契约 §8 红线)────────────
|
|
569
|
-
// 纯数据,无依赖 —— 放这里是为了让主描述符留在 600 行红线内(规则 §26)。
|
|
570
|
-
export const RUN_PARAMS = {
|
|
571
|
-
type: 'object',
|
|
572
|
-
additionalProperties: false,
|
|
573
|
-
required: ['prompt'],
|
|
574
|
-
properties: {
|
|
575
|
-
prompt: { type: 'string', description: 'The full task/instruction for codebuddy. Be complete and self-contained.' },
|
|
576
|
-
backend: { type: 'string', enum: BACKEND_ENUM, description: 'Which CLI face to dispatch to. codebuddy (default; domestic CodeBuddy npm CLI, product endpoint www.codebuddy.ai) for coding work; codebuddy-intl = CodeBuddy INTERNATIONAL face of the same npm CLI (product.ioa.json catalogue: claude-sonnet-5 / claude-opus-5 / gemini-3.1-pro / gpt-6-astra / hy3-ioa ...; aliases codebuddy-ioa / codebuddy-international) when the account is an international CodeBuddy account; codebuddy-en = WorkBuddy international edition (the WorkBuddyAI desktop bundled CLI at C:\\Program Files\\WorkBuddyAI, product endpoint www.workbuddy.ai; needs codebuddyEnToken unless DSH already holds a workbuddy key) — aliases workbuddy-en / workbuddy-ai also accepted; workbuddy = WorkBuddy domestic desktop CLI (product endpoint copilot.tencent.com, zero config), the office-scenario face: documents/slides/spreadsheets, knowledge-base lookups, image/video generation, WeChat/WeCom replies. New calls without a backend follow the user-preferred default backend (plugin settings). Continuing a session routes back to its owning backend automatically.' },
|
|
577
|
-
mode: { type: 'string', enum: ['auto', 'plan', 'accept-edits'], description: 'auto follows DSH plan state; plan = no writes; accept-edits = allow edits. Default auto.' },
|
|
578
|
-
model: { type: 'string', description: MODEL_DESCRIPTION },
|
|
579
|
-
effort: { type: 'string', enum: ['minimal', 'low', 'medium', 'high', 'xhigh', 'max'], description: 'Optional reasoning effort.' },
|
|
580
|
-
maxTurns: { type: 'integer', description: 'Optional max agentic turns (1-500, default unlimited).' },
|
|
581
|
-
cwd: { type: 'string', description: 'Working directory for codebuddy. Defaults to the DSH workspace root.' },
|
|
582
|
-
addDirs: { type: 'array', items: { type: 'string' }, description: 'Extra directories to add to codebuddy workspace.' },
|
|
583
|
-
timeoutSec: { type: 'integer', description: 'Run timeout seconds (10-3600, default 300); a DSH-side hang guard force-terminates at timeout+60s.' },
|
|
584
|
-
background: { type: 'boolean', description: 'Run as a background job and return a jobId immediately.' }
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
export const CONTINUE_PARAMS = {
|
|
588
|
-
type: 'object',
|
|
589
|
-
additionalProperties: false,
|
|
590
|
-
required: ['prompt'],
|
|
591
|
-
properties: {
|
|
592
|
-
prompt: { type: 'string', description: 'Follow-up instruction for the ongoing codebuddy conversation.' },
|
|
593
|
-
sessionId: { type: 'string', description: 'codebuddy session id to resume (from a prior codebuddy_run result).' },
|
|
594
|
-
latest: { type: 'boolean', description: 'Continue the most recent codebuddy conversation instead of a specific id.' },
|
|
595
|
-
backend: { type: 'string', enum: BACKEND_ENUM, description: 'Which CLI face to resume on. codebuddy-en = WorkBuddy international (WorkBuddyAI desktop CLI; aliases workbuddy-en / workbuddy-ai accepted), workbuddy = WorkBuddy domestic desktop CLI. When omitted, the backend that owns the sessionId is used automatically; brand-new conversations follow the user-preferred default backend (plugin settings).' },
|
|
596
|
-
mode: { type: 'string', enum: ['auto', 'plan', 'accept-edits'], description: 'Execution mode; default auto.' },
|
|
597
|
-
model: { type: 'string', description: 'Optional model id (two layers: product face carries it, account licenses it; the credit multiplier of each id comes from the CLI descriptor — see codebuddy_run).' },
|
|
598
|
-
effort: { type: 'string', enum: ['minimal', 'low', 'medium', 'high', 'xhigh', 'max'], description: 'Optional reasoning effort.' },
|
|
599
|
-
maxTurns: { type: 'integer', description: 'Optional max agentic turns.' },
|
|
600
|
-
cwd: { type: 'string', description: "Working directory for codebuddy; when resuming, defaults to the resumed session's project directory." },
|
|
601
|
-
timeoutSec: { type: 'integer', description: 'Run timeout seconds (10-3600, default 300); a DSH-side hang guard force-terminates at timeout+60s.' },
|
|
602
|
-
background: { type: 'boolean', description: 'Run as a background job and return a jobId immediately.' }
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
export const STATUS_PARAMS = { type: 'object', additionalProperties: false, required: [], properties: { cwd: { type: 'string', description: 'Optional: filter the snapshot to a single project (working directory).' } } }
|