opencode-tbot 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 +24 -72
- package/README.zh-CN.md +25 -73
- package/dist/assets/{plugin-config-Crgl_PZz.js → plugin-config-BYsYAzvx.js} +6 -45
- package/dist/assets/plugin-config-BYsYAzvx.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.js +276 -152
- package/dist/plugin.js.map +1 -1
- package/package.json +2 -3
- package/INSTALL.md +0 -92
- package/dist/assets/plugin-config-Crgl_PZz.js.map +0 -1
package/README.md
CHANGED
|
@@ -17,17 +17,7 @@ A Telegram plugin for driving [OpenCode](https://opencode.ai) from chat.
|
|
|
17
17
|
- Session completion and error events can be reported back to the bound Telegram chat.
|
|
18
18
|
- Chat state is stored in a JSON state file that works in both Node and Bun runtimes.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## Installation
|
|
23
|
-
|
|
24
|
-
### Requirements
|
|
25
|
-
|
|
26
|
-
- OpenCode must be installed and able to load plugins.
|
|
27
|
-
- Node.js 22.12.0 or newer is required for local builds and development.
|
|
28
|
-
- You need a Telegram bot token from BotFather.
|
|
29
|
-
|
|
30
|
-
### Recommended Install Flow
|
|
20
|
+
## Install
|
|
31
21
|
|
|
32
22
|
Run:
|
|
33
23
|
|
|
@@ -35,38 +25,7 @@ Run:
|
|
|
35
25
|
npx opencode-tbot@latest install
|
|
36
26
|
```
|
|
37
27
|
|
|
38
|
-
The installer
|
|
39
|
-
|
|
40
|
-
1. register `opencode-tbot@latest` in `~/.config/opencode/opencode.json`
|
|
41
|
-
2. ask for your Telegram bot token
|
|
42
|
-
3. ask whether voice transcription should be enabled
|
|
43
|
-
4. ask for an OpenRouter API key if voice transcription is enabled
|
|
44
|
-
5. write plugin defaults to `~/.config/opencode/opencode-tbot/config.json`
|
|
45
|
-
|
|
46
|
-
Restart OpenCode after installation, then message the bot with `/start` or `/status`.
|
|
47
|
-
|
|
48
|
-
### Non-Interactive Install
|
|
49
|
-
|
|
50
|
-
For CI or scripted setup:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npx opencode-tbot@latest install \
|
|
54
|
-
--bot-token <telegram-token> \
|
|
55
|
-
--disable-voice
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
If voice transcription is enabled, `--openrouter-api-key` is required.
|
|
59
|
-
|
|
60
|
-
Useful flags:
|
|
61
|
-
|
|
62
|
-
- `--enable-voice`
|
|
63
|
-
- `--disable-voice`
|
|
64
|
-
- `--openrouter-api-key <key>`
|
|
65
|
-
- `--telegram-api-root <url>`
|
|
66
|
-
- `--skip-register`
|
|
67
|
-
- `--home-dir <path>`
|
|
68
|
-
|
|
69
|
-
`--skip-register` is mainly for tests or local packaging flows where plugin registration is handled separately.
|
|
28
|
+
The installer registers the plugin globally and writes the default runtime config.
|
|
70
29
|
|
|
71
30
|
## Configuration
|
|
72
31
|
|
|
@@ -74,7 +33,6 @@ The runtime config is loaded in this order:
|
|
|
74
33
|
|
|
75
34
|
1. global defaults from `~/.config/opencode/opencode-tbot/config.json`
|
|
76
35
|
2. project overrides from `<worktree>/tbot.config.json`
|
|
77
|
-
3. legacy project filename `<worktree>/opencode-tbot.config.json` if `tbot.config.json` is absent
|
|
78
36
|
|
|
79
37
|
Project config is merged on top of the global config. `telegram`, `state`, and `openrouter` are deep-merged by section.
|
|
80
38
|
|
|
@@ -108,25 +66,34 @@ Project config is merged on top of the global config. `telegram`, `state`, and `
|
|
|
108
66
|
| `telegram.allowedChatIds` | No | `[]` | Allowed Telegram chat IDs. If empty, the bot accepts messages from any chat. |
|
|
109
67
|
| `telegram.apiRoot` | No | `https://api.telegram.org` | Telegram Bot API base URL. Useful for tests or self-hosted gateways. |
|
|
110
68
|
| `state.path` | No | `./data/opencode-tbot.state.json` | JSON state file path, resolved relative to the current OpenCode worktree. |
|
|
111
|
-
| `database.path` | Legacy | - | Backward-compatible alias for `state.path`. No sqlite migration is performed. |
|
|
112
69
|
| `openrouter.apiKey` | No | `""` | OpenRouter API key. Required only when voice transcription is enabled. |
|
|
113
70
|
| `openrouter.model` | No | `openai/gpt-audio-mini` | OpenRouter model for voice transcription. |
|
|
114
71
|
| `openrouter.timeoutMs` | No | `30000` | Voice transcription timeout in milliseconds. |
|
|
115
72
|
| `openrouter.transcriptionPrompt` | No | `""` | Optional extra instruction appended to the transcription prompt. |
|
|
116
73
|
| `logLevel` | No | `info` | Plugin log level. Logs are emitted through `client.app.log()`. |
|
|
117
74
|
|
|
118
|
-
##
|
|
75
|
+
## Runtime Expectations
|
|
76
|
+
|
|
77
|
+
Required:
|
|
78
|
+
|
|
79
|
+
- `telegram.botToken`
|
|
80
|
+
|
|
81
|
+
Optional:
|
|
82
|
+
|
|
83
|
+
- `telegram.allowedChatIds`
|
|
84
|
+
- `telegram.apiRoot`
|
|
85
|
+
- `state.path`
|
|
86
|
+
- `openrouter.apiKey`
|
|
87
|
+
- `openrouter.model`
|
|
88
|
+
- `openrouter.timeoutMs`
|
|
89
|
+
- `openrouter.transcriptionPrompt`
|
|
90
|
+
- `logLevel`
|
|
91
|
+
|
|
92
|
+
Notes:
|
|
119
93
|
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
- Create and switch OpenCode sessions in chat
|
|
124
|
-
- View and switch agents
|
|
125
|
-
- View and switch models and reasoning levels
|
|
126
|
-
- Approve or reject OpenCode permission requests from Telegram
|
|
127
|
-
- Receive session error and idle notifications in Telegram
|
|
128
|
-
- Restrict access with an optional Telegram allowlist
|
|
129
|
-
- Persist chat bindings and pending actions in a JSON state file
|
|
94
|
+
- `state.path` defaults to `./data/opencode-tbot.state.json` and is resolved relative to the current OpenCode worktree.
|
|
95
|
+
- Logs are emitted through `client.app.log()`.
|
|
96
|
+
- Permission approvals and session notifications are handled through plugin hooks.
|
|
130
97
|
|
|
131
98
|
## Commands
|
|
132
99
|
|
|
@@ -142,7 +109,7 @@ Project config is merged on top of the global config. `telegram`, `state`, and `
|
|
|
142
109
|
|
|
143
110
|
Any non-command text message is treated as a prompt and sent to OpenCode. Telegram `voice` messages follow the same prompt flow after transcription when OpenRouter is configured. Telegram images are forwarded as OpenCode file parts.
|
|
144
111
|
|
|
145
|
-
##
|
|
112
|
+
## Development
|
|
146
113
|
|
|
147
114
|
Build the plugin bundle:
|
|
148
115
|
|
|
@@ -164,17 +131,6 @@ pnpm test
|
|
|
164
131
|
|
|
165
132
|
For local source-based loading in this repository, OpenCode can use [.opencode/plugins/opencode-tbot.ts](./.opencode/plugins/opencode-tbot.ts), which re-exports `src/plugin.ts`.
|
|
166
133
|
|
|
167
|
-
## Deployment
|
|
168
|
-
|
|
169
|
-
Supported deployment modes:
|
|
170
|
-
|
|
171
|
-
- Recommended npm installation through `npx opencode-tbot@latest install`
|
|
172
|
-
- Non-interactive install for CI or scripted environments
|
|
173
|
-
- Local development bridge through `.opencode/plugins/opencode-tbot.ts`
|
|
174
|
-
- Unpublished external-project bridge that re-exports `dist/plugin.js`
|
|
175
|
-
|
|
176
|
-
Deployment details are documented in [docs/deployment.md](./docs/deployment.md).
|
|
177
|
-
|
|
178
134
|
## FAQ
|
|
179
135
|
|
|
180
136
|
### Do I need a running OpenCode instance?
|
|
@@ -184,7 +140,3 @@ Yes. This repository provides a Telegram integration layer and depends on the Op
|
|
|
184
140
|
### Is this an official OpenCode project?
|
|
185
141
|
|
|
186
142
|
No. It integrates with OpenCode, but it is not built by the OpenCode team.
|
|
187
|
-
|
|
188
|
-
### Why is Node.js 22 recommended?
|
|
189
|
-
|
|
190
|
-
The project uses modern Node APIs for the CLI, tests, and local development. Runtime state storage is file-based and works in both Node and Bun-compatible plugin hosts.
|
package/README.zh-CN.md
CHANGED
|
@@ -15,58 +15,17 @@
|
|
|
15
15
|
- Telegram 语音消息可先通过 OpenRouter 转写,再进入正常 prompt 流程。
|
|
16
16
|
- OpenCode 触发的权限请求可以直接在 Telegram 中通过内联按钮批准或拒绝。
|
|
17
17
|
- 会话完成和错误事件可以主动回推到绑定的 Telegram chat。
|
|
18
|
-
- 聊天状态通过 JSON
|
|
19
|
-
|
|
20
|
-
当前仓库以 OpenCode 插件形式运行,不再提供独立 bot 进程。
|
|
18
|
+
- 聊天状态通过 JSON 状态文件持久化,可兼容 Node 和 Bun 运行环境。
|
|
21
19
|
|
|
22
20
|
## 安装
|
|
23
21
|
|
|
24
|
-
### 环境要求
|
|
25
|
-
|
|
26
|
-
- 需要已安装并可加载插件的 OpenCode。
|
|
27
|
-
- 本地构建和开发需要 Node.js 22.12.0 或更高版本。
|
|
28
|
-
- 需要一个由 BotFather 创建的 Telegram bot token。
|
|
29
|
-
|
|
30
|
-
### 推荐安装方式
|
|
31
|
-
|
|
32
22
|
执行:
|
|
33
23
|
|
|
34
24
|
```bash
|
|
35
25
|
npx opencode-tbot@latest install
|
|
36
26
|
```
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
1. 在 `~/.config/opencode/opencode.json` 中注册 `opencode-tbot@latest`
|
|
41
|
-
2. 提示输入 Telegram bot token
|
|
42
|
-
3. 询问是否启用语音转写
|
|
43
|
-
4. 如果启用语音转写,则继续提示输入 OpenRouter API key
|
|
44
|
-
5. 将插件全局默认配置写入 `~/.config/opencode/opencode-tbot/config.json`
|
|
45
|
-
|
|
46
|
-
安装完成后重启 OpenCode,再向 bot 发送 `/start` 或 `/status` 验证即可。
|
|
47
|
-
|
|
48
|
-
### 非交互安装
|
|
49
|
-
|
|
50
|
-
适合 CI 或脚本化环境:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npx opencode-tbot@latest install \
|
|
54
|
-
--bot-token <telegram-token> \
|
|
55
|
-
--disable-voice
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
如果启用了语音转写,则必须同时提供 `--openrouter-api-key`。
|
|
59
|
-
|
|
60
|
-
常用参数:
|
|
61
|
-
|
|
62
|
-
- `--enable-voice`
|
|
63
|
-
- `--disable-voice`
|
|
64
|
-
- `--openrouter-api-key <key>`
|
|
65
|
-
- `--telegram-api-root <url>`
|
|
66
|
-
- `--skip-register`
|
|
67
|
-
- `--home-dir <path>`
|
|
68
|
-
|
|
69
|
-
`--skip-register` 主要用于测试或本地打包流程,此时插件注册由外部步骤负责。
|
|
28
|
+
安装器会注册全局插件并写入默认运行时配置。
|
|
70
29
|
|
|
71
30
|
## 配置
|
|
72
31
|
|
|
@@ -74,7 +33,6 @@ npx opencode-tbot@latest install \
|
|
|
74
33
|
|
|
75
34
|
1. 全局默认配置 `~/.config/opencode/opencode-tbot/config.json`
|
|
76
35
|
2. 项目覆盖配置 `<worktree>/tbot.config.json`
|
|
77
|
-
3. 如果不存在 `tbot.config.json`,则兼容旧文件名 `<worktree>/opencode-tbot.config.json`
|
|
78
36
|
|
|
79
37
|
项目配置会覆盖全局默认值;`telegram`、`state`、`openrouter` 这些分段配置会进行深合并。
|
|
80
38
|
|
|
@@ -108,25 +66,34 @@ npx opencode-tbot@latest install \
|
|
|
108
66
|
| `telegram.allowedChatIds` | 否 | `[]` | 允许访问的 Telegram chat ID 数组。为空时表示接受任意 chat。 |
|
|
109
67
|
| `telegram.apiRoot` | 否 | `https://api.telegram.org` | Telegram Bot API 根地址,适合测试或自托管网关。 |
|
|
110
68
|
| `state.path` | 否 | `./data/opencode-tbot.state.json` | JSON 状态文件路径,相对当前 OpenCode worktree 解析。 |
|
|
111
|
-
| `database.path` | 兼容字段 | - | `state.path` 的旧别名,仅做兼容映射,不迁移 sqlite 数据。 |
|
|
112
69
|
| `openrouter.apiKey` | 否 | `""` | OpenRouter API key。仅在启用语音转写时需要。 |
|
|
113
70
|
| `openrouter.model` | 否 | `openai/gpt-audio-mini` | 语音转写使用的 OpenRouter 模型。 |
|
|
114
71
|
| `openrouter.timeoutMs` | 否 | `30000` | 语音转写超时时间,单位毫秒。 |
|
|
115
72
|
| `openrouter.transcriptionPrompt` | 否 | `""` | 追加到内置转写提示词后的可选说明。 |
|
|
116
73
|
| `logLevel` | 否 | `info` | 插件日志级别。日志统一通过 `client.app.log()` 上报。 |
|
|
117
74
|
|
|
118
|
-
##
|
|
75
|
+
## 运行时约定
|
|
76
|
+
|
|
77
|
+
必填:
|
|
78
|
+
|
|
79
|
+
- `telegram.botToken`
|
|
80
|
+
|
|
81
|
+
可选:
|
|
82
|
+
|
|
83
|
+
- `telegram.allowedChatIds`
|
|
84
|
+
- `telegram.apiRoot`
|
|
85
|
+
- `state.path`
|
|
86
|
+
- `openrouter.apiKey`
|
|
87
|
+
- `openrouter.model`
|
|
88
|
+
- `openrouter.timeoutMs`
|
|
89
|
+
- `openrouter.transcriptionPrompt`
|
|
90
|
+
- `logLevel`
|
|
91
|
+
|
|
92
|
+
说明:
|
|
119
93
|
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
123
|
-
- 在聊天中创建和切换 OpenCode 会话
|
|
124
|
-
- 查看和切换 agent
|
|
125
|
-
- 查看和切换模型与推理等级
|
|
126
|
-
- 在 Telegram 中审批或拒绝 OpenCode 权限请求
|
|
127
|
-
- 接收会话错误和空闲通知
|
|
128
|
-
- 通过 Telegram allowlist 限制访问
|
|
129
|
-
- 使用 JSON 状态文件持久化聊天绑定和待处理动作
|
|
94
|
+
- `state.path` 默认是 `./data/opencode-tbot.state.json`,并相对当前 OpenCode worktree 解析
|
|
95
|
+
- 日志通过 `client.app.log()` 统一输出
|
|
96
|
+
- 权限审批和会话通知由插件 hook 处理
|
|
130
97
|
|
|
131
98
|
## 命令
|
|
132
99
|
|
|
@@ -140,9 +107,9 @@ npx opencode-tbot@latest install \
|
|
|
140
107
|
- `/model` 或 `/models` 列出可用模型并切换当前模型
|
|
141
108
|
- `/language` 切换 bot 显示语言
|
|
142
109
|
|
|
143
|
-
任意非命令文本都会被当作 prompt 发送给 OpenCode。配置了 OpenRouter 后,Telegram `voice`
|
|
110
|
+
任意非命令文本都会被当作 prompt 发送给 OpenCode。配置了 OpenRouter 后,Telegram `voice` 消息会先转写再进入同一条 prompt 流程。图片会作为 OpenCode 文件片段上传。
|
|
144
111
|
|
|
145
|
-
##
|
|
112
|
+
## 开发
|
|
146
113
|
|
|
147
114
|
构建插件:
|
|
148
115
|
|
|
@@ -164,17 +131,6 @@ pnpm test
|
|
|
164
131
|
|
|
165
132
|
在本仓库中做源码调试时,OpenCode 可以通过 [.opencode/plugins/opencode-tbot.ts](./.opencode/plugins/opencode-tbot.ts) 直接加载 `src/plugin.ts`。
|
|
166
133
|
|
|
167
|
-
## 部署
|
|
168
|
-
|
|
169
|
-
支持的部署模式:
|
|
170
|
-
|
|
171
|
-
- 通过 `npx opencode-tbot@latest install` 的推荐安装流
|
|
172
|
-
- 面向 CI 或脚本环境的非交互安装
|
|
173
|
-
- 通过 `.opencode/plugins/opencode-tbot.ts` 的本地开发桥接
|
|
174
|
-
- 在外部项目中通过 re-export `dist/plugin.js` 的构建产物桥接
|
|
175
|
-
|
|
176
|
-
更完整的部署说明见 [docs/deployment.md](./docs/deployment.md)。
|
|
177
|
-
|
|
178
134
|
## 常见问题
|
|
179
135
|
|
|
180
136
|
### 我需要一个正在运行的 OpenCode 实例吗?
|
|
@@ -184,7 +140,3 @@ pnpm test
|
|
|
184
140
|
### 这是 OpenCode 官方项目吗?
|
|
185
141
|
|
|
186
142
|
不是。它只是与 OpenCode 集成,并非 OpenCode 官方项目。
|
|
187
|
-
|
|
188
|
-
### 为什么仍然推荐 Node.js 22?
|
|
189
|
-
|
|
190
|
-
CLI、测试和本地开发仍然使用现代 Node API。插件运行时的状态存储已经改为文件方案,可兼容 Node 和 Bun 风格的宿主环境。
|
|
@@ -13,20 +13,18 @@ var TelegramConfigSchema = z.preprocess((value) => value ?? {}, z.object({
|
|
|
13
13
|
apiRoot: z.string().trim().url().default(DEFAULT_TELEGRAM_API_ROOT)
|
|
14
14
|
}));
|
|
15
15
|
var StateConfigSchema = z.preprocess((value) => value ?? {}, z.object({ path: z.string().trim().min(1).default(DEFAULT_STATE_FILE_PATH) }));
|
|
16
|
-
var LegacyDatabaseConfigSchema = z.preprocess((value) => value ?? {}, z.object({ path: z.string().trim().min(1).optional() }));
|
|
17
16
|
var OpenRouterConfigSchema = z.preprocess((value) => value ?? {}, z.object({
|
|
18
17
|
apiKey: z.string().default(""),
|
|
19
18
|
model: z.string().default(DEFAULT_OPENROUTER_MODEL),
|
|
20
19
|
timeoutMs: z.coerce.number().int().positive().default(3e4),
|
|
21
20
|
transcriptionPrompt: z.string().default("")
|
|
22
21
|
}));
|
|
23
|
-
var AppConfigSchema = z.
|
|
22
|
+
var AppConfigSchema = z.object({
|
|
24
23
|
telegram: TelegramConfigSchema,
|
|
25
24
|
state: StateConfigSchema,
|
|
26
|
-
database: LegacyDatabaseConfigSchema.optional(),
|
|
27
25
|
openrouter: OpenRouterConfigSchema,
|
|
28
26
|
logLevel: z.string().default("info")
|
|
29
|
-
})
|
|
27
|
+
});
|
|
30
28
|
function loadAppConfig(configSource = {}, options = {}) {
|
|
31
29
|
return buildAppConfig(parseConfig(AppConfigSchema, configSource), options);
|
|
32
30
|
}
|
|
@@ -54,36 +52,20 @@ function normalizeOptionalString(value) {
|
|
|
54
52
|
return normalized.length > 0 ? normalized : null;
|
|
55
53
|
}
|
|
56
54
|
function resolveStatePath(data, cwd) {
|
|
57
|
-
return resolve(cwd, data.state.path ||
|
|
55
|
+
return resolve(cwd, data.state.path || "./data/opencode-tbot.state.json");
|
|
58
56
|
}
|
|
59
57
|
function normalizeApiRoot(value) {
|
|
60
58
|
const normalized = value.trim();
|
|
61
59
|
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
62
60
|
}
|
|
63
|
-
function normalizeLegacyConfigSource(value) {
|
|
64
|
-
if (!isPlainObject$1(value)) return value ?? {};
|
|
65
|
-
const source = value;
|
|
66
|
-
if (source.state?.path || !source.database?.path) return source;
|
|
67
|
-
return {
|
|
68
|
-
...source,
|
|
69
|
-
state: {
|
|
70
|
-
...source.state ?? {},
|
|
71
|
-
path: source.database.path
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
61
|
function parseConfig(schema, configSource) {
|
|
76
62
|
const parsed = schema.safeParse(configSource ?? {});
|
|
77
63
|
if (parsed.success) return parsed.data;
|
|
78
64
|
throw new Error(`Invalid plugin configuration: ${JSON.stringify(parsed.error.flatten())}`);
|
|
79
65
|
}
|
|
80
|
-
function isPlainObject$1(value) {
|
|
81
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
82
|
-
}
|
|
83
66
|
//#endregion
|
|
84
67
|
//#region src/app/plugin-config.ts
|
|
85
68
|
var PLUGIN_CONFIG_FILE_NAME = "tbot.config.json";
|
|
86
|
-
var LEGACY_PLUGIN_CONFIG_FILE_NAME = "opencode-tbot.config.json";
|
|
87
69
|
var GLOBAL_PLUGIN_DIRECTORY_NAME = "opencode-tbot";
|
|
88
70
|
var GLOBAL_PLUGIN_CONFIG_FILE_NAME = "config.json";
|
|
89
71
|
var OPENCODE_CONFIG_FILE_NAME = "opencode.json";
|
|
@@ -118,10 +100,9 @@ function mergePluginConfigSources(...sources) {
|
|
|
118
100
|
const merged = {};
|
|
119
101
|
for (const source of sources) {
|
|
120
102
|
if (!source) continue;
|
|
121
|
-
const normalized =
|
|
103
|
+
const normalized = source;
|
|
122
104
|
const previousTelegram = merged.telegram;
|
|
123
105
|
const previousState = merged.state;
|
|
124
|
-
const previousDatabase = merged.database;
|
|
125
106
|
const previousOpenRouter = merged.openrouter;
|
|
126
107
|
Object.assign(merged, normalized);
|
|
127
108
|
if (normalized.telegram) merged.telegram = {
|
|
@@ -132,10 +113,6 @@ function mergePluginConfigSources(...sources) {
|
|
|
132
113
|
...previousState ?? {},
|
|
133
114
|
...normalized.state
|
|
134
115
|
};
|
|
135
|
-
if (normalized.database) merged.database = {
|
|
136
|
-
...previousDatabase ?? {},
|
|
137
|
-
...normalized.database
|
|
138
|
-
};
|
|
139
116
|
if (normalized.openrouter) merged.openrouter = {
|
|
140
117
|
...previousOpenRouter ?? {},
|
|
141
118
|
...normalized.openrouter
|
|
@@ -167,14 +144,12 @@ function orderPluginConfig(config) {
|
|
|
167
144
|
const prioritizedKeys = new Set([
|
|
168
145
|
"telegram",
|
|
169
146
|
"state",
|
|
170
|
-
"database",
|
|
171
147
|
"openrouter",
|
|
172
148
|
"logLevel"
|
|
173
149
|
]);
|
|
174
150
|
const ordered = {};
|
|
175
151
|
if (config.telegram) ordered.telegram = config.telegram;
|
|
176
152
|
if (config.state) ordered.state = config.state;
|
|
177
|
-
if (config.database) ordered.database = config.database;
|
|
178
153
|
if (config.openrouter) ordered.openrouter = config.openrouter;
|
|
179
154
|
if (config.logLevel !== void 0) ordered.logLevel = config.logLevel;
|
|
180
155
|
for (const [key, value] of Object.entries(config)) if (!prioritizedKeys.has(key)) ordered[key] = value;
|
|
@@ -187,11 +162,7 @@ function isMissingFileError(error) {
|
|
|
187
162
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
188
163
|
}
|
|
189
164
|
async function resolveProjectPluginConfigFilePath(cwd) {
|
|
190
|
-
|
|
191
|
-
if (await pathExists(preferredPath)) return preferredPath;
|
|
192
|
-
const legacyPath = join(cwd, LEGACY_PLUGIN_CONFIG_FILE_NAME);
|
|
193
|
-
if (await pathExists(legacyPath)) return legacyPath;
|
|
194
|
-
return preferredPath;
|
|
165
|
+
return join(cwd, PLUGIN_CONFIG_FILE_NAME);
|
|
195
166
|
}
|
|
196
167
|
async function pathExists(filePath) {
|
|
197
168
|
try {
|
|
@@ -202,17 +173,7 @@ async function pathExists(filePath) {
|
|
|
202
173
|
throw error;
|
|
203
174
|
}
|
|
204
175
|
}
|
|
205
|
-
function normalizePluginConfigSource(source) {
|
|
206
|
-
if (source.state?.path || !source.database?.path) return source;
|
|
207
|
-
return {
|
|
208
|
-
...source,
|
|
209
|
-
state: {
|
|
210
|
-
...source.state ?? {},
|
|
211
|
-
path: source.database.path
|
|
212
|
-
}
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
176
|
//#endregion
|
|
216
177
|
export { writePluginConfigFile as a, preparePluginConfiguration as i, getOpenCodeConfigFilePath as n, DEFAULT_TELEGRAM_API_ROOT as o, mergePluginConfigSources as r, loadAppConfig as s, getGlobalPluginConfigFilePath as t };
|
|
217
178
|
|
|
218
|
-
//# sourceMappingURL=plugin-config-
|
|
179
|
+
//# sourceMappingURL=plugin-config-BYsYAzvx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-config-BYsYAzvx.js","names":[],"sources":["../../src/app/config.ts","../../src/app/plugin-config.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { z } from \"zod\";\n\nexport const DEFAULT_OPENROUTER_MODEL = \"openai/gpt-audio-mini\";\nexport const DEFAULT_STATE_FILE_PATH = \"./data/opencode-tbot.state.json\";\nexport const DEFAULT_TELEGRAM_API_ROOT = \"https://api.telegram.org\";\n\nconst AllowedChatIdSchema = z.union([\n z.number().int(),\n z.string().regex(/^-?\\d+$/u).transform((value) => Number(value)),\n]);\n\nconst TelegramConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n botToken: z.string().trim().min(1),\n allowedChatIds: z.array(AllowedChatIdSchema).default([]),\n apiRoot: z.string().trim().url().default(DEFAULT_TELEGRAM_API_ROOT),\n }),\n);\n\nconst StateConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n path: z.string().trim().min(1).default(DEFAULT_STATE_FILE_PATH),\n }),\n);\n\nconst OpenRouterConfigSchema = z.preprocess(\n (value) => value ?? {},\n z.object({\n apiKey: z.string().default(\"\"),\n model: z.string().default(DEFAULT_OPENROUTER_MODEL),\n timeoutMs: z.coerce.number().int().positive().default(30_000),\n transcriptionPrompt: z.string().default(\"\"),\n }),\n);\n\nconst AppConfigSchema = z.object({\n telegram: TelegramConfigSchema,\n state: StateConfigSchema,\n openrouter: OpenRouterConfigSchema,\n logLevel: z.string().default(\"info\"),\n});\n\nexport interface PluginConfigSource {\n telegram?: {\n botToken?: string;\n allowedChatIds?: Array<number | string>;\n apiRoot?: string;\n [key: string]: unknown;\n };\n state?: {\n path?: string;\n [key: string]: unknown;\n };\n openrouter?: {\n apiKey?: string;\n model?: string;\n timeoutMs?: number;\n transcriptionPrompt?: string;\n [key: string]: unknown;\n };\n logLevel?: string;\n [key: string]: unknown;\n}\n\nexport interface AppOpenRouterConfig {\n configured: boolean;\n apiKey: string | null;\n model: string;\n timeoutMs: number;\n transcriptionPrompt: string | null;\n}\n\nexport interface AppConfig {\n telegramBotToken: string;\n telegramAllowedChatIds: number[];\n telegramApiRoot: string;\n logLevel: string;\n stateFilePath: string;\n openrouter: AppOpenRouterConfig;\n}\n\nexport interface LoadAppConfigOptions {\n cwd?: string;\n}\n\nexport function loadAppConfig(\n configSource: PluginConfigSource | undefined = {},\n options: LoadAppConfigOptions = {},\n): AppConfig {\n const parsed = parseConfig(AppConfigSchema, configSource);\n\n return buildAppConfig(parsed, options);\n}\n\nexport const loadPluginConfig = loadAppConfig;\n\nfunction buildAppConfig(\n data: z.infer<typeof AppConfigSchema>,\n options: LoadAppConfigOptions,\n): AppConfig {\n const openRouterApiKey = normalizeOptionalString(data.openrouter.apiKey);\n const openRouterModel = normalizeOptionalString(data.openrouter.model) ?? DEFAULT_OPENROUTER_MODEL;\n const transcriptionPrompt = normalizeOptionalString(data.openrouter.transcriptionPrompt);\n\n return {\n telegramBotToken: data.telegram.botToken,\n telegramAllowedChatIds: data.telegram.allowedChatIds,\n telegramApiRoot: normalizeApiRoot(data.telegram.apiRoot),\n logLevel: data.logLevel,\n stateFilePath: resolveStatePath(data, options.cwd ?? process.cwd()),\n openrouter: {\n configured: !!openRouterApiKey,\n apiKey: openRouterApiKey,\n model: openRouterModel,\n timeoutMs: data.openrouter.timeoutMs,\n transcriptionPrompt,\n },\n };\n}\n\nfunction normalizeOptionalString(value: string): string | null {\n const normalized = value.trim();\n\n return normalized.length > 0 ? normalized : null;\n}\n\nfunction resolveStatePath(\n data: z.infer<typeof AppConfigSchema>,\n cwd: string,\n): string {\n return resolve(cwd, data.state.path || DEFAULT_STATE_FILE_PATH);\n}\n\nfunction normalizeApiRoot(value: string): string {\n const normalized = value.trim();\n\n return normalized.endsWith(\"/\")\n ? normalized.slice(0, -1)\n : normalized;\n}\n\nfunction parseConfig<TSchema extends z.ZodTypeAny>(\n schema: TSchema,\n configSource: PluginConfigSource | undefined,\n): z.infer<TSchema> {\n const parsed = schema.safeParse(configSource ?? {});\n\n if (parsed.success) {\n return parsed.data;\n }\n\n throw new Error(\n `Invalid plugin configuration: ${JSON.stringify(parsed.error.flatten())}`,\n );\n}\n","import { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { PluginConfigSource } from \"./config.js\";\n\nexport const PLUGIN_CONFIG_FILE_NAME = \"tbot.config.json\";\nexport const GLOBAL_PLUGIN_DIRECTORY_NAME = \"opencode-tbot\";\nexport const GLOBAL_PLUGIN_CONFIG_FILE_NAME = \"config.json\";\nexport const OPENCODE_CONFIG_FILE_NAME = \"opencode.json\";\n\nexport interface PreparedPluginConfiguration {\n cwd: string;\n config: PluginConfigSource;\n globalConfigFilePath: string;\n projectConfigFilePath: string;\n configFilePath: string;\n}\n\nexport interface PreparePluginConfigurationOptions {\n cwd: string;\n config?: PluginConfigSource;\n homeDir?: string;\n}\n\nexport async function preparePluginConfiguration(\n options: PreparePluginConfigurationOptions,\n): Promise<PreparedPluginConfiguration> {\n const homeDir = options.homeDir ?? homedir();\n const globalConfigFilePath = getGlobalPluginConfigFilePath(homeDir);\n const projectConfigFilePath = await resolveProjectPluginConfigFilePath(options.cwd);\n const [globalConfig, projectConfig] = await Promise.all([\n loadPluginConfigFile(globalConfigFilePath),\n loadPluginConfigFile(projectConfigFilePath),\n ]);\n const config = mergePluginConfigSources(globalConfig, projectConfig, options.config);\n const configFilePath = await pathExists(projectConfigFilePath)\n ? projectConfigFilePath\n : globalConfigFilePath;\n\n return {\n cwd: options.cwd,\n config,\n globalConfigFilePath,\n projectConfigFilePath,\n configFilePath,\n };\n}\n\nexport function getOpenCodeConfigDirectory(homeDir: string = homedir()): string {\n return join(homeDir, \".config\", \"opencode\");\n}\n\nexport function getOpenCodeConfigFilePath(homeDir: string = homedir()): string {\n return join(getOpenCodeConfigDirectory(homeDir), OPENCODE_CONFIG_FILE_NAME);\n}\n\nexport function getGlobalPluginConfigFilePath(homeDir: string = homedir()): string {\n return join(\n getOpenCodeConfigDirectory(homeDir),\n GLOBAL_PLUGIN_DIRECTORY_NAME,\n GLOBAL_PLUGIN_CONFIG_FILE_NAME,\n );\n}\n\nexport async function writePluginConfigFile(\n configFilePath: string,\n config: PluginConfigSource,\n): Promise<void> {\n await mkdir(dirname(configFilePath), { recursive: true });\n await writeFile(configFilePath, serializePluginConfig(config), \"utf8\");\n}\n\nexport function mergePluginConfigSources(\n ...sources: Array<PluginConfigSource | undefined>\n): PluginConfigSource {\n const merged: PluginConfigSource = {};\n\n for (const source of sources) {\n if (!source) {\n continue;\n }\n\n const normalized = source;\n const previousTelegram = merged.telegram;\n const previousState = merged.state;\n const previousOpenRouter = merged.openrouter;\n\n Object.assign(merged, normalized);\n\n if (normalized.telegram) {\n merged.telegram = {\n ...(previousTelegram ?? {}),\n ...normalized.telegram,\n };\n }\n\n if (normalized.state) {\n merged.state = {\n ...(previousState ?? {}),\n ...normalized.state,\n };\n }\n\n if (normalized.openrouter) {\n merged.openrouter = {\n ...(previousOpenRouter ?? {}),\n ...normalized.openrouter,\n };\n }\n }\n\n return merged;\n}\n\nexport function serializePluginConfig(config: PluginConfigSource): string {\n return `${JSON.stringify(orderPluginConfig(config), null, 2)}\\n`;\n}\n\nasync function loadPluginConfigFile(configFilePath: string): Promise<PluginConfigSource> {\n try {\n const content = await readFile(configFilePath, \"utf8\");\n\n return parsePluginConfigText(content, configFilePath);\n } catch (error) {\n if (isMissingFileError(error)) {\n return {};\n }\n\n throw error;\n }\n}\n\nfunction parsePluginConfigText(\n content: string,\n configFilePath: string,\n): PluginConfigSource {\n try {\n const parsed = JSON.parse(content) as unknown;\n\n if (!isPlainObject(parsed)) {\n throw new Error(\"Config root must be a JSON object.\");\n }\n\n return parsed as PluginConfigSource;\n } catch (error) {\n throw new Error(\n [\n `Failed to parse ${configFilePath} as JSON.`,\n error instanceof Error ? error.message : String(error),\n ].join(\" \"),\n );\n }\n}\n\nfunction orderPluginConfig(config: PluginConfigSource): PluginConfigSource {\n const prioritizedKeys = new Set([\n \"telegram\",\n \"state\",\n \"openrouter\",\n \"logLevel\",\n ]);\n const ordered: PluginConfigSource = {};\n\n if (config.telegram) {\n ordered.telegram = config.telegram;\n }\n\n if (config.state) {\n ordered.state = config.state;\n }\n\n if (config.openrouter) {\n ordered.openrouter = config.openrouter;\n }\n\n if (config.logLevel !== undefined) {\n ordered.logLevel = config.logLevel;\n }\n\n for (const [key, value] of Object.entries(config)) {\n if (!prioritizedKeys.has(key)) {\n ordered[key] = value;\n }\n }\n\n return ordered;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isMissingFileError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n\nasync function resolveProjectPluginConfigFilePath(cwd: string): Promise<string> {\n const preferredPath = join(cwd, PLUGIN_CONFIG_FILE_NAME);\n\n return preferredPath;\n}\n\nasync function pathExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath);\n return true;\n } catch (error) {\n if (isMissingFileError(error)) {\n return false;\n }\n\n throw error;\n }\n}\n"],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as writePluginConfigFile, n as getOpenCodeConfigFilePath, r as mergePluginConfigSources, t as getGlobalPluginConfigFilePath } from "./assets/plugin-config-
|
|
1
|
+
import { a as writePluginConfigFile, n as getOpenCodeConfigFilePath, r as mergePluginConfigSources, t as getGlobalPluginConfigFilePath } from "./assets/plugin-config-BYsYAzvx.js";
|
|
2
2
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname } from "node:path";
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./assets/plugin-config-
|
|
1
|
+
import "./assets/plugin-config-BYsYAzvx.js";
|
|
2
2
|
import { TelegramBotPlugin, ensureTelegramBotPluginRuntime, resetTelegramBotPluginRuntimeForTests } from "./plugin.js";
|
|
3
3
|
export { TelegramBotPlugin, TelegramBotPlugin as default, ensureTelegramBotPluginRuntime, resetTelegramBotPluginRuntimeForTests };
|