dsh-codebuddy-llm 0.1.0 → 0.1.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.
- package/README.md +4 -3
- package/README.zh.md +4 -3
- package/index.js +45 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -28,14 +28,14 @@ This is an unofficial, third-party plugin. Its author is the only party behind i
|
|
|
28
28
|
|
|
29
29
|
## Requirements
|
|
30
30
|
|
|
31
|
-
- DeepSeek Harness
|
|
31
|
+
- DeepSeek Harness `>=0.2.1-rc.2 <0.3.0` (declared as `engines.dsh`; the installer refuses a mismatched host instead of loading it)
|
|
32
32
|
- Node.js `>=24.9`
|
|
33
33
|
- The `codebuddy` CLI on `PATH`, signed in (or point `command` at its absolute path)
|
|
34
34
|
|
|
35
35
|
## Tips
|
|
36
36
|
|
|
37
37
|
- **Prove the CLI first, without the harness.** `codebuddy --print --output-format stream-json "hello"` should print one JSON line per event. A plugin that registers but answers nothing usually means the CLI is not signed in, not on the `PATH` of the process that launched the harness, or does not support the flags in `args`.
|
|
38
|
-
- **Prefer an absolute `command`** when the harness runs from a GUI, a daemon, or a service manager: those often inherit a smaller `PATH` than your shell.
|
|
38
|
+
- **Prefer an absolute `command`** when the harness runs from a GUI, a daemon, or a service manager: those often inherit a smaller `PATH` than your shell. A missing CLI is reported rather than hidden — the Models page refuses with `CodeBuddy CLI is unavailable: codebuddy is not on this process's PATH (N directories searched)`, and the same text is logged at load.
|
|
39
39
|
- **Narrow the default permission mode** for repositories you did not write. `default`, `acceptEdits`, or `plan` keeps the CLI's tools from acting on their own; `bypassPermissions` does not.
|
|
40
40
|
- **Try `transport: acp`** when the CLI supports `--acp`: one child per route instead of one per call, the CLI's thinking arrives as its own block, and a conversation resumes its CLI-side session. Fall back to `print` for a CLI without ACP.
|
|
41
41
|
- **Keep the entry id `llm-cli`.** That id is the settings namespace, so the documented `llm-cli:` section and any existing profile settings keep working after install.
|
|
@@ -118,7 +118,8 @@ Model ids come from the CLI itself: an `acp` route asks the handshake (which als
|
|
|
118
118
|
- Only the final answer crosses the boundary: the CLI's internal tool steps stay invisible to the harness session log.
|
|
119
119
|
- `permissionMode` governs the CLI's tools, and harness permission presets, the filesystem sandbox, and the shell sandbox do not mediate them. The default `bypassPermissions` therefore grants the child the desktop process's OS access — narrow it when that is not intended.
|
|
120
120
|
- Only CodeBuddy-shaped output is understood: both the `stream-json` vocabulary and the positional-prompt invocation are CodeBuddy's.
|
|
121
|
-
- A missing executable
|
|
121
|
+
- A missing or unreachable executable is reported as a refusal naming the configured command, instead of an empty catalog; the route still mounts, and still serves a `models` list you configured yourself. Model calls then fail the same way, so fix the `command` before relying on the route.
|
|
122
|
+
- A listing command that exits non-zero, times out, or prints a help text without the model line is reported the same way: discovery never turns an unreadable CLI into a silently empty catalog.
|
|
122
123
|
- Compaction and a model switch need a context capacity: the CLI must report one, or the catalog entry must declare `contextWindow`.
|
|
123
124
|
|
|
124
125
|
## Provenance
|
package/README.zh.md
CHANGED
|
@@ -28,14 +28,14 @@ description: "委托式 CLI LLM 适配器:每次模型调用都交给 CodeBudd
|
|
|
28
28
|
|
|
29
29
|
## 运行要求
|
|
30
30
|
|
|
31
|
-
- DeepSeek Harness
|
|
31
|
+
- DeepSeek Harness `>=0.2.1-rc.2 <0.3.0`(以 `engines.dsh` 声明,宿主版本不符时安装器会拒绝,而不是带病装载)
|
|
32
32
|
- Node.js `>=24.9`
|
|
33
33
|
- `PATH` 上有 `codebuddy` 命令并已登录(或用 `command` 指向绝对路径)
|
|
34
34
|
|
|
35
35
|
## 使用提示
|
|
36
36
|
|
|
37
37
|
- **先用 CLI 自证,再装插件。** 直接跑 `codebuddy --print --output-format stream-json "hello"`,应能看到一行一个事件的 JSON。若插件挂上了却答不出内容,通常意味着 CLI 未登录、不在启动 harness 那个进程的 `PATH` 上,或不支持 `args` 里的参数。
|
|
38
|
-
- **`command` 尽量写绝对路径。** 从 GUI、守护进程或服务管理器启动 harness 时,继承到的 `PATH` 往往比你的 shell 小。
|
|
38
|
+
- **`command` 尽量写绝对路径。** 从 GUI、守护进程或服务管理器启动 harness 时,继承到的 `PATH` 往往比你的 shell 小。CLI 缺失不会被静默吞掉:Models 页会以 `CodeBuddy CLI is unavailable: codebuddy is not on this process's PATH (N directories searched)` 拒绝,装载时也会打印同样的内容。
|
|
39
39
|
- **对不是自己写的仓库,先调窄权限。** `default`、`acceptEdits` 或 `plan` 会阻止 CLI 的工具自行行动;`bypassPermissions` 不会。
|
|
40
40
|
- **CLI 支持 `--acp` 时优先试 `transport: acp`。** 每条路由只起一个子进程而非每次调用一个,CLI 的思考过程会作为独立块返回,对话也能续用 CLI 侧会话;不支持 ACP 的 CLI 仍用 `print`。
|
|
41
41
|
- **保留 entry id `llm-cli`。** 这个 id 就是设置命名空间,改掉它会让文档里的 `llm-cli:` 配置段和已有 profile 设置失效。
|
|
@@ -118,7 +118,8 @@ dsh plugin --profile work add dsh-codebuddy-llm
|
|
|
118
118
|
- 只有最终答案越过边界:CLI 内部的工具步骤对 harness 会话日志不可见。
|
|
119
119
|
- `permissionMode` 管的是 CLI 的工具;harness 的权限预设、文件系统沙箱和 shell 沙箱都不介入。因此默认的 `bypassPermissions` 等于把桌面进程的 OS 权限交给子进程——不希望如此时请调窄。
|
|
120
120
|
- 只理解 CodeBuddy 形状的输出:`stream-json` 词汇和位置参数式调用都是 CodeBuddy 的约定。
|
|
121
|
-
-
|
|
121
|
+
- 可执行文件缺失或不可执行时,会以拒绝的形式报出所配置的命令,而不是返回空目录;路由仍会挂载,你自己在 `models` 里配置的列表也照常可用。此时模型调用同样会失败,请先修好 `command` 再依赖该路由。
|
|
122
|
+
- 列表命令非零退出、超时,或输出里没有模型行时,同样以拒绝形式报出:探测不会把「读不懂的 CLI」伪装成「空目录」。
|
|
122
123
|
- 压缩与模型切换需要上下文容量:要么 CLI 报出该值,要么目录条目声明 `contextWindow`。
|
|
123
124
|
|
|
124
125
|
## 来源
|
package/index.js
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
import { LlmAdapter } from "@deepseek-ai/dsh-llm";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
|
+
import { accessSync, constants } from "node:fs";
|
|
4
|
+
import { delimiter, join } from "node:path";
|
|
3
5
|
/** Largest delay a Node timer accepts; inlined so this file needs no dsh-timeout package. */
|
|
4
6
|
const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
7
|
+
/**
|
|
8
|
+
* Report why the configured executable cannot be run, or undefined when it can.
|
|
9
|
+
*
|
|
10
|
+
* A host launched from a desktop shell inherits launchd's PATH rather than the
|
|
11
|
+
* one a login shell assembles, so an installed CLI is routinely unreachable
|
|
12
|
+
* under the bare name `codebuddy`. Discovery would otherwise report an empty
|
|
13
|
+
* catalog, which reads as "this route serves no models" instead of "the CLI is
|
|
14
|
+
* not installed or not on this process's PATH".
|
|
15
|
+
* @param command - configured executable, either a bare name or a path.
|
|
16
|
+
* @param env - extra environment entries the child receives over the seam's base.
|
|
17
|
+
* @returns an actionable diagnostic, or undefined when the executable resolves.
|
|
18
|
+
*/
|
|
19
|
+
function executableProblem(command, env) {
|
|
20
|
+
const runs = (candidate) => {
|
|
21
|
+
try {
|
|
22
|
+
accessSync(candidate, constants.X_OK);
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
if (command.length === 0) return "the configured command is empty";
|
|
29
|
+
if (command.includes("/")) return runs(command) ? undefined : `${command} is missing or not executable`;
|
|
30
|
+
const path = env.PATH ?? process.env.PATH ?? "";
|
|
31
|
+
const searched = path.split(delimiter).filter((dir) => dir.length > 0);
|
|
32
|
+
for (const dir of searched) if (runs(join(dir, command))) return undefined;
|
|
33
|
+
return `${command} is not on this process's PATH (${searched.length === 0 ? "PATH is empty" : `${searched.length} directories searched`})`;
|
|
34
|
+
}
|
|
5
35
|
//#region lib/types/acp.js
|
|
6
36
|
/**
|
|
7
37
|
* ACP transport: one long-lived CLI child that carries every delegated run of a
|
|
@@ -1536,7 +1566,16 @@ async function discoverAcpModels(request) {
|
|
|
1536
1566
|
async function discoverCliModels(request) {
|
|
1537
1567
|
const advertised = request.acp === void 0 ? void 0 : await discoverAcpModels(request);
|
|
1538
1568
|
const help = advertised === void 0 || advertised.length === 0 ? await captureListing(request) : void 0;
|
|
1539
|
-
|
|
1569
|
+
let discovered;
|
|
1570
|
+
if (advertised !== void 0 && advertised.length > 0) discovered = [...advertised];
|
|
1571
|
+
else if (help === void 0) throw new Error(`the discovery command \`${request.argv.join(" ")}\` reported nothing within ${String(request.timeoutMs)}ms (non-zero exit, timeout, or cancellation)`);
|
|
1572
|
+
else {
|
|
1573
|
+
discovered = parseCodeBuddyModels(help);
|
|
1574
|
+
// Help text without the model listing means this CLI's ids cannot be read,
|
|
1575
|
+
// which is a different fault from a route that serves none: reporting it
|
|
1576
|
+
// keeps a shape change from passing as an empty catalog.
|
|
1577
|
+
if (discovered.length === 0) throw new Error(`\`${request.argv.join(" ")}\` listed no supported models; the CLI's --model help text is not in the expected shape`);
|
|
1578
|
+
}
|
|
1540
1579
|
const seen = new Set(discovered.map((model) => model.id));
|
|
1541
1580
|
const models = [...discovered];
|
|
1542
1581
|
for (const model of request.configured) {
|
|
@@ -1624,6 +1663,11 @@ function apply(ctx, config) {
|
|
|
1624
1663
|
const probeCatalog = async (signal) => {
|
|
1625
1664
|
const current = plainOptions(config);
|
|
1626
1665
|
const facts = resolveAdapterOptions(current, process.cwd());
|
|
1666
|
+
// A missing CLI is a deployment fault, not an empty catalog: throwing here
|
|
1667
|
+
// reaches the Models page as a refusal carrying this text, while the load
|
|
1668
|
+
// probe logs it, so neither surface shows a silent zero-model route.
|
|
1669
|
+
const problem = executableProblem(facts.argv[0], facts.env);
|
|
1670
|
+
if (problem !== void 0) throw new Error(`CodeBuddy CLI is unavailable: ${problem}. Install the CodeBuddy CLI, or point \`command\` in this plugin's \`llm-cli\` config at its absolute path.`);
|
|
1627
1671
|
const models = await discoverCliModels({
|
|
1628
1672
|
argv: facts.discoveryArgv,
|
|
1629
1673
|
cwd: facts.cwd,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codebuddy-llm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Delegating CLI LLM adapter for the DeepSeek Harness: answers each model call by running the CodeBuddy CLI child that carries its own sign-in and agent loop, so a deployment runs without an API key",
|
|
5
5
|
"author": "saisaiwang <287442583@qq.com>",
|
|
6
6
|
"repository": {
|
|
@@ -46,11 +46,11 @@
|
|
|
46
46
|
"registry": "https://registry.npmjs.org/"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
49
|
-
"dsh": "
|
|
49
|
+
"dsh": ">=0.2.1-rc.2 <0.3.0",
|
|
50
50
|
"node": ">=24.9"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@deepseek-ai/dsh-llm": "
|
|
53
|
+
"@deepseek-ai/dsh-llm": ">=0.2.1-rc.2 <0.3.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependenciesMeta": {
|
|
56
56
|
"@deepseek-ai/dsh-llm": {
|