opencode-tbot 0.1.33 → 0.1.34
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.ja.md +128 -44
- package/README.md +84 -41
- package/README.zh-CN.md +104 -58
- package/dist/plugin.js +40 -17
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
package/README.zh-CN.md
CHANGED
|
@@ -4,27 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
[English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md)
|
|
6
6
|
|
|
7
|
-
> 本项目并非由 OpenCode
|
|
7
|
+
> 本项目并非由 OpenCode 官方团队开发,也不隶属于 OpenCode 官方。
|
|
8
8
|
|
|
9
9
|
## 概览
|
|
10
10
|
|
|
11
|
-
`opencode-tbot`
|
|
11
|
+
`opencode-tbot` 让你可以在 Telegram 中直接操作 OpenCode,并为每个聊天维护一份绑定状态。
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
- Telegram
|
|
15
|
-
- 图片轮次会在临时 fork
|
|
16
|
-
- Telegram
|
|
17
|
-
- OpenCode 的权限请求可以直接在 Telegram 中审批。
|
|
13
|
+
- 纯文本消息会转发到当前 OpenCode 会话。
|
|
14
|
+
- Telegram 照片和图片文档会作为 OpenCode 文件片段上传。
|
|
15
|
+
- 图片轮次会在临时 fork 会话中执行,避免后续纯文本对话继承图片上下文。
|
|
16
|
+
- OpenCode 发起的权限请求可以直接在 Telegram 内联按钮里审批或拒绝。
|
|
18
17
|
- 会话错误事件可以回推到已绑定的 Telegram chat。
|
|
19
|
-
-
|
|
18
|
+
- 语音消息会被明确拒绝,并返回本地化提示。
|
|
19
|
+
- 聊天绑定和会话选择状态会保存在 JSON 状态文件中。
|
|
20
20
|
|
|
21
21
|
## 环境要求
|
|
22
22
|
|
|
23
23
|
- 一个正在运行、并会加载该插件的 OpenCode Host 进程。
|
|
24
24
|
- 一个 Telegram bot token。
|
|
25
|
-
- Node.js `>=22.12.0
|
|
25
|
+
- Node.js `>=22.12.0`,用于 CLI 和本地开发。
|
|
26
|
+
- `pnpm`,用于仓库开发。
|
|
26
27
|
|
|
27
|
-
##
|
|
28
|
+
## 安装与更新
|
|
28
29
|
|
|
29
30
|
推荐安装方式:
|
|
30
31
|
|
|
@@ -32,22 +33,33 @@
|
|
|
32
33
|
npm exec --package opencode-tbot@latest opencode-tbot -- install
|
|
33
34
|
```
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
安装器会:
|
|
37
|
+
|
|
38
|
+
- 在全局 OpenCode 插件列表中注册 `opencode-tbot@latest`
|
|
39
|
+
- 更新实际生效的 OpenCode 全局配置文件
|
|
40
|
+
- 写入或合并全局插件运行时配置
|
|
41
|
+
- 打印 OpenCode 配置路径、插件配置路径和默认插件日志目录
|
|
36
42
|
|
|
37
43
|
如果 `~/.config/opencode/opencode.jsonc` 已存在,安装器会优先更新它;否则会使用 `~/.config/opencode/opencode.json`。
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
查看已安装 CLI 版本:
|
|
40
46
|
|
|
41
47
|
```bash
|
|
42
48
|
npm exec --package opencode-tbot@latest opencode-tbot -- --version
|
|
43
49
|
```
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
只更新 OpenCode 中注册的 npm 插件 spec,而不改 bot token:
|
|
46
52
|
|
|
47
53
|
```bash
|
|
48
54
|
npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
49
55
|
```
|
|
50
56
|
|
|
57
|
+
`install` 是默认命令。例如,下面这种写法也适合非交互安装:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm exec --package opencode-tbot@latest opencode-tbot -- --bot-token <token>
|
|
61
|
+
```
|
|
62
|
+
|
|
51
63
|
### CLI 参数
|
|
52
64
|
|
|
53
65
|
`install` 支持:
|
|
@@ -55,7 +67,7 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
|
55
67
|
- `--bot-token <token>` 非交互写入 Telegram bot token
|
|
56
68
|
- `--telegram-api-root <url>` 覆盖 Telegram Bot API 根地址
|
|
57
69
|
- `--plugin-spec <spec>` 注册自定义 npm 插件 spec
|
|
58
|
-
- `--skip-register`
|
|
70
|
+
- `--skip-register` 只重写插件配置,不修改 OpenCode 插件注册
|
|
59
71
|
- `--home-dir <path>` 使用自定义 home 目录
|
|
60
72
|
|
|
61
73
|
`update` 支持:
|
|
@@ -65,15 +77,23 @@ npm exec --package opencode-tbot@latest opencode-tbot -- update
|
|
|
65
77
|
|
|
66
78
|
## 配置
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
运行时配置只会从以下路径加载:
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
- `~/.config/opencode/opencode-tbot/config.json`
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
OpenCode 的插件注册信息保存在全局 OpenCode 配置中:
|
|
73
85
|
|
|
74
|
-
|
|
86
|
+
- 如果存在,使用 `~/.config/opencode/opencode.jsonc`
|
|
87
|
+
- 否则使用 `~/.config/opencode/opencode.json`
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
本插件不会从 `.env` 读取运行时配置,请使用全局 JSON 配置文件。
|
|
90
|
+
|
|
91
|
+
遗留行为说明:
|
|
92
|
+
|
|
93
|
+
- `<worktree>/tbot.config.json` 会在运行时被忽略;如果检测到,插件会记录警告,提示你迁移配置
|
|
94
|
+
- 遗留的 `openrouter` 语音转写配置会在运行时被忽略;安装器重写配置时也会自动移除
|
|
95
|
+
|
|
96
|
+
### `config.json` 示例
|
|
77
97
|
|
|
78
98
|
```json
|
|
79
99
|
{
|
|
@@ -112,69 +132,77 @@ OpenCode 的插件注册信息保存在全局 OpenCode 配置中:优先使用
|
|
|
112
132
|
|
|
113
133
|
| 字段 | 必填 | 默认值 | 说明 |
|
|
114
134
|
| --- | --- | --- | --- |
|
|
115
|
-
| `telegram.botToken` | 是 | - | Telegram bot token
|
|
135
|
+
| `telegram.botToken` | 是 | - | Telegram bot token。通常由安装器写入全局插件配置。 |
|
|
116
136
|
| `telegram.allowedChatIds` | 否 | `[]` | 允许访问的 Telegram chat ID。为空时接受任意 chat。 |
|
|
117
|
-
| `telegram.apiRoot` | 否 | `https://api.telegram.org` | Telegram Bot API
|
|
137
|
+
| `telegram.apiRoot` | 否 | `https://api.telegram.org` | Telegram Bot API 根地址,适合测试或自建网关。 |
|
|
118
138
|
| `state.path` | 否 | `./data/opencode-tbot.state.json` | JSON 状态文件路径,相对当前 OpenCode worktree 解析。 |
|
|
119
|
-
| `prompt.waitTimeoutMs` | 否 | `1800000` | 单次异步 prompt
|
|
120
|
-
| `prompt.pollRequestTimeoutMs` | 否 | `15000` |
|
|
121
|
-
| `prompt.recoveryInactivityTimeoutMs` | 否 | `120000` |
|
|
122
|
-
| `logging.level` | 否 | `info` |
|
|
139
|
+
| `prompt.waitTimeoutMs` | 否 | `1800000` | 单次异步 prompt 生命周期的总等待上限。 |
|
|
140
|
+
| `prompt.pollRequestTimeoutMs` | 否 | `15000` | 每次向 OpenCode 发起恢复轮询请求时的超时时间。 |
|
|
141
|
+
| `prompt.recoveryInactivityTimeoutMs` | 否 | `120000` | 仅在长时间没有新进展时生效的恢复超时。 |
|
|
142
|
+
| `logging.level` | 否 | `info` | Host 和文件日志共用的结构化日志级别,会规范化为 `debug`、`info`、`warn` 或 `error`。 |
|
|
123
143
|
| `logging.sinks.host` | 否 | `true` | 是否通过 `client.app.log({ body: ... })` 写入 OpenCode Host 日志。 |
|
|
124
144
|
| `logging.sinks.file` | 否 | `true` | 是否写入插件自己的 JSONL 文件日志。 |
|
|
125
|
-
| `logging.file.dir` | 否 | `%USERPROFILE%/.local/share/opencode/log/plugins/opencode-tbot` |
|
|
145
|
+
| `logging.file.dir` | 否 | `%USERPROFILE%/.local/share/opencode/log/plugins/opencode-tbot` | 插件 JSONL 日志目录。相对路径会基于当前 OpenCode worktree 解析。 |
|
|
126
146
|
| `logging.file.retention.maxFiles` | 否 | `30` | 最多保留多少个插件日志文件。 |
|
|
127
147
|
| `logging.file.retention.maxTotalBytes` | 否 | `314572800` | 插件日志文件总大小上限。 |
|
|
128
|
-
| `logLevel` | 否 | `info` | `logging.level`
|
|
148
|
+
| `logLevel` | 否 | `info` | `logging.level` 的兼容别名。仍然可用。 |
|
|
129
149
|
|
|
130
150
|
### 说明
|
|
131
151
|
|
|
132
152
|
- `state.path` 会相对当前 OpenCode worktree 解析。
|
|
133
|
-
-
|
|
153
|
+
- `logging.file.dir` 如果是相对路径,也会相对当前 worktree 解析。
|
|
154
|
+
- Telegram prompt 采用 async-first:插件先提交 `session.promptAsync()`,再通过消息与状态恢复最终回复。
|
|
134
155
|
- 如果 `telegram.allowedChatIds` 为空,bot 会接受任意 chat 的消息;生产环境建议显式限制。
|
|
135
156
|
- 权限审批与会话错误通知通过插件 hooks 处理。
|
|
136
|
-
- `/language` 当前支持 English
|
|
137
|
-
- 默认会双写日志:OpenCode Host 日志 + 插件 JSONL 文件日志。
|
|
157
|
+
- `/language` 当前支持 English、简体中文、日语,并会同步当前 chat 的 Telegram 命令描述。
|
|
138
158
|
- 文件日志默认只记录元数据,不记录 prompt 正文、附件内容、原始 URL 或 secrets。
|
|
139
159
|
|
|
140
|
-
## 日志
|
|
141
|
-
|
|
142
|
-
- OpenCode Host 日志目录:`%USERPROFILE%/.local/share/opencode/log`
|
|
143
|
-
- 插件日志目录:`%USERPROFILE%/.local/share/opencode/log/plugins/opencode-tbot`
|
|
144
|
-
- 文件格式:JSONL,每行一条结构化事件
|
|
145
|
-
- 关键关联字段:`runtimeId`、`operationId`、`correlationId`、`updateId`、`chatId`、`sessionId`、`projectId`
|
|
146
|
-
- 常见组件:`runtime`、`telegram`、`opencode`、`prompt`、`plugin-event`、`storage`
|
|
147
|
-
- 默认保留策略:最多 30 个文件,总大小不超过 300 MB
|
|
148
|
-
|
|
149
160
|
## 快速开始
|
|
150
161
|
|
|
151
162
|
1. 运行 `npm exec --package opencode-tbot@latest opencode-tbot -- install`。
|
|
152
|
-
2.
|
|
153
|
-
3. 在目标 worktree 中启动 OpenCode
|
|
163
|
+
2. 如果需要限制可访问 chat,在 `~/.config/opencode/opencode-tbot/config.json` 中设置 `telegram.allowedChatIds`。
|
|
164
|
+
3. 在目标 worktree 中启动 OpenCode,让插件运行时被加载。
|
|
154
165
|
4. 在 Telegram 中执行 `/status` 验证连通性。
|
|
155
|
-
5.
|
|
166
|
+
5. 运行 `/new [title]`,或直接发送文本消息开始使用。
|
|
156
167
|
|
|
157
168
|
## 命令
|
|
158
169
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
| 命令 | 作用 |
|
|
171
|
+
| --- | --- |
|
|
172
|
+
| `/start` | 显示欢迎消息和快速开始说明。 |
|
|
173
|
+
| `/status` | 汇总展示 OpenCode 健康状态、版本、工作区路径、插件列表、LSP 状态和 MCP 状态。 |
|
|
174
|
+
| `/new [title]` | 在当前项目中创建一个新的 OpenCode 会话。 |
|
|
175
|
+
| `/agents` 或 `/agent` | 列出可用 Agent 并切换当前 Agent。 |
|
|
176
|
+
| `/sessions` | 列出可用会话、切换当前会话,并提供重命名操作。 |
|
|
177
|
+
| `/cancel` | 取消待输入的会话重命名,或中止当前会话正在运行的请求。 |
|
|
178
|
+
| `/model` 或 `/models` | 列出可用模型、切换当前模型,并在可用时选择推理级别。 |
|
|
179
|
+
| `/language` | 切换当前 chat 的 bot 显示语言。 |
|
|
167
180
|
|
|
168
|
-
|
|
181
|
+
### 消息行为
|
|
169
182
|
|
|
170
183
|
- 非命令文本会作为 prompt 发送给 OpenCode。
|
|
171
|
-
- Telegram
|
|
172
|
-
-
|
|
173
|
-
- `/cancel` 会同时中止 OpenCode
|
|
174
|
-
- Telegram
|
|
184
|
+
- Telegram 照片和图片文档会作为 OpenCode 文件片段转发。
|
|
185
|
+
- 图片附件会在当前会话的临时 fork 中处理,避免污染后续纯文本上下文。
|
|
186
|
+
- `/cancel` 会同时中止 OpenCode 会话请求和本地 Telegram 等待状态,让下一次 prompt 能立即开始。
|
|
187
|
+
- Telegram 语音消息暂不支持,会收到本地化拒绝提示。
|
|
188
|
+
|
|
189
|
+
## 日志
|
|
190
|
+
|
|
191
|
+
- OpenCode Host 日志目录:`%USERPROFILE%/.local/share/opencode/log`
|
|
192
|
+
- 插件日志目录:`%USERPROFILE%/.local/share/opencode/log/plugins/opencode-tbot`
|
|
193
|
+
- 文件格式:追加写入的 JSONL,每行一个结构化事件
|
|
194
|
+
- 关联字段:`runtimeId`、`operationId`、`correlationId`、`updateId`、`chatId`、`sessionId`、`projectId`
|
|
195
|
+
- 常见组件:`runtime`、`telegram`、`opencode`、`prompt`、`plugin-event`、`storage`
|
|
196
|
+
- 默认保留策略:最多保留最新 30 个文件,且总大小不超过 300 MB
|
|
175
197
|
|
|
176
198
|
## 开发
|
|
177
199
|
|
|
200
|
+
安装依赖:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
pnpm install
|
|
204
|
+
```
|
|
205
|
+
|
|
178
206
|
构建:
|
|
179
207
|
|
|
180
208
|
```bash
|
|
@@ -187,12 +215,26 @@ pnpm build
|
|
|
187
215
|
pnpm typecheck
|
|
188
216
|
```
|
|
189
217
|
|
|
190
|
-
|
|
218
|
+
运行默认测试集:
|
|
191
219
|
|
|
192
220
|
```bash
|
|
193
221
|
pnpm test
|
|
194
222
|
```
|
|
195
223
|
|
|
224
|
+
运行最接近 CI 的集成路径:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
npm install -g opencode-ai
|
|
228
|
+
OPENCODE_HOST_E2E=1 pnpm test
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
PowerShell 写法:
|
|
232
|
+
|
|
233
|
+
```powershell
|
|
234
|
+
npm install -g opencode-ai
|
|
235
|
+
$env:OPENCODE_HOST_E2E="1"; pnpm test
|
|
236
|
+
```
|
|
237
|
+
|
|
196
238
|
正常使用应依赖“全局安装的 npm 插件 + 全局 OpenCode 配置”。本仓库不再默认提供 `.opencode/plugins` bridge。
|
|
197
239
|
|
|
198
240
|
如果你在本仓库里做源码调试,需要手动创建 `.opencode/plugins/opencode-tbot.ts`:
|
|
@@ -207,8 +249,12 @@ export { default } from "../../src/plugin.ts";
|
|
|
207
249
|
|
|
208
250
|
### 需要一个正在运行的 OpenCode 实例吗?
|
|
209
251
|
|
|
210
|
-
|
|
252
|
+
需要。本仓库只提供 Telegram 集成层,依赖加载该插件的 OpenCode Host 进程。
|
|
253
|
+
|
|
254
|
+
### 为什么 OpenCode 里会显示 `file:///.../node_modules/...` 形式的插件路径?
|
|
255
|
+
|
|
256
|
+
这通常表示某个本地项目在自己的 `node_modules` 中安装了 `opencode-tbot`。CLI 检测到这种布局时会给出警告。请在那个项目里执行 `npm uninstall opencode-tbot` 移除本地包,然后改用推荐的 `npm exec --package ...` 安装流程。
|
|
211
257
|
|
|
212
258
|
### 这是 OpenCode 官方项目吗?
|
|
213
259
|
|
|
214
|
-
不是。它集成 OpenCode
|
|
260
|
+
不是。它集成 OpenCode,但并非 OpenCode 官方团队开发。
|
package/dist/plugin.js
CHANGED
|
@@ -3120,14 +3120,16 @@ function normalizePermissionReply(value) {
|
|
|
3120
3120
|
function extractSessionErrorMessage(error) {
|
|
3121
3121
|
if (error instanceof Error && error.message.trim().length > 0) return error.message.trim();
|
|
3122
3122
|
if (!isPlainRecord(error)) return null;
|
|
3123
|
+
if (typeof error.message === "string" && error.message.trim().length > 0) return error.message.trim();
|
|
3123
3124
|
if (isPlainRecord(error.data) && typeof error.data.message === "string" && error.data.message.trim().length > 0) return error.data.message.trim();
|
|
3124
3125
|
return asNonEmptyString(error.name);
|
|
3125
3126
|
}
|
|
3126
3127
|
function normalizeForegroundSessionError(error) {
|
|
3127
3128
|
if (error instanceof Error) return error;
|
|
3128
|
-
if (isPlainRecord(error)
|
|
3129
|
+
if (isPlainRecord(error)) {
|
|
3129
3130
|
const normalized = new Error(extractSessionErrorMessage(error) ?? "Unknown session error.");
|
|
3130
|
-
|
|
3131
|
+
const normalizedName = asNonEmptyString(error.name);
|
|
3132
|
+
if (normalizedName) normalized.name = normalizedName;
|
|
3131
3133
|
if (isPlainRecord(error.data)) normalized.data = error.data;
|
|
3132
3134
|
return normalized;
|
|
3133
3135
|
}
|
|
@@ -3920,14 +3922,18 @@ function normalizeError(error, copy) {
|
|
|
3920
3922
|
message: copy.errors.contextOverflow,
|
|
3921
3923
|
cause: extractMessage(error.data) ?? null
|
|
3922
3924
|
};
|
|
3923
|
-
if (isNamedError(error, "APIError"))
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3925
|
+
if (isNamedError(error, "APIError")) {
|
|
3926
|
+
const providerMessage = extractMessage(error.data);
|
|
3927
|
+
return {
|
|
3928
|
+
message: copy.errors.providerRequest,
|
|
3929
|
+
cause: joinNonEmptyParts([
|
|
3930
|
+
getProviderCompatibilityHint(providerMessage),
|
|
3931
|
+
providerMessage,
|
|
3932
|
+
extractStatusCode(error.data, copy),
|
|
3933
|
+
extractRetryable(error.data, copy)
|
|
3934
|
+
])
|
|
3935
|
+
};
|
|
3936
|
+
}
|
|
3931
3937
|
if (isNamedError(error, "NotFoundError")) return {
|
|
3932
3938
|
message: copy.errors.notFound,
|
|
3933
3939
|
cause: extractMessage(error.data) ?? null
|
|
@@ -3945,6 +3951,10 @@ function normalizeError(error, copy) {
|
|
|
3945
3951
|
cause: extractMessage(error) ?? stringifyUnknown(error)
|
|
3946
3952
|
};
|
|
3947
3953
|
}
|
|
3954
|
+
function getProviderCompatibilityHint(message) {
|
|
3955
|
+
if (!message) return null;
|
|
3956
|
+
return /tool_choice parameter does not support being set to required or object in thinking mode/iu.test(message) ? "Current model/reasoning mode is incompatible with tool calling. Switch to a compatible model or disable thinking mode." : null;
|
|
3957
|
+
}
|
|
3948
3958
|
function isBadRequestError(error) {
|
|
3949
3959
|
return !!error && typeof error === "object" && "success" in error && error.success === false;
|
|
3950
3960
|
}
|
|
@@ -5837,14 +5847,15 @@ function getTelegramBotRuntimeRegistry() {
|
|
|
5837
5847
|
//#region src/plugin.ts
|
|
5838
5848
|
async function ensureTelegramBotPluginRuntime(options) {
|
|
5839
5849
|
const runtimeStateHolder = getTelegramBotPluginRuntimeStateHolder();
|
|
5840
|
-
const
|
|
5841
|
-
if (runtimeStateHolder.state && runtimeStateHolder.state.
|
|
5850
|
+
const explicitCwd = resolveExplicitPluginRuntimeCwd(options.context);
|
|
5851
|
+
if (runtimeStateHolder.state && explicitCwd === null) return runtimeStateHolder.state.runtimePromise;
|
|
5852
|
+
if (runtimeStateHolder.state && explicitCwd !== null && runtimeStateHolder.state.cwd !== explicitCwd) {
|
|
5842
5853
|
const activeState = runtimeStateHolder.state;
|
|
5843
5854
|
runtimeStateHolder.state = null;
|
|
5844
5855
|
await disposeTelegramBotPluginRuntimeState(activeState);
|
|
5845
5856
|
}
|
|
5846
5857
|
if (!runtimeStateHolder.state) {
|
|
5847
|
-
const runtimePromise = startPluginRuntime(options,
|
|
5858
|
+
const runtimePromise = startPluginRuntime(options, resolvePluginRuntimeCwd(options.context), requirePluginClient(options.context)).then((runtime) => {
|
|
5848
5859
|
if (runtimeStateHolder.state?.runtimePromise === runtimePromise) runtimeStateHolder.state.runtime = runtime;
|
|
5849
5860
|
return runtime;
|
|
5850
5861
|
}).catch((error) => {
|
|
@@ -5852,7 +5863,7 @@ async function ensureTelegramBotPluginRuntime(options) {
|
|
|
5852
5863
|
throw error;
|
|
5853
5864
|
});
|
|
5854
5865
|
runtimeStateHolder.state = {
|
|
5855
|
-
cwd,
|
|
5866
|
+
cwd: explicitCwd ?? resolvePluginRuntimeCwd(options.context),
|
|
5856
5867
|
runtime: null,
|
|
5857
5868
|
runtimePromise
|
|
5858
5869
|
};
|
|
@@ -5869,7 +5880,7 @@ async function resetTelegramBotPluginRuntimeForTests() {
|
|
|
5869
5880
|
runtimeStateHolder.state = null;
|
|
5870
5881
|
await disposeTelegramBotPluginRuntimeState(activeState);
|
|
5871
5882
|
}
|
|
5872
|
-
async function startPluginRuntime(options, cwd) {
|
|
5883
|
+
async function startPluginRuntime(options, cwd, client) {
|
|
5873
5884
|
const bootstrapApp = options.bootstrapApp ?? bootstrapPluginApp;
|
|
5874
5885
|
const prepareConfiguration = options.prepareConfiguration ?? preparePluginConfiguration;
|
|
5875
5886
|
const startRuntime = options.startRuntime ?? startTelegramBotRuntime;
|
|
@@ -5877,7 +5888,7 @@ async function startPluginRuntime(options, cwd) {
|
|
|
5877
5888
|
cwd,
|
|
5878
5889
|
config: options.config
|
|
5879
5890
|
});
|
|
5880
|
-
const { config, container } = bootstrapApp(
|
|
5891
|
+
const { config, container } = bootstrapApp(client, preparedConfiguration.config, { cwd: preparedConfiguration.cwd });
|
|
5881
5892
|
try {
|
|
5882
5893
|
if (preparedConfiguration.ignoredProjectConfigFilePath) container.logger.child({ component: "runtime" }).warn({
|
|
5883
5894
|
cwd: preparedConfiguration.cwd,
|
|
@@ -5904,7 +5915,19 @@ async function startPluginRuntime(options, cwd) {
|
|
|
5904
5915
|
}
|
|
5905
5916
|
}
|
|
5906
5917
|
function resolvePluginRuntimeCwd(context) {
|
|
5907
|
-
return context
|
|
5918
|
+
return resolveExplicitPluginRuntimeCwd(context) ?? process.cwd();
|
|
5919
|
+
}
|
|
5920
|
+
function resolveExplicitPluginRuntimeCwd(context) {
|
|
5921
|
+
return normalizePluginRuntimePath(context?.worktree) ?? normalizePluginRuntimePath(context?.directory);
|
|
5922
|
+
}
|
|
5923
|
+
function requirePluginClient(context) {
|
|
5924
|
+
if (context?.client) return context.client;
|
|
5925
|
+
throw new Error("OpenCode plugin context.client is required.");
|
|
5926
|
+
}
|
|
5927
|
+
function normalizePluginRuntimePath(value) {
|
|
5928
|
+
if (typeof value !== "string") return null;
|
|
5929
|
+
const normalized = value.trim();
|
|
5930
|
+
return normalized.length > 0 ? normalized : null;
|
|
5908
5931
|
}
|
|
5909
5932
|
async function disposeTelegramBotPluginRuntimeState(state) {
|
|
5910
5933
|
await (state.runtime ?? await state.runtimePromise.catch(() => null))?.dispose();
|