@luchenglong/cli-bridge 0.2.4 → 0.2.5
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 +39 -0
- package/docs/HANDOVER.md +201 -51
- package/dynamic/agy.host.js +1 -1
- package/dynamic/codebuddy.host.js +1063 -925
- package/dynamic/codebuddy.host.template.mjs +1 -0
- package/dynamic/mimo.host.js +314 -548
- package/dynamic/mimo.host.template.mjs +43 -30
- package/dynamic/opencode.host.js +32 -22
- package/home-plugin/cli-bridge-indicator/lib/preset-declarations.mjs +11 -14
- package/mcp/cli-bridge-mcp.mjs +1 -1
- package/mcp/providers/codebuddy.mjs +427 -398
- package/mcp/providers/mimo.mjs +37 -68
- package/mcp/providers/opencode.mjs +28 -1
- package/package.json +2 -1
- package/preset/codebuddy-first/cli-bridge.mjs +12 -0
- package/preset/mimo-first/cli-bridge.mjs +32 -50
- package/providers/codebuddy-catalog.mjs +432 -0
- package/providers/codebuddy.mjs +641 -926
- package/providers/mimo.mjs +271 -517
- package/providers/opencode.mjs +31 -21
- package/scripts/build.mjs +23 -5
package/providers/opencode.mjs
CHANGED
|
@@ -1,22 +1,13 @@
|
|
|
1
|
-
// providers/opencode.mjs — opencode provider descriptor(第四家 CLI
|
|
1
|
+
// providers/opencode.mjs — opencode provider descriptor(第四家 CLI,无旧包可迁)。
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// -m, --model provider/model V2 支持 provider/model#variant
|
|
12
|
-
// --session <id> / --continue 会话续接(无 `opencode continue` 子命令)
|
|
13
|
-
// --agent / --title / --file / --thinking / --standalone
|
|
14
|
-
// ⚠️ V2 无 --dir(V1 有)→ cwd 只能靠 spawn 的工作目录
|
|
15
|
-
// ⚠️ V2 无 --variant(V1 有)→ variant 并入 --model 的 # 后缀
|
|
16
|
-
// 退出码:0 成功 / 1 错误 / 130 SIGINT(退出码才是成败判据)
|
|
17
|
-
// 事件 type(源码全集):step_start / text / reasoning / tool_use / step_finish / error
|
|
18
|
-
// ⚠️ 不存在 result/complete/init 事件
|
|
19
|
-
// ⚠️ 文本在 part.text;统计在 step_finish.part(cost/tokens)——两者是不同事件
|
|
3
|
+
// 基线 = 本机实测 OpenCode V2 CLI v2.0.29(桌面版自带 opencode-cli.exe)+ 源码 emit 全集。
|
|
4
|
+
// 完整 CLI 事实表见 docs/HANDOVER.md §13;这里只留写代码时最容易踩的几条:
|
|
5
|
+
// • 非交互 = `opencode run "<prompt>"`,prompt 是【位置参数】(run 子命令无 --prompt;
|
|
6
|
+
// `-p` 是 --password)。`--format json` → NDJSON。`--auto` = 自动批准权限。
|
|
7
|
+
// • ⚠️ V2 无 --dir(cwd 靠 spawn)、无 --variant(并入 --model#variant)。
|
|
8
|
+
// • 退出码才是成败判据:0 成功 / 1 错误 / 130 SIGINT。
|
|
9
|
+
// • ⚠️ 无 result/complete/init 事件;type 全集 = step_start/text/reasoning/tool_use/
|
|
10
|
+
// step_finish/error。文本在 part.text,统计在 step_finish.part —— 两者是不同事件。
|
|
20
11
|
//
|
|
21
12
|
// 红线(PROVIDER-CONTRACT.md §8 + §1):
|
|
22
13
|
// - 本文件会被 build 内联进 dynamic 沙箱(new Function):绝不出现 import.meta 字面量;
|
|
@@ -209,16 +200,35 @@ export default function defineProvider(deps = {}) {
|
|
|
209
200
|
let settingsRef = { binPath: '', defaultModel: '', defaultAgent: '' }
|
|
210
201
|
|
|
211
202
|
/**
|
|
212
|
-
*
|
|
203
|
+
* 取当前生效的偏好设置。三条来源按优先级合并,每次 buildArgv 都重新读 ——
|
|
204
|
+
* 面板改默认模型后无需重启即生效:
|
|
205
|
+
* 1) `host.getSettings('opencode')` —— preset/dynamic 形态(attach 时由宿主注入);
|
|
206
|
+
* 2) `deps.readSettings()` —— MCP 形态(真 Node 进程,每次现读设置文件);
|
|
207
|
+
* 3) `settingsRef` —— attach 时固化的一次性快照 / 缺省值。
|
|
208
|
+
* 三条都拿不到 → 缺省空值(= 不传 --model,交给 opencode 自身配置决定)。
|
|
209
|
+
*
|
|
210
|
+
* 历史坑:MCP 形态不 attach(自建 engine),只认 host.getSettings 会让面板设置的
|
|
211
|
+
* defaultModel 在 MCP 面对 opencode_run 完全失效 —— 只有 args.model 才落地。
|
|
212
|
+
* 三个形态行为不一致是缺陷,故此处统一把 readSettings 纳入(与 mimo 同构)。
|
|
213
213
|
*/
|
|
214
214
|
function currentSettings() {
|
|
215
|
+
const out = Object.assign({}, settingsRef)
|
|
216
|
+
try {
|
|
217
|
+
if (typeof deps.readSettings === 'function') {
|
|
218
|
+
const r = deps.readSettings()
|
|
219
|
+
if (r && typeof r === 'object') {
|
|
220
|
+
const part = ('partition' in r || 'path' in r || 'home' in r) ? r.partition : r
|
|
221
|
+
if (part && typeof part === 'object') Object.assign(out, part)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
} catch (e) { }
|
|
215
225
|
try {
|
|
216
226
|
if (host && typeof host.getSettings === 'function') {
|
|
217
227
|
const s = host.getSettings('opencode')
|
|
218
|
-
if (s && typeof s === 'object')
|
|
228
|
+
if (s && typeof s === 'object') Object.assign(out, s)
|
|
219
229
|
}
|
|
220
230
|
} catch (e) { }
|
|
221
|
-
return
|
|
231
|
+
return out
|
|
222
232
|
}
|
|
223
233
|
|
|
224
234
|
const descriptor = {
|
package/scripts/build.mjs
CHANGED
|
@@ -50,14 +50,22 @@ function emit(rel, content) {
|
|
|
50
50
|
|
|
51
51
|
// ── 1. dynamic host(文本内联,沙箱禁 import)──────────────────────────────────
|
|
52
52
|
function stripModuleSyntax(src, label) {
|
|
53
|
-
|
|
53
|
+
// 多行 import(`import {\n a, b\n} from '...'`)在单行过滤下会残留 `import ` 前缀并
|
|
54
|
+
// 触发下面的守卫误报 —— 先把跨行 import 折叠成一行再过滤(与单行同规则)。
|
|
55
|
+
const collapsed = src.replace(
|
|
56
|
+
/^\s*import\s*\{[^}]*\}\s*from\s*['"][^'"]+['"];?\s*$/gms,
|
|
57
|
+
(m) => '// ' + m.replace(/\s+/g, ' ').trim()
|
|
58
|
+
)
|
|
59
|
+
const out = collapsed
|
|
54
60
|
.split('\n')
|
|
55
61
|
.filter((l) => !/^\s*import\s[^(]*from\s*['"][^'"]+['"];?\s*$/.test(l) && !/^\s*import\s*['"]/.test(l))
|
|
56
62
|
.join('\n')
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.replace(/^
|
|
60
|
-
.replace(/^export\s
|
|
63
|
+
// 缩进形态也要剥:`export function f()` 可能带前导空格(从 descriptor 闭包里
|
|
64
|
+
// 搬出来的函数保留原缩进),只匹配行首会漏掉 → 残留 export 在脚本体里直接语法错。
|
|
65
|
+
.replace(/^(\s*)export\s+(const|let|var|function|async function|class)\s/gm, '$1$2 ')
|
|
66
|
+
.replace(/^(\s*)export\s+default\s+(async\s+)?function\s+([A-Za-z0-9_$]+)\s*/gm, '$1$2function $3 ')
|
|
67
|
+
.replace(/^(\s*)export\s+default\s+(async\s+)?function\s*\(/gm, '$1$2function __default__(')
|
|
68
|
+
.replace(/^(\s*)export\s*\{[^}]*\};?\s*$/gm, '')
|
|
61
69
|
// 内联目标是「脚本体」:残留的 export default/import 说明源用了本转换器不支持
|
|
62
70
|
// 的形态。静默产出坏代码会让 dynamic host 在沙箱里炸得莫名其妙,必须大声失败。
|
|
63
71
|
if (/^\s*(export\s+default|import\s|import\()/m.test(out)) {
|
|
@@ -77,10 +85,20 @@ function buildDynamicHost(id) {
|
|
|
77
85
|
// 模板没有 /*__SCHED__*/ 占位(旧模板)→ 不注入,保持向后兼容。
|
|
78
86
|
const sched = stripModuleSyntax(read('core/scheduling.mjs'), 'core/scheduling.mjs')
|
|
79
87
|
+ '\nconst SCHED_ALL_IDS = ' + JSON.stringify(ids) + '\n'
|
|
88
|
+
// 可选的第二段内联:providers/<id>-catalog.mjs。存在且模板声明了占位符才注入 ——
|
|
89
|
+
// 语义与 __SCHED__ 完全同构(模板没有该占位符 → 不注入,向后兼容)。
|
|
90
|
+
// 目的:providers/<id>.mjs 超 600 行红线时把纯逻辑拆出去,沙箱里仍是单脚本。
|
|
91
|
+
const extraRel = 'providers/' + id + '-catalog.mjs'
|
|
92
|
+
const extra = existsSync(join(ROOT, extraRel)) ? stripModuleSyntax(read(extraRel), extraRel) : null
|
|
80
93
|
if (!tpl.includes('/*__KIT__*/') || !tpl.includes('/*__PROVIDER__*/')) {
|
|
81
94
|
throw new Error(tplRel + ' missing /*__KIT__*/ or /*__PROVIDER__*/ placeholder')
|
|
82
95
|
}
|
|
83
96
|
let out = tpl.replace('/*__KIT__*/', () => kit).replace('/*__PROVIDER__*/', () => prov)
|
|
97
|
+
// __EXTRA__ 放在 KIT/PROVIDER 之后替换:避免其内容里若含同名占位符被二次展开。
|
|
98
|
+
if (out.includes('/*__EXTRA__*/')) {
|
|
99
|
+
if (!extra) throw new Error(tplRel + ': __EXTRA__ placeholder present but ' + extraRel + ' missing')
|
|
100
|
+
out = out.replace('/*__EXTRA__*/', () => extra)
|
|
101
|
+
} else if (tpl.includes('/*__EXTRA__*/')) throw new Error(tplRel + ': __EXTRA__ placeholder vanished after other replacements')
|
|
84
102
|
if (out.includes('/*__SCHED__*/')) out = out.replace('/*__SCHED__*/', () => sched)
|
|
85
103
|
else if (tpl.includes('/*__SCHED__*/')) throw new Error(tplRel + ': __SCHED__ placeholder vanished after other replacements')
|
|
86
104
|
return out
|