opencode-chat-channel 1.1.0 → 1.2.0

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 CHANGED
@@ -47,7 +47,26 @@ Edit `~/.config/opencode/opencode.json` and add the plugin:
47
47
 
48
48
  opencode will pull and install the package automatically on next startup.
49
49
 
50
- #### Step 2: Configure the channel(s) you want to use
50
+ #### Step 2: Select channels to enable
51
+
52
+ Add `CHAT_CHANNELS` to `~/.config/opencode/.env` to control which channels are active:
53
+
54
+ ```bash
55
+ # ~/.config/opencode/.env
56
+
57
+ # Enable Feishu only (recommended to start)
58
+ CHAT_CHANNELS=feishu
59
+
60
+ # Enable multiple channels at once
61
+ # CHAT_CHANNELS=feishu,wecom
62
+
63
+ # Leave unset or empty = auto mode: any channel with valid credentials starts automatically
64
+ # CHAT_CHANNELS=
65
+ ```
66
+
67
+ Then configure credentials for each enabled channel (see sections below).
68
+
69
+ #### Step 3: Configure channel credentials
51
70
 
52
71
  See the [Feishu Configuration](#feishu-configuration) section below.
53
72
 
@@ -205,7 +224,26 @@ opencode AI (Sisyphus)
205
224
 
206
225
  下次启动 opencode 时会自动拉取并安装。
207
226
 
208
- #### 第二步:配置需要使用的渠道
227
+ #### 第二步:选择要启用的渠道
228
+
229
+ 在 `~/.config/opencode/.env` 中配置 `CHAT_CHANNELS`,指定要开启哪些渠道:
230
+
231
+ ```bash
232
+ # ~/.config/opencode/.env
233
+
234
+ # 只开启飞书(初始推荐)
235
+ CHAT_CHANNELS=feishu
236
+
237
+ # 同时开启多个渠道
238
+ # CHAT_CHANNELS=feishu,wecom
239
+
240
+ # 留空或不配置 = 自动模式:凭证存在的渠道自动启用
241
+ # CHAT_CHANNELS=
242
+ ```
243
+
244
+ 然后配置对应渠道的凭证(见下方各渠道配置说明)。
245
+
246
+ #### 第三步:配置渠道凭证
209
247
 
210
248
  参见下方各渠道的配置说明。
211
249
 
package/dist/index.d.ts CHANGED
@@ -1,19 +1,21 @@
1
1
  /**
2
2
  * opencode-chat-channel — opencode 多渠道机器人插件
3
3
  *
4
- * 支持多个即时通讯渠道同时运行,每个渠道独立处理消息。
5
- * 当前已实现:飞书(Feishu/Lark)
6
- * 骨架已创建:企业微信(WeCom)
4
+ * 通过 .env 文件中的 CHAT_CHANNELS 配置项选择启用哪些渠道:
7
5
  *
8
- * 凭证加载:
9
- * FEISHU_APP_ID 等非敏感凭证存放在 ~/.config/opencode/.env
10
- * 敏感凭证存放在 macOS Keychain(各渠道独立 service/account)
6
+ * CHAT_CHANNELS=feishu # 只启用飞书
7
+ * CHAT_CHANNELS=feishu,wecom # 同时启用飞书和企业微信
8
+ * CHAT_CHANNELS= # 留空:自动探测(凭证存在即启用)
9
+ * # 不配置此项:同留空,自动探测
11
10
  *
12
- * 每个渠道用户独享一个 opencode session,对话历史保留 2 小时。
11
+ * 其他配置项:
12
+ * OPENCODE_BASE_URL opencode API 地址(默认 http://localhost:4321)
13
+ *
14
+ * 各渠道的凭证配置详见 README。
13
15
  */
14
16
  import type { Plugin } from "@opencode-ai/plugin";
15
17
  export declare const ChatChannelPlugin: Plugin;
16
18
  export default ChatChannelPlugin;
17
- export type { ChatChannel, ChannelFactory, IncomingMessage, PluginClient } from "./types.js";
19
+ export type { ChatChannel, ChannelFactory, ChannelName, IncomingMessage, PluginClient } from "./types.js";
18
20
  export { SessionManager, extractResponseText, loadDotEnv } from "./session-manager.js";
19
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAgGlD,eAAO,MAAM,iBAAiB,EAAE,MAoE/B,CAAC;AAEF,eAAe,iBAAiB,CAAC;AAGjC,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAgIlD,eAAO,MAAM,iBAAiB,EAAE,MAyF/B,CAAC;AAEF,eAAe,iBAAiB,CAAC;AAGjC,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1G,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -261,11 +261,32 @@ var wecomChannelFactory = async (client) => {
261
261
  };
262
262
 
263
263
  // src/index.ts
264
- var OPENCODE_BASE_URL = process.env["OPENCODE_BASE_URL"] ?? "http://localhost:4321";
265
- var CHANNEL_FACTORIES = [
266
- feishuChannelFactory,
267
- wecomChannelFactory
268
- ];
264
+ var CHANNEL_REGISTRY = {
265
+ feishu: feishuChannelFactory,
266
+ wecom: wecomChannelFactory
267
+ };
268
+ function resolveEnabledChannels(client) {
269
+ const raw = process.env["CHAT_CHANNELS"]?.trim();
270
+ if (!raw)
271
+ return null;
272
+ const requested = raw.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
273
+ const known = Object.keys(CHANNEL_REGISTRY);
274
+ const enabled = [];
275
+ for (const name of requested) {
276
+ if (known.includes(name)) {
277
+ enabled.push(name);
278
+ } else {
279
+ client.app.log({
280
+ body: {
281
+ service: "chat-channel",
282
+ level: "warn",
283
+ message: `[config] 未知渠道名 "${name}",已忽略。可用渠道:${known.join(", ")}`
284
+ }
285
+ });
286
+ }
287
+ }
288
+ return enabled;
289
+ }
269
290
  function createMessageHandler(channel, sessionManager, client) {
270
291
  return async (msg) => {
271
292
  const { userId, replyTarget, text } = msg;
@@ -313,18 +334,30 @@ function createMessageHandler(channel, sessionManager, client) {
313
334
  var ChatChannelPlugin = async ({ client }) => {
314
335
  const configDir = join(process.env["HOME"] ?? `/Users/${process.env["USER"] ?? "unknown"}`, ".config", "opencode");
315
336
  loadDotEnv(join(configDir, ".env"));
337
+ const enabledNames = resolveEnabledChannels(client);
338
+ const factories = enabledNames ? enabledNames.map((name) => [name, CHANNEL_REGISTRY[name]]) : Object.entries(CHANNEL_REGISTRY);
339
+ if (enabledNames) {
340
+ await client.app.log({
341
+ body: {
342
+ service: "chat-channel",
343
+ level: "info",
344
+ message: `[config] CHAT_CHANNELS="${process.env["CHAT_CHANNELS"]}",将启用: ${enabledNames.join(", ") || "(无)"}`
345
+ }
346
+ });
347
+ }
316
348
  const channels = [];
317
- for (const factory of CHANNEL_FACTORIES) {
349
+ for (const [, factory] of factories) {
318
350
  const channel = await factory(client);
319
351
  if (channel)
320
352
  channels.push(channel);
321
353
  }
322
354
  if (channels.length === 0) {
355
+ const hint = enabledNames ? `检查 CHAT_CHANNELS="${process.env["CHAT_CHANNELS"]}" 指定的渠道是否已配置凭证` : "请在 .env 中配置至少一个渠道的凭证,或设置 CHAT_CHANNELS=<渠道名> 明确指定";
323
356
  await client.app.log({
324
357
  body: {
325
358
  service: "chat-channel",
326
359
  level: "warn",
327
- message: "所有渠道均未就绪(凭证缺失或未配置),插件空启动。"
360
+ message: `所有渠道均未就绪,插件空启动。${hint}`
328
361
  }
329
362
  });
330
363
  return {};
package/dist/types.d.ts CHANGED
@@ -49,4 +49,9 @@ export interface ChatChannel {
49
49
  * 若凭证未配置,应返回 null(插件将跳过该渠道并记录日志)。
50
50
  */
51
51
  export type ChannelFactory = (client: PluginClient) => Promise<ChatChannel | null>;
52
+ /**
53
+ * 已注册的渠道名称。
54
+ * 新增渠道时在此处添加对应字面量,便于编译期检查。
55
+ */
56
+ export type ChannelName = "feishu" | "wecom";
52
57
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAI3D,kBAAkB;AAClB,MAAM,WAAW,eAAe;IAC9B,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAID;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzE;;;OAGG;IACH,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvD,kBAAkB;IAClB,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAID;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,YAAY,KACjB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,8CAA8C;AAC9C,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAI3D,kBAAkB;AAClB,MAAM,WAAW,eAAe;IAC9B,oBAAoB;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAID;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzE;;;OAGG;IACH,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvD,kBAAkB;IAClB,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAID;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,MAAM,EAAE,YAAY,KACjB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;AAIjC;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-chat-channel",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "opencode plugin — multi-channel bot (Feishu/Lark, WeCom) with extensible ChatChannel interface",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",