@luchenglong/cli-bridge 0.0.0-stage → 0.2.3
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 +191 -0
- package/LICENSE +21 -0
- package/MCP-POLICY.md +53 -0
- package/PROVIDER-CONTRACT.md +235 -0
- package/README.en.md +98 -0
- package/README.md +151 -2
- package/assets/indicator-states.svg +62 -0
- package/bin/agy-quota.mjs +223 -0
- package/core/bridge-kit.mjs +549 -0
- package/core/scheduling.mjs +149 -0
- package/docs/ARCHITECTURE.md +117 -0
- package/docs/FALLBACK-AND-INDICATOR.md +93 -0
- package/docs/HANDOVER.md +226 -0
- package/docs/INSTALL.md +118 -0
- package/docs/MCP-POLICY.zh.md +49 -0
- package/docs/MIGRATION.md +43 -0
- package/docs/RELEASE-SOP.md +80 -0
- package/docs/history/agy/CHANGELOG.md +326 -0
- package/docs/history/codebuddy/CHANGELOG.md +668 -0
- package/docs/history/mimo/CHANGELOG.md +346 -0
- package/dynamic/agy.host.js +1237 -0
- package/dynamic/agy.host.template.mjs +140 -0
- package/dynamic/codebuddy.host.js +1787 -0
- package/dynamic/codebuddy.host.template.mjs +162 -0
- package/dynamic/mimo.host.js +1732 -0
- package/dynamic/mimo.host.template.mjs +169 -0
- package/dynamic/opencode.host.js +1443 -0
- package/dynamic/opencode.host.template.mjs +125 -0
- package/home-plugin/cli-bridge-indicator/cordis.patch.yml +31 -0
- package/home-plugin/cli-bridge-indicator/lib/client.js +606 -0
- package/home-plugin/cli-bridge-indicator/lib/index.mjs +420 -0
- package/home-plugin/cli-bridge-indicator/lib/preset-declarations.mjs +137 -0
- package/home-plugin/cli-bridge-indicator/lib/settings.mjs +300 -0
- package/mcp/agy-mcp-server.mjs +6 -0
- package/mcp/cli-bridge-mcp.mjs +185 -0
- package/mcp/codebuddy-mcp-server.mjs +6 -0
- package/mcp/mimo-mcp-server.mjs +6 -0
- package/mcp/providers/agy.mjs +254 -0
- package/mcp/providers/codebuddy.mjs +397 -0
- package/mcp/providers/mimo.mjs +290 -0
- package/mcp/providers/opencode.mjs +236 -0
- package/package.json +89 -4
- package/preset/agy-first/agent.cordis.yml +141 -0
- package/preset/agy-first/cli-bridge.mjs +169 -0
- package/preset/agy-first/plugin-list.mjs +26 -0
- package/preset/agy-first/preset.yml +3 -0
- package/preset/codebuddy-first/agent.cordis.yml +141 -0
- package/preset/codebuddy-first/cli-bridge.mjs +188 -0
- package/preset/codebuddy-first/plugin-list.mjs +20 -0
- package/preset/codebuddy-first/preset.yml +3 -0
- package/preset/mimo-first/agent.cordis.yml +143 -0
- package/preset/mimo-first/cli-bridge.mjs +236 -0
- package/preset/mimo-first/plugin-list.mjs +39 -0
- package/preset/mimo-first/preset.yml +3 -0
- package/preset/opencode-first/agent.cordis.yml +141 -0
- package/preset/opencode-first/cli-bridge.mjs +147 -0
- package/preset/opencode-first/plugin-list.mjs +26 -0
- package/preset/opencode-first/preset.yml +3 -0
- package/preset/standard-base.mjs +102 -0
- package/providers/agy.mjs +398 -0
- package/providers/codebuddy.mjs +926 -0
- package/providers/mimo.mjs +864 -0
- package/providers/opencode.mjs +619 -0
- package/providers/registry.mjs +39 -0
- package/scripts/build.mjs +235 -0
- package/scripts/deploy.mjs +61 -0
- package/scripts/verify.mjs +148 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// dynamic/opencode.host.template.mjs — opencode 动态沙箱宿主模板(cordis_define code.host 源)。
|
|
2
|
+
//
|
|
3
|
+
// 构建(node scripts/build.mjs --only=opencode)把 core/bridge-kit.mjs 与
|
|
4
|
+
// providers/opencode.mjs 分别内联进下方两个占位标记行(各占一行、行内仅此标记),
|
|
5
|
+
// 生成 dynamic/opencode.host.js。注意:标记字面量绝不能出现在本注释里 —— 构建做全局
|
|
6
|
+
// 替换,注释中出现同样会被替换成正文代码而炸掉语法。
|
|
7
|
+
// 沙箱纪律(旧仓 dynamic/host.js 头注 verbatim 精神):
|
|
8
|
+
// - 禁 import/require、无 TypeScript;无 AbortController/process 裸引用/Buffer/原生
|
|
9
|
+
// 定时器 —— process 只经 typeof 守卫探测;宿主能力全部来自注入的 harness.*/ctx。
|
|
10
|
+
// - 顶层 return { inject, apply } 为动态宿主约定形态(生成物是 .js/CJS 包装,顶层
|
|
11
|
+
// return 合法;本模板文件是 .mjs,不要直接 node --check 模板本身,只 check 生成物)。
|
|
12
|
+
// - 无 ctx.emit:状态经 ctx.get('cliBridgeCollector').mergeSnapshot('opencode', snap)
|
|
13
|
+
// 推给家级灯;动态形态不宣告 mode(旧语义:普通模式灯仅在调用时临时显示)。
|
|
14
|
+
/*__KIT__*/
|
|
15
|
+
/*__PROVIDER__*/
|
|
16
|
+
/*__SCHED__*/
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
inject: ['tools', 'subprocess', 'systemPrompt', 'timer'],
|
|
20
|
+
apply(ctx) {
|
|
21
|
+
// 调度门禁(0.2.0):设置面板关掉 opencode → 本形态不注册工具/政策段;fail-open。
|
|
22
|
+
if (!isBridgeEnabled('opencode', SCHED_ALL_IDS)) return
|
|
23
|
+
const subprocess = ctx.subprocess
|
|
24
|
+
const sandboxPolicy = ctx.get('sandboxPolicy')
|
|
25
|
+
// 沙箱可能运行在无 process 的环境:typeof 守卫读 env(旧仓 dynamic 的等价面)。
|
|
26
|
+
const env = (typeof process !== 'undefined' && process.env) ? process.env : {}
|
|
27
|
+
|
|
28
|
+
const provider = defineProvider({ env })
|
|
29
|
+
|
|
30
|
+
function publish(snapshot) {
|
|
31
|
+
try {
|
|
32
|
+
const collector = ctx.get('cliBridgeCollector')
|
|
33
|
+
if (collector && typeof collector.mergeSnapshot === 'function') { collector.mergeSnapshot('opencode', snapshot); return }
|
|
34
|
+
} catch (e) { /* fall through to legacy alias */ }
|
|
35
|
+
try {
|
|
36
|
+
const legacy = ctx.get('opencodeCollector')
|
|
37
|
+
if (legacy && typeof legacy.mergeSnapshot === 'function') legacy.mergeSnapshot(snapshot)
|
|
38
|
+
} catch (e) { /* 灯数据尽力而为 */ }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// exe 优先级(与描述符同一套):env OPENCODE_BIN/OPENCODE_CLI > 桌面版 V2 探测
|
|
42
|
+
// > PATH 查找 opencode-cli(subprocess.resolveExecutable)。
|
|
43
|
+
// 二进制名 opencode-cli(V2 桌面版),不做 opencode.exe 兜底(V1/V2 不能并存)。
|
|
44
|
+
const exeCandidates = resolveExePrefix(env, '')
|
|
45
|
+
async function resolveExe(backend, signal) {
|
|
46
|
+
for (const c of exeCandidates) {
|
|
47
|
+
if (/\.(mjs|cjs|js)$/i.test(c) && typeof process !== 'undefined' && process.execPath) return [process.execPath, c]
|
|
48
|
+
return c
|
|
49
|
+
}
|
|
50
|
+
return await subprocess.resolveExecutable('opencode-cli', undefined, signal)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// cwd 兜底:OPENCODE_MCP_CWD > sandboxPolicy.workspaceRoot > process.cwd() > '.'。
|
|
54
|
+
function getCwdFallback() {
|
|
55
|
+
if (env.OPENCODE_MCP_CWD) return String(env.OPENCODE_MCP_CWD)
|
|
56
|
+
if (sandboxPolicy && typeof sandboxPolicy.workspaceRoot === 'string' && sandboxPolicy.workspaceRoot) return sandboxPolicy.workspaceRoot
|
|
57
|
+
if (typeof process !== 'undefined' && typeof process.cwd === 'function') { try { return process.cwd() } catch (e) {} }
|
|
58
|
+
return '.'
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
provider.attach({ ctx, subprocess, resolveExe, getCwdFallback, publish })
|
|
62
|
+
|
|
63
|
+
const OUTPUT_SCHEMA = { type: 'object', additionalProperties: true }
|
|
64
|
+
|
|
65
|
+
harness.registerTool(ctx, harness.defineTool({
|
|
66
|
+
name: provider.tools.run.name,
|
|
67
|
+
description: provider.tools.run.description,
|
|
68
|
+
parameters: provider.tools.run.inputSchema,
|
|
69
|
+
output: { schema: OUTPUT_SCHEMA, render: function (args, value) { return renderResult(value, provider) } },
|
|
70
|
+
execute: function (args, exec) { return provider.runToolLogic(args, exec) }
|
|
71
|
+
}))
|
|
72
|
+
harness.registerTool(ctx, harness.defineTool({
|
|
73
|
+
name: provider.tools.continue.name,
|
|
74
|
+
description: provider.tools.continue.description,
|
|
75
|
+
parameters: provider.tools.continue.inputSchema,
|
|
76
|
+
output: { schema: OUTPUT_SCHEMA, render: function (args, value) { return renderResult(value, provider) } },
|
|
77
|
+
execute: function (args, exec) { return provider.continueToolLogic(args, exec) }
|
|
78
|
+
}))
|
|
79
|
+
harness.registerTool(ctx, harness.defineTool({
|
|
80
|
+
name: provider.tools.status.name,
|
|
81
|
+
description: provider.tools.status.description,
|
|
82
|
+
parameters: provider.tools.status.inputSchema,
|
|
83
|
+
output: { schema: OUTPUT_SCHEMA, render: function (args, value) { return renderStatus(value, provider) } },
|
|
84
|
+
execute: function (args) { return provider.statusToolLogic(args) }
|
|
85
|
+
}))
|
|
86
|
+
|
|
87
|
+
// 浏览器指示灯轮询的 RPC 面(旧 dynamic/handle('<id>_status') verbatim 语义)。
|
|
88
|
+
harness.handle('opencode_status', function () { return provider.statusToolLogic({}) })
|
|
89
|
+
|
|
90
|
+
const policyText = [
|
|
91
|
+
'opencode-first execution policy (local opencode CLI bridge).',
|
|
92
|
+
'',
|
|
93
|
+
'Local agent CLI "opencode" handles coding tasks under full DSH control (permissions auto-approved, never blocks on a prompt). By default, opencode runs in the background and returns a jobId immediately; collect results via job_output and watch live progress via opencode_status anytime.',
|
|
94
|
+
'',
|
|
95
|
+
'Decision table for tool selection:',
|
|
96
|
+
'- Single read/glob/grep or short (<30s) command -> Native tools.',
|
|
97
|
+
'- Implementing, editing, refactoring, debugging, builds, multi-file investigation -> opencode_run.',
|
|
98
|
+
'- Follow-ups on the same topic -> opencode_continue (with latest=true or sessionId; opencode preserves session context).',
|
|
99
|
+
'- Final build/test verification of opencode output -> Native tools.',
|
|
100
|
+
'',
|
|
101
|
+
'Context protocol (one topic = one opencode session):',
|
|
102
|
+
'- First dispatch on a topic: provide the task with a compact CONTEXT preamble (point to paths, do not paste file contents):',
|
|
103
|
+
' CONTEXT: 2-6 lines — goal; repo root; key paths; decisions/constraints; current state.',
|
|
104
|
+
' TASK: the complete instruction.',
|
|
105
|
+
'- Follow-ups: call opencode_continue and state only what is new.',
|
|
106
|
+
'',
|
|
107
|
+
'Execution & Fallback protocol:',
|
|
108
|
+
'- Dispatch defaults to background=true (set background=false only to block). Collect via job_output.',
|
|
109
|
+
'- On rate-limit or network failure, a confirmation dialog opens in BOTH foreground and background while in flight.',
|
|
110
|
+
'- If result has fallback=true (status FALLBACK_TO_DSH), the user chose DSH-local: finish with native tools and NEVER call opencode again for this task.',
|
|
111
|
+
'- Never loop opencode calls; never ask opencode to call back into DSH.',
|
|
112
|
+
'',
|
|
113
|
+
'Model & credentials:',
|
|
114
|
+
'- Prefer a free model for routine work: pass a model id ending in -free (e.g. "opencode/nemotron-3-ultra-free") unless this task genuinely needs a frontier model.',
|
|
115
|
+
'- Omit the model unless you have a reason: opencode then uses its own configured default (or the one chosen in CLI Bridge settings). Pass model in provider/model form to override.',
|
|
116
|
+
'- Credentials are owned by opencode, not by this bridge: auth/API-key failures mean the user should run `opencode auth login`. Do not retry in a loop.'
|
|
117
|
+
].join('\n')
|
|
118
|
+
|
|
119
|
+
ctx.systemPrompt.section({
|
|
120
|
+
name: 'opencode:policy',
|
|
121
|
+
order: (typeof ctx.systemPrompt.getSectionOrder === 'function' ? ctx.systemPrompt.getSectionOrder('TOOL_SUBAGENT') : 2800) + 10,
|
|
122
|
+
text: policyText
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# CLI Bridge — bundle 补丁层(单一入口)
|
|
2
|
+
#
|
|
3
|
+
# 本文件由 DSH 插件系统在安装后自动作为 profile 的 bundle 层挂载:
|
|
4
|
+
# dsh plugin --profile web add @luchenglong/cli-bridge (npm registry)
|
|
5
|
+
# dsh plugin --profile web add <本地包路径> (本地安装)
|
|
6
|
+
# 声明位置: 主包 package.json 的 dsh.bundle.patch。
|
|
7
|
+
#
|
|
8
|
+
# 三个旧包(agy-first-bridge / codebuddy-first-bridge / mimo-first-bridge)
|
|
9
|
+
# 各自的 bundle patch 在这里收敛为一行:
|
|
10
|
+
# - host 半:裸包名 '@luchenglong/cli-bridge' 经主包 package.json main 解析
|
|
11
|
+
# → home-plugin/cli-bridge-indicator/lib/index.mjs(多 provider 状态收集器)。
|
|
12
|
+
# - client 半(浏览器):主包 package.json 的 dsh.client 声明被宿主
|
|
13
|
+
# client-modules 自动纳入花名册,无需单独一行。
|
|
14
|
+
# 【红线契约】lib/client.js 的 __ModuleLoader__.load({ id }) 必须 === 包名
|
|
15
|
+
# "@luchenglong/cli-bridge"(scoped 名整体即 id;官方与社区 scoped 插件同机制),
|
|
16
|
+
# 否则 arrive() 抛 'loaded without registering' 并使整屏插件页崩溃
|
|
17
|
+
# (agy v1.6.1 / codebuddy v1.1.8 / mimo 同款历史事故)。
|
|
18
|
+
# - agent preset 声明:不再走 bundle patch 内联行(@deepseek-ai/dsh-agent-preset
|
|
19
|
+
# 包 0.1.7-alpha.1 才存在,旧 loader 对导入失败是致命的)。改由指示灯 host 半
|
|
20
|
+
# 在 apply() 里 ctx.inject(['agentPresets']) 向注册表登记三个 preset
|
|
21
|
+
# (cordis-agy / codebuddy-first / cordis-mimo;旧 DSH 上注入器挂起零副作用)。
|
|
22
|
+
# 定义与 legacy YAML 同源:lib/preset-declarations.mjs 直接 import
|
|
23
|
+
# preset/<dir>/plugin-list.mjs(buildPlugins(meta) 一份源两用),
|
|
24
|
+
# {__jsExpr} 字面量原样透传给注册器 —— 不存在第二个生成器。
|
|
25
|
+
#
|
|
26
|
+
# 机器特定配置请写在用户层补丁
|
|
27
|
+
# Windows: %APPDATA%\DSH Desktop\dsh-home\cordis.patch.yml
|
|
28
|
+
# 的同 id 行里 — 用户层后应用,按行 id 整体覆盖本行 config。
|
|
29
|
+
- insert:
|
|
30
|
+
- id: cli-bridge-indicator
|
|
31
|
+
name: '@luchenglong/cli-bridge'
|