@luchenglong/cli-bridge 0.0.0-stage → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/LICENSE +21 -0
  3. package/MCP-POLICY.md +53 -0
  4. package/PROVIDER-CONTRACT.md +235 -0
  5. package/README.en.md +98 -0
  6. package/README.md +150 -2
  7. package/assets/indicator-states.svg +62 -0
  8. package/bin/agy-quota.mjs +223 -0
  9. package/core/bridge-kit.mjs +549 -0
  10. package/core/scheduling.mjs +149 -0
  11. package/docs/ARCHITECTURE.md +117 -0
  12. package/docs/FALLBACK-AND-INDICATOR.md +93 -0
  13. package/docs/INSTALL.md +118 -0
  14. package/docs/MCP-POLICY.zh.md +49 -0
  15. package/docs/MIGRATION.md +43 -0
  16. package/docs/RELEASE-SOP.md +77 -0
  17. package/docs/history/agy/CHANGELOG.md +326 -0
  18. package/docs/history/codebuddy/CHANGELOG.md +668 -0
  19. package/docs/history/mimo/CHANGELOG.md +346 -0
  20. package/dynamic/agy.host.js +1237 -0
  21. package/dynamic/agy.host.template.mjs +140 -0
  22. package/dynamic/codebuddy.host.js +1787 -0
  23. package/dynamic/codebuddy.host.template.mjs +162 -0
  24. package/dynamic/mimo.host.js +1732 -0
  25. package/dynamic/mimo.host.template.mjs +169 -0
  26. package/home-plugin/cli-bridge-indicator/cordis.patch.yml +31 -0
  27. package/home-plugin/cli-bridge-indicator/lib/client.js +606 -0
  28. package/home-plugin/cli-bridge-indicator/lib/index.mjs +420 -0
  29. package/home-plugin/cli-bridge-indicator/lib/preset-declarations.mjs +137 -0
  30. package/home-plugin/cli-bridge-indicator/lib/settings.mjs +300 -0
  31. package/mcp/agy-mcp-server.mjs +6 -0
  32. package/mcp/cli-bridge-mcp.mjs +184 -0
  33. package/mcp/codebuddy-mcp-server.mjs +6 -0
  34. package/mcp/mimo-mcp-server.mjs +6 -0
  35. package/mcp/providers/agy.mjs +254 -0
  36. package/mcp/providers/codebuddy.mjs +397 -0
  37. package/mcp/providers/mimo.mjs +290 -0
  38. package/package.json +87 -4
  39. package/preset/agy-first/agent.cordis.yml +141 -0
  40. package/preset/agy-first/cli-bridge.mjs +169 -0
  41. package/preset/agy-first/plugin-list.mjs +26 -0
  42. package/preset/agy-first/preset.yml +3 -0
  43. package/preset/codebuddy-first/agent.cordis.yml +141 -0
  44. package/preset/codebuddy-first/cli-bridge.mjs +188 -0
  45. package/preset/codebuddy-first/plugin-list.mjs +20 -0
  46. package/preset/codebuddy-first/preset.yml +3 -0
  47. package/preset/mimo-first/agent.cordis.yml +143 -0
  48. package/preset/mimo-first/cli-bridge.mjs +236 -0
  49. package/preset/mimo-first/plugin-list.mjs +39 -0
  50. package/preset/mimo-first/preset.yml +3 -0
  51. package/preset/standard-base.mjs +102 -0
  52. package/providers/agy.mjs +398 -0
  53. package/providers/codebuddy.mjs +926 -0
  54. package/providers/mimo.mjs +864 -0
  55. package/providers/registry.mjs +34 -0
  56. package/scripts/build.mjs +235 -0
  57. package/scripts/deploy.mjs +61 -0
  58. package/scripts/verify.mjs +148 -0
@@ -0,0 +1,290 @@
1
+ // mcp/providers/mimo.mjs — mimo MCP 工具面(契约 §4;移植自旧 mimo-mcp-server.mjs 的
2
+ // runMimo/runDesktop/handleTool/TOOLS/renderResultText,framing/生命周期归 keystone
3
+ // 统一服务器 mcp/cli-bridge-mcp.mjs)。
4
+ //
5
+ // 旧语义保持:
6
+ // - mimocode:直接 spawn mimo CLI(MIMO_BIN/MIMO_CLI > ~/.mimocode/bin/mimo[.exe] >
7
+ // 'mimo';.mjs/.cjs/.js 目标经 process.execPath 包装,供测试 fixture 使用)。
8
+ // 实时折叠走 bridge-kit 行流 + engine.foldEvent(旧 foldStep 语义)。
9
+ // - mimo-desktop:委托 provider.execute(provider.delegates('mimo-desktop')=true);
10
+ // 非 spawn 走本地 HTTP。begin/end 由本模块做(MCP 无 kit runner)。
11
+ // - cwd 兜底 = env MIMO_MCP_CWD || MIMO_BRIDGE_CWD || process.cwd()(旧 CWD_FALLBACK;
12
+ // 旧仓曾硬编码机器绝对路径,新实现按 agy 定案改 process.cwd() 兜底)。
13
+ // - 无 ctx.emit:状态走快照文件 {homeDir}/cli-bridge-mcp-mimo.json(keystone
14
+ // indicator readMcpFile 只认 'cli-bridge-mcp-<id>.json' 模式,Lead 复核纠错定案)
15
+ // (bridge-kit buildMcpBridgePayload + 原子写 tmp→rename;写失败静默,红线:绝不影响
16
+ // 工具结果)。旧 mcp-live.json 兼容读归 keystone,本面不写旧文件。
17
+ // - 限流(isLimited)触发即落 fallbackResult(旧 handleTool verbatim:run 内部各退出
18
+ // 路径均已 engine.end,此处仅改返回值对象,绝不二次 engine.end —— 防 runs 虚标/计数下溢)。
19
+
20
+ import { spawn as nodeSpawn } from 'node:child_process'
21
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs'
22
+ import { dirname, join as joinPath, resolve as resolvePath } from 'node:path'
23
+
24
+ import defineProvider from '../../providers/mimo.mjs'
25
+ import {
26
+ createStatusEngine, createLineStream, buildMcpBridgePayload,
27
+ fallbackResult, shortLabel, renderStatus
28
+ } from '../../core/bridge-kit.mjs'
29
+
30
+ export const meta = { id: 'mimo', label: 'MIMO', version: '0.2.2' }
31
+
32
+ const BACKEND_DESKTOP = 'mimo-desktop'
33
+ const SETTINGS_FILE_NAME = 'cli-bridge-settings.json'
34
+
35
+ // 统一设置文件分区读(与 preset 同规则;MCP 子进程无 ctx.get,只读 env/文件)。
36
+ function resolveSettingsFile(env) {
37
+ try {
38
+ if (env.CLI_BRIDGE_SETTINGS_FILE) return env.CLI_BRIDGE_SETTINGS_FILE
39
+ if (env.DSH_HOME) return joinPath(env.DSH_HOME, SETTINGS_FILE_NAME)
40
+ if (process.platform === 'win32' && env.APPDATA) return joinPath(env.APPDATA, 'DSH Desktop', 'dsh-home', SETTINGS_FILE_NAME)
41
+ if (env.HOME) return joinPath(env.HOME, '.dsh', SETTINGS_FILE_NAME)
42
+ } catch (e) { }
43
+ return null
44
+ }
45
+ function readPartition(env) {
46
+ const p = resolveSettingsFile(env)
47
+ if (!p) return { partition: null, path: null, home: null }
48
+ try {
49
+ const all = JSON.parse(readFileSync(p, 'utf8'))
50
+ return { partition: (all && typeof all === 'object' && all.mimo) ? all.mimo : null, path: p, home: dirname(p) }
51
+ } catch (e) {
52
+ return { partition: null, path: p, home: dirname(p) }
53
+ }
54
+ }
55
+
56
+ const provider = defineProvider({
57
+ env: process.env,
58
+ process,
59
+ nodeFs: { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync },
60
+ nodeChild: { spawn: nodeSpawn },
61
+ nodePath: { join: joinPath, dirname },
62
+ readSettings: () => readPartition(process.env)
63
+ })
64
+
65
+ let lastIo = null
66
+ function publishSnapshot(snapshot) {
67
+ const io = lastIo
68
+ if (!io) return
69
+ try {
70
+ // 文件名必须 'cli-bridge-mcp-<id>.json':keystone indicator 的 readMcpFile 按此模式
71
+ // 枚举(agy 面同款);写成别的名字 MCP 形态活动永远进不了状态灯(Lead 复核纠错)。
72
+ const target = io.path.join(io.homeDir, 'cli-bridge-mcp-mimo.json')
73
+ const payload = buildMcpBridgePayload(snapshot, process.pid, Date.now())
74
+ const tmp = target + '.' + process.pid + '.tmp'
75
+ try { io.fs.mkdirSync(io.path.dirname(target), { recursive: true }) } catch (e) { }
76
+ io.fs.writeFileSync(tmp, JSON.stringify(payload), 'utf8')
77
+ io.fs.renameSync(tmp, target)
78
+ } catch (e) { /* 灯数据尽力而为,绝不影响工具调用 */ }
79
+ }
80
+ // MCP 形态不 attach(无 ctx.subprocess),用本模块自持 engine。
81
+ const engine = createStatusEngine({ provider, publish: publishSnapshot })
82
+ provider.engine = engine
83
+
84
+ // ── exe / cwd 解析(旧 resolveMimoExe + CWD_FALLBACK verbatim 语义)──────────────
85
+ function exePrefix() {
86
+ const env = process.env
87
+ const candidates = []
88
+ if (env.MIMO_BIN) candidates.push(env.MIMO_BIN)
89
+ if (env.MIMO_CLI) candidates.push(env.MIMO_CLI)
90
+ if (env.USERPROFILE) candidates.push(env.USERPROFILE + '\\.mimocode\\bin\\mimo.exe')
91
+ if (env.HOME) {
92
+ candidates.push(env.HOME + '\\.mimocode\\bin\\mimo.exe')
93
+ candidates.push(env.HOME + '/.mimocode/bin/mimo')
94
+ }
95
+ for (const exe of candidates) {
96
+ try { if (exe && existsSync(exe)) return /\.(mjs|cjs|js)$/i.test(exe) ? [process.execPath, exe] : [exe] } catch (e) { }
97
+ }
98
+ const bin = env.MIMO_BIN || env.MIMO_CLI || ''
99
+ if (bin) return /\.(mjs|cjs|js)$/i.test(bin) ? [process.execPath, bin] : [bin]
100
+ return ['mimo']
101
+ }
102
+ function resolveCwd(a) {
103
+ if (a && a.cwd) return resolvePath(String(a.cwd))
104
+ return process.env.MIMO_MCP_CWD || process.env.MIMO_BRIDGE_CWD || process.cwd()
105
+ }
106
+ function preferredBackendFromEnv() {
107
+ const env = process.env
108
+ return env.MIMO_BRIDGE_BACKEND || env.MIMO_BACKEND || (readPartition(env).partition || {}).preferredBackend || null
109
+ }
110
+
111
+ // ── spawn(旧 runMimo verbatim 语义;实时折叠走 bridge-kit 行流)────────────────
112
+ function runMimo(args) {
113
+ return new Promise((resolve) => {
114
+ const cwd = resolveCwd(args)
115
+ const built = provider.buildArgv(exePrefix(), args, { planActive: false, defaultMode: 'auto', backend: 'mimocode' })
116
+ engine.begin(cwd)
117
+ let child
118
+ try {
119
+ child = nodeSpawn(built.argv[0], built.argv.slice(1), { cwd, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true })
120
+ } catch (e) {
121
+ const res = { ok: false, status: 'MIMO_UNAVAILABLE', response: '', sessionId: null, exitCode: null, mode: built.mode, backend: 'mimocode', stderr: 'mimo spawn failed: ' + String(e && e.message || e), errorMessage: String(e && e.message || e) }
122
+ engine.end(res, cwd)
123
+ resolve(res)
124
+ return
125
+ }
126
+ let out = ''
127
+ let err = ''
128
+ let killed = false
129
+ const timer = setTimeout(() => { killed = true; try { child.kill('SIGTERM') } catch (e) { } }, (built.timeoutSec + 60) * 1000)
130
+ const stream = createLineStream((ln) => {
131
+ const t = ln.trim()
132
+ if (!t.startsWith('{')) return
133
+ try { engine.foldEvent(JSON.parse(t), cwd) } catch (e) { }
134
+ })
135
+ child.stdout.on('data', (d) => {
136
+ out += d
137
+ if (out.length > 4000000) out = out.slice(-2000000)
138
+ stream.pushChunk(String(d))
139
+ })
140
+ child.stderr.on('data', (d) => { err += d; if (err.length > 1000000) err = err.slice(-500000) })
141
+ child.on('error', (e) => {
142
+ clearTimeout(timer)
143
+ stream.flush()
144
+ const res = { ok: false, status: 'MIMO_UNAVAILABLE', response: '', sessionId: null, exitCode: null, mode: built.mode, backend: 'mimocode', stderr: String(e && e.message || e), errorMessage: String(e && e.message || e) }
145
+ engine.end(res, cwd)
146
+ resolve(res)
147
+ })
148
+ child.on('close', (code) => {
149
+ clearTimeout(timer)
150
+ stream.flush()
151
+ const outcome = { exitCode: killed ? 124 : (code == null ? -1 : code) }
152
+ let res = provider.buildResult(provider.parseJson(out), outcome, built.mode, err, out, 'mimocode')
153
+ if (killed && !res.ok) {
154
+ res.status = 'HUNG_TIMEOUT'
155
+ res.stderr = (res.stderr ? res.stderr + ' ' : '') + '[killed by DSH timeout guard after ' + built.timeoutSec + 's; if this was a long-running script (build/test) raise timeoutSec]'
156
+ }
157
+ engine.end(res, cwd)
158
+ resolve(res)
159
+ })
160
+ })
161
+ }
162
+
163
+ // ── 文本渲染(旧 renderResultText verbatim;契约 §4:错误也是文本)───────────────
164
+ function textResult(res) {
165
+ if (!res) return '(no result)'
166
+ const b = res.backend ? ' backend=' + res.backend : ''
167
+ if (res.fallback) {
168
+ return 'status=FALLBACK_TO_DSH fallback=true' + b + '\n' + (res.reason ? 'reason=' + res.reason + '\n' : '') +
169
+ 'The user/host chose DSH-local. Finish with native tools and NEVER call mimo again for this task.'
170
+ }
171
+ if (res.ok === false && res.error) return 'mimo_settings/error' + b + ': ' + res.error
172
+ if (!res.ok) {
173
+ const hint = provider.failureHint ? provider.failureHint(res) : ''
174
+ return 'mimo failed status=' + (res.status || 'ERROR') + b + '\n' + shortLabel(res.stderr || res.errorMessage || '') + (hint ? '\n' + hint : '')
175
+ }
176
+ return 'mimo ok status=' + res.status + b + (res.sessionId ? ' sessionId=' + res.sessionId : '') + '\n\n' + String(res.response || '')
177
+ }
178
+
179
+ // ── 工具面(旧 MCP TOOLS verbatim:含 sessionId 关键注释与 mimo_settings)────────
180
+ // 直接复用描述符的 schema/description(三形态单一真源);MCP 面去掉 background 参数
181
+ // (stdio 调用恒为同步阻塞,无宿主 jobs 服务)—— 旧 MCP 的 run/continue 本就无 background。
182
+ function stripBackground(schema) {
183
+ const copy = JSON.parse(JSON.stringify(schema))
184
+ if (copy.properties) delete copy.properties.background
185
+ return copy
186
+ }
187
+
188
+ export function tools(env) {
189
+ const run = { name: provider.tools.run.name, description: provider.tools.run.description, inputSchema: stripBackground(provider.tools.run.inputSchema) }
190
+ const cont = { name: provider.tools.continue.name, description: provider.tools.continue.description, inputSchema: stripBackground(provider.tools.continue.inputSchema) }
191
+ const status = { name: provider.tools.status.name, description: provider.tools.status.description, inputSchema: provider.tools.status.inputSchema }
192
+ const settings = provider.extraTools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema }))[0]
193
+ return [run, cont, status, settings]
194
+ }
195
+
196
+ export async function call(name, args, io) {
197
+ if (io) lastIo = io
198
+ const a = args || {}
199
+ const runtimeBackend = provider.resolveBackend(a, null, preferredBackendFromEnv())
200
+
201
+ if (name === 'mimo_settings') {
202
+ const v = await provider.extraTools[0].logic(a, null)
203
+ return provider.extraTools[0].render(v)[0].text
204
+ }
205
+
206
+ if (name === 'mimo_status') {
207
+ const snap = await provider.statusToolLogic(a)
208
+ snap.defaultBackend = runtimeBackend
209
+ snap.backend = runtimeBackend
210
+ return renderStatus(snap, provider)[0].text
211
+ }
212
+
213
+ if (name === 'mimo_run' || name === 'mimo_continue') {
214
+ if (!a.prompt || !String(a.prompt).trim()) return 'mimo error: prompt is required'
215
+ const mapped = {
216
+ prompt: a.prompt,
217
+ mode: a.mode,
218
+ model: a.model,
219
+ effort: a.effort,
220
+ cwd: a.cwd,
221
+ timeoutSec: a.timeoutSec,
222
+ title: a.title,
223
+ backend: a.backend,
224
+ background: false, // MCP 恒同步阻塞(无宿主 jobs)
225
+ // 【关键】desktop 后端的 sessionId 必须转发。旧 handleTool 此处曾是白名单转发,
226
+ // 漏了 sessionId(只在 mimo_continue 分支补)→ mimo_run 传 sessionId 被静默丢弃
227
+ // → 永远 newDesktopSessionId 造新 id → 因 Desktop API 不能创建会话,mimo_run 在
228
+ // desktop 后端下完全不可用。
229
+ sessionId: a.sessionId
230
+ }
231
+ if (name === 'mimo_continue') {
232
+ if (a.sessionId) mapped.sessionId = a.sessionId
233
+ else mapped.continueLatest = true
234
+ }
235
+ const backend = provider.resolveBackend(mapped, null, preferredBackendFromEnv())
236
+ let res
237
+ if (backend === BACKEND_DESKTOP) {
238
+ const pf = provider.preflight({ backend })
239
+ if (pf && pf.abort) {
240
+ res = pf.abort
241
+ engine.begin(resolveCwd(mapped))
242
+ engine.end(res, resolveCwd(mapped))
243
+ } else {
244
+ const cwd = resolveCwd(mapped)
245
+ const built = provider.buildArgv(exePrefix(), mapped, { planActive: false, defaultMode: 'auto', backend })
246
+ engine.begin(cwd)
247
+ res = await provider.execute({ args: mapped, cwd, built, backend })
248
+ engine.end(res, cwd)
249
+ }
250
+ } else {
251
+ res = await runMimo(mapped)
252
+ }
253
+ if (!res.ok && provider.isLimited(res)) {
254
+ // runMimo / desktop 分支所有退出路径均已 engine.end;此处仅改返回值对象,
255
+ // 绝不二次 engine.end(防 runs 虚标与 running 计数下溢)。
256
+ res = fallbackResult(res, res.mode, provider)
257
+ res.backend = backend
258
+ }
259
+ return textResult(res)
260
+ }
261
+
262
+ return 'mimo error: unknown tool: ' + name
263
+ }
264
+
265
+ // ── 自检(keystone --check 调用;argv 契约防漂移)───────────────────────────────
266
+ export function check(env) {
267
+ const ts = tools(env || process.env)
268
+ const names = ts.map((t) => t.name)
269
+ for (const req of ['mimo_run', 'mimo_continue', 'mimo_status', 'mimo_settings']) {
270
+ if (!names.includes(req)) throw new Error('mimo mcp: missing tool ' + req)
271
+ }
272
+ for (const t of ts) {
273
+ if (!t.name || !t.description || !t.inputSchema || t.inputSchema.type !== 'object') throw new Error('mimo mcp: bad tool def ' + JSON.stringify(t && t.name))
274
+ }
275
+ // MCP 面必须覆盖描述符三件套 + settings(名字一致,提示词连续性红线)。
276
+ for (const k of ['run', 'continue', 'status']) {
277
+ if (!names.includes(provider.tools[k].name)) throw new Error('mimo mcp: tools surface missing descriptor name ' + provider.tools[k].name)
278
+ }
279
+ // mimocode argv 契约(旧 core verbatim)。
280
+ const b = provider.buildArgv(['mimo'], { prompt: 'x' }, { planActive: false, backend: 'mimocode' })
281
+ for (const f of ['run', '--format', 'json', '--dangerously-skip-permissions', '--agent', 'build']) {
282
+ if (!b.argv.includes(f)) throw new Error('mimo mcp: argv contract drift: ' + f)
283
+ }
284
+ // mimo-desktop 空壳(非 spawn 路径,交 execute)。
285
+ const d = provider.buildArgv(['mimo'], { prompt: 'x' }, { planActive: false, backend: BACKEND_DESKTOP })
286
+ if (d.argv.length !== 0) throw new Error('mimo mcp: desktop buildArgv must be empty shell')
287
+ // delegates 规则:只有 desktop 委托。
288
+ if (provider.delegates(BACKEND_DESKTOP) !== true || provider.delegates('mimocode') !== false) throw new Error('mimo mcp: delegates contract drift')
289
+ return true
290
+ }
package/package.json CHANGED
@@ -1,6 +1,89 @@
1
1
  {
2
2
  "name": "@luchenglong/cli-bridge",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.2",
4
+ "description": "CLI Bridge for DeepSeek Harness (DSH): one package bridging three local coding-CLI agents — agy (Google Antigravity CLI), Tencent CodeBuddy Code, and Xiaomi MiMo (MiMoCode / MiMo Desktop). Each provider keeps its own agent preset (cordis-agy / codebuddy-first / cordis-mimo), tools (agy_run / codebuddy_run / mimo_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
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "engines": {
10
+ "node": ">=18",
11
+ "dsh": ">=0.1.1-rc.2 <0.3.0-0"
12
+ },
13
+ "main": "./home-plugin/cli-bridge-indicator/lib/index.mjs",
14
+ "exports": {
15
+ ".": "./home-plugin/cli-bridge-indicator/lib/index.mjs",
16
+ "./client": "./home-plugin/cli-bridge-indicator/lib/client.js",
17
+ "./bridge-kit": "./core/bridge-kit.mjs",
18
+ "./registry": "./providers/registry.mjs",
19
+ "./providers/agy": "./providers/agy.mjs",
20
+ "./providers/codebuddy": "./providers/codebuddy.mjs",
21
+ "./providers/mimo": "./providers/mimo.mjs",
22
+ "./preset-agy": "./preset/agy-first/cli-bridge.mjs",
23
+ "./preset-codebuddy": "./preset/codebuddy-first/cli-bridge.mjs",
24
+ "./preset-mimo": "./preset/mimo-first/cli-bridge.mjs",
25
+ "./package.json": "./package.json"
26
+ },
27
+ "dsh": {
28
+ "client": {
29
+ "platform": "web"
30
+ },
31
+ "bundle": {
32
+ "patch": "./home-plugin/cli-bridge-indicator/cordis.patch.yml"
33
+ }
34
+ },
35
+ "bin": {
36
+ "cli-bridge-mcp": "mcp/cli-bridge-mcp.mjs",
37
+ "agy-mcp-server": "mcp/agy-mcp-server.mjs",
38
+ "codebuddy-mcp-server": "mcp/codebuddy-mcp-server.mjs",
39
+ "mimo-mcp-server": "mcp/mimo-mcp-server.mjs"
40
+ },
41
+ "scripts": {
42
+ "build": "node scripts/build.mjs",
43
+ "test": "node scripts/build.mjs --check && node --test",
44
+ "verify": "node scripts/verify.mjs",
45
+ "check": "node scripts/build.mjs --check && node scripts/verify.mjs && node --test && node mcp/cli-bridge-mcp.mjs --check",
46
+ "prepack": "node scripts/verify.mjs && node scripts/build.mjs --check",
47
+ "deploy:local": "node scripts/deploy.mjs"
48
+ },
49
+ "files": [
50
+ "core/",
51
+ "providers/",
52
+ "preset/",
53
+ "home-plugin/",
54
+ "dynamic/",
55
+ "mcp/",
56
+ "bin/",
57
+ "scripts/",
58
+ "docs/",
59
+ "assets/",
60
+ "locale/",
61
+ "CHANGELOG.md",
62
+ "MCP-POLICY.md",
63
+ "PROVIDER-CONTRACT.md",
64
+ "README.md",
65
+ "README.en.md",
66
+ "LICENSE"
67
+ ],
68
+ "keywords": [
69
+ "dsh",
70
+ "cordis",
71
+ "cli-bridge",
72
+ "agy",
73
+ "codebuddy",
74
+ "mimo",
75
+ "mcp",
76
+ "mcp-server",
77
+ "agent",
78
+ "deepseek-harness"
79
+ ],
80
+ "author": "chenglong",
81
+ "repository": {
82
+ "type": "git",
83
+ "url": "git+https://github.com/new-256/cli-bridge.git"
84
+ },
85
+ "homepage": "https://github.com/new-256/cli-bridge#readme",
86
+ "bugs": {
87
+ "url": "https://github.com/new-256/cli-bridge/issues"
88
+ }
89
+ }
@@ -0,0 +1,141 @@
1
+ # 生成物 — 由 node scripts/build.mjs 从 preset/agy-first/plugin-list.mjs 生成,勿手改。
2
+ # legacy 目录形态($DSH_HOME/.agent-presets/cordis-agy/);新 DSH 走声明制
3
+ # (home-plugin/cli-bridge-indicator/lib/preset-declarations.mjs 直接 import 同一源)。
4
+ - id: persona
5
+ name: '@deepseek-ai/dsh-persona'
6
+ config:
7
+ suffix: 'Your working directory is {{cwd}}.'
8
+ prefix: 'You are a coding agent powered by the {{model}} model.'
9
+ - id: agent-instructions
10
+ name: '@deepseek-ai/dsh-agent-instructions'
11
+ config:
12
+ maxBytes: 65536
13
+ - id: tool-bash
14
+ name: '@deepseek-ai/dsh-tool-bash'
15
+ disabled: !!js 'process.platform === ''win32'''
16
+ - id: tool-pwsh
17
+ name: '@deepseek-ai/dsh-tool-pwsh'
18
+ disabled: !!js 'process.platform !== ''win32'''
19
+ - id: tool-fs
20
+ name: '@deepseek-ai/dsh-tool-fs'
21
+ - id: tool-fs-search
22
+ name: '@deepseek-ai/dsh-tool-fs-search'
23
+ config:
24
+ sampleOverCapGlobResults: false
25
+ - id: tool-jobs
26
+ name: '@deepseek-ai/dsh-tool-jobs'
27
+ - id: skill-filesystem
28
+ name: '@deepseek-ai/dsh-skill-filesystem'
29
+ - id: tool-skill
30
+ name: '@deepseek-ai/dsh-tool-skill'
31
+ - id: command-goal
32
+ name: '@deepseek-ai/dsh-command-goal'
33
+ - id: tool-goal
34
+ name: '@deepseek-ai/dsh-tool-goal'
35
+ - id: planning
36
+ name: 'cordis:group'
37
+ group: true
38
+ isolate:
39
+ planMode: true
40
+ config:
41
+ - id: plan-mode
42
+ name: '@deepseek-ai/dsh-plan-mode'
43
+ config:
44
+ section: |
45
+ You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
46
+
47
+ Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
48
+
49
+ The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
50
+
51
+ Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
52
+
53
+ Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
54
+
55
+ When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
56
+ - id: compaction
57
+ name: 'cordis:group'
58
+ group: true
59
+ isolate:
60
+ compaction: true
61
+ toolResultPruner: true
62
+ config:
63
+ - id: compaction-basic
64
+ name: '@deepseek-ai/dsh-compaction-basic'
65
+ - id: command-compact
66
+ name: '@deepseek-ai/dsh-command-compact'
67
+ - id: tool-result-pruner
68
+ name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
69
+ config:
70
+ thresholdChars: 8192
71
+ headChars: 4096
72
+ tailChars: 1024
73
+ - id: delegation
74
+ name: 'cordis:group'
75
+ group: true
76
+ isolate:
77
+ workflowEngine: true
78
+ config:
79
+ - id: tool-subagent-control
80
+ name: '@deepseek-ai/dsh-tool-subagent-control'
81
+ - id: tool-subagent-list-agents
82
+ name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
83
+ - id: tool-subagent
84
+ name: '@deepseek-ai/dsh-tool-subagent'
85
+ config:
86
+ provider: spawn
87
+ toolName: subagent
88
+ modelSelectionSettings: true
89
+ backgroundMode: continuable
90
+ - id: tool-subagent-fork
91
+ name: '@deepseek-ai/dsh-tool-subagent'
92
+ config:
93
+ provider: fork
94
+ toolName: subagent_fork
95
+ backgroundMode: continuable
96
+ - id: tool-subagent-codex
97
+ name: '@deepseek-ai/dsh-tool-subagent'
98
+ disabled: true
99
+ config:
100
+ provider: codex
101
+ toolName: subagent_codex
102
+ backgroundMode: one-shot
103
+ maxDepth: provider-managed
104
+ - id: tool-subagent-claude-code
105
+ name: '@deepseek-ai/dsh-tool-subagent'
106
+ disabled: true
107
+ config:
108
+ provider: claude-code
109
+ toolName: subagent_claude_code
110
+ backgroundMode: one-shot
111
+ maxDepth: provider-managed
112
+ - id: workflow-ptc
113
+ name: '@deepseek-ai/dsh-workflow-ptc'
114
+ config:
115
+ provider: spawn
116
+ - id: tool-workflow
117
+ name: '@deepseek-ai/dsh-tool-workflow'
118
+ - id: tool-ralph
119
+ name: '@deepseek-ai/dsh-tool-ralph'
120
+ disabled: true
121
+ config:
122
+ subagentProvider: spawn
123
+ maxRounds: 64
124
+ - id: tool-ask-user
125
+ name: '@deepseek-ai/dsh-tool-ask-user'
126
+ - id: tool-todo
127
+ name: '@deepseek-ai/dsh-tool-todo'
128
+ config:
129
+ allowParallelInProgress: true
130
+ - id: tool-web
131
+ name: '@deepseek-ai/dsh-tool-web'
132
+ config:
133
+ fetch: true
134
+ searchTimeoutMs: 60000
135
+ - id: present
136
+ name: '@deepseek-ai/dsh-tool-present'
137
+ - id: tool-plugin-manager
138
+ name: '@deepseek-ai/dsh-plugin-manager/tools'
139
+ disabled: true
140
+ - id: cli-bridge-agy
141
+ name: '@luchenglong/cli-bridge/preset-agy'