ylib-syim 0.0.1

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.
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env bash
2
+ # 彻底卸载 install-dingtalk-bridge.sh 安装的 im-agent-hub 管控项(ctl + 数据目录)
3
+ #
4
+ # 不会删除:
5
+ # - Node.js / nvm / 系统包管理器安装的 Node
6
+ # - im-agent-hub 项目内的 node_modules、openclaw.json、dist/、源码
7
+ #
8
+ # 用法:
9
+ # bash scripts/install/uninstall-im-agent-hub.sh
10
+ # bash scripts/install/uninstall-im-agent-hub.sh -y # 跳过确认
11
+ #
12
+ # 环境变量:
13
+ # IM_AGENT_HUB_HOME 数据目录(默认 ~/.im-agent-hub)
14
+ # IM_AGENT_HUB_UNINSTALL_YES=1 等同 -y
15
+
16
+ set -euo pipefail
17
+
18
+ DEFAULT_HOME="${HOME:?}/.im-agent-hub"
19
+ BOLD='\033[1m'
20
+ WARN='\033[33m'
21
+ INFO='\033[36m'
22
+ OK='\033[32m'
23
+ NC='\033[0m'
24
+
25
+ ui() { echo -e "${INFO}[卸载]${NC} $*"; }
26
+ ui_ok() { echo -e "${OK}[卸载]${NC} $*"; }
27
+ ui_warn() { echo -e "${WARN}[卸载]${NC} $*"; }
28
+
29
+ AUTO_YES=0
30
+ if [[ "${1:-}" == "-y" ]] || [[ "${1:-}" == "--yes" ]] || [[ "${IM_AGENT_HUB_UNINSTALL_YES:-0}" == "1" ]]; then
31
+ AUTO_YES=1
32
+ fi
33
+
34
+ HOME_DIR="${IM_AGENT_HUB_HOME:-$DEFAULT_HOME}"
35
+ MANIFEST="$HOME_DIR/manifest.env"
36
+ CTL_PATH=""
37
+ PACKAGE_ROOT=""
38
+
39
+ if [[ -f "$MANIFEST" ]]; then
40
+ # shellcheck disable=SC1090
41
+ source "$MANIFEST"
42
+ HOME_DIR="${IM_AGENT_HUB_HOME:-$HOME_DIR}"
43
+ MANIFEST="$HOME_DIR/manifest.env"
44
+ CTL_PATH="${IM_AGENT_HUB_CTL_PATH:-}"
45
+ PACKAGE_ROOT="${IM_AGENT_HUB_PACKAGE_ROOT:-}"
46
+ fi
47
+
48
+ if [[ -z "$CTL_PATH" ]]; then
49
+ for try in "${IM_AGENT_HUB_BIN:-$HOME/.local/bin}/im-agent-hub-ctl" "$HOME/.local/bin/im-agent-hub-ctl" "/usr/local/bin/im-agent-hub-ctl"; do
50
+ if [[ -f "$try" ]] && head -1 "$try" 2>/dev/null | grep -q '^#!'; then
51
+ if grep -q "im-agent-hub-ctl\|manifest.env" "$try" 2>/dev/null; then
52
+ CTL_PATH="$try"
53
+ break
54
+ fi
55
+ fi
56
+ done
57
+ fi
58
+
59
+ stop_bridge() {
60
+ local pid_file="$HOME_DIR/run/dingtalk-stdio-bridge.pid"
61
+ if [[ ! -f "$pid_file" ]]; then
62
+ ui "未发现 pid 文件,跳过停止进程"
63
+ return 0
64
+ fi
65
+ local pid
66
+ pid="$(cat "$pid_file" 2>/dev/null || true)"
67
+ if [[ -z "$pid" ]]; then
68
+ rm -f "$pid_file"
69
+ return 0
70
+ fi
71
+ if kill -0 "$pid" 2>/dev/null; then
72
+ ui "正在停止 dingtalk-stdio-bridge (pid=$pid)..."
73
+ kill "$pid" 2>/dev/null || true
74
+ sleep 1
75
+ kill -9 "$pid" 2>/dev/null || true
76
+ ui_ok "进程已停止"
77
+ else
78
+ ui "pid 文件存在但进程已不存在,清理 pid 文件"
79
+ fi
80
+ rm -f "$pid_file"
81
+ }
82
+
83
+ remove_ctl() {
84
+ local removed=0
85
+ if [[ -n "$CTL_PATH" ]] && [[ -f "$CTL_PATH" ]]; then
86
+ rm -f "$CTL_PATH"
87
+ ui_ok "已删除: $CTL_PATH"
88
+ removed=1
89
+ fi
90
+ # 兜底:常见路径上仍是本仓库安装的 ctl(无 manifest 或路径变更时)
91
+ for try in "$HOME/.local/bin/im-agent-hub-ctl" "/usr/local/bin/im-agent-hub-ctl"; do
92
+ [[ "$try" == "$CTL_PATH" ]] && continue
93
+ if [[ -f "$try" ]] && grep -q "manifest.env" "$try" 2>/dev/null; then
94
+ rm -f "$try"
95
+ ui_ok "已删除: $try"
96
+ removed=1
97
+ fi
98
+ done
99
+ if [[ "$removed" -eq 0 ]]; then
100
+ ui_warn "未找到 im-agent-hub-ctl(可能已删除或安装路径非默认)"
101
+ fi
102
+ }
103
+
104
+ remove_data_dir() {
105
+ if [[ ! -d "$HOME_DIR" ]]; then
106
+ ui_warn "数据目录不存在: $HOME_DIR"
107
+ return 0
108
+ fi
109
+ rm -rf "$HOME_DIR"
110
+ ui_ok "已删除数据目录: $HOME_DIR"
111
+ }
112
+
113
+ main() {
114
+ echo -e "${BOLD}im-agent-hub 安装项卸载${NC}"
115
+ echo ""
116
+ ui "将移除:后台桥接进程(若存在)、im-agent-hub-ctl、数据目录 $HOME_DIR"
117
+ ui "不会移除:Node/nvm、项目 node_modules、openclaw.json、dist/"
118
+ if [[ -n "$PACKAGE_ROOT" ]]; then
119
+ ui "(记录的项目目录,保留不动): $PACKAGE_ROOT"
120
+ fi
121
+ echo ""
122
+
123
+ if [[ "$AUTO_YES" -ne 1 ]]; then
124
+ read -r -p "确认卸载?[y/N] " confirm || true
125
+ if [[ ! "${confirm:-}" =~ ^[yY]$ ]]; then
126
+ echo "已取消"
127
+ exit 0
128
+ fi
129
+ fi
130
+
131
+ stop_bridge
132
+ remove_ctl
133
+ remove_data_dir
134
+
135
+ echo ""
136
+ ui_ok "卸载完成。"
137
+ ui "如需删除本机 Node,请自行处理(本脚本不改动 nvm / brew / apt 等安装的 Node)。"
138
+ }
139
+
140
+ main "$@"
@@ -0,0 +1,387 @@
1
+ /**
2
+ * 飞书 Stdio 桥接:与 dingtalk-stdio-bridge 同思路,但面向飞书 WebSocket + 端点模式。
3
+ *
4
+ * 不依赖本地 OpenClaw Gateway,直接通过 cfg.channels.feishu.gatewayBaseUrl
5
+ * 让插件内的端点模式(endpoint-dispatch.ts)调用远程 Gateway(如 yuce-gpt)。
6
+ *
7
+ * 工作原理:
8
+ * 1. 调用 plugin.register({ runtime: minimalRuntime, ... }),注入最小 runtime mock
9
+ * (避免 LarkClient.runtime 为空时抛错)
10
+ * 2. 调用 monitorFeishuProvider({ config: cfg }),启动飞书 WebSocket 监听
11
+ * 3. 有消息时,handler.ts 的 7 阶段 pipeline 运行;dispatch.ts 检测到 gatewayBaseUrl
12
+ * 后调用 endpoint-dispatch.ts 的 dispatchToAgentViaEndpoint,走 SSE 端点
13
+ *
14
+ * 前提:先在 im-agent-hub 目录运行 `npm install`,以安装:
15
+ * "@larksuite/openclaw-lark": "file:../openclaw-lark"
16
+ * "openclaw": "file:../openclaw"
17
+ *
18
+ * 配置方式:
19
+ * A. syim.json 的 channels.feishu:顶层或 accounts.* 下含 appId / appSecret / gatewayBaseUrl
20
+ * B. 环境变量 FEISHU_APP_ID / FEISHU_APP_SECRET / FEISHU_GATEWAY_URL|GATEWAY_URL / GATEWAY_TOKEN
21
+ */
22
+
23
+ import fs from "node:fs";
24
+ import os from "node:os";
25
+ import path from "node:path";
26
+
27
+ const CHANNEL_KEY = "feishu";
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // 项目根目录解析
31
+ // ---------------------------------------------------------------------------
32
+
33
+ /** Hub 式配置:Gateway 只写在子账号上时,从 accounts 中取第一个非空字段 */
34
+ function firstStringInAccounts(
35
+ accounts: Record<string, unknown> | undefined,
36
+ field: string
37
+ ): string {
38
+ if (!accounts || typeof accounts !== "object") return "";
39
+ for (const acc of Object.values(accounts)) {
40
+ if (!acc || typeof acc !== "object") continue;
41
+ const v = (acc as Record<string, unknown>)[field];
42
+ if (typeof v === "string" && v.trim()) return v.trim();
43
+ }
44
+ return "";
45
+ }
46
+
47
+ function getProjectRoot(): string {
48
+ const main = process.argv[1];
49
+ if (main) {
50
+ const resolved = path.resolve(main);
51
+ const base = path.basename(resolved);
52
+ if (
53
+ base === "lark-stdio-bridge.ts" ||
54
+ base === "lark-stdio-bridge.cjs" ||
55
+ base === "lark-stdio-bridge.mjs"
56
+ ) {
57
+ return path.join(path.dirname(resolved), "..");
58
+ }
59
+ }
60
+ return process.cwd();
61
+ }
62
+
63
+ function channelsForLog(
64
+ channels: Record<string, unknown> | undefined
65
+ ): Record<string, unknown> | undefined {
66
+ if (!channels || typeof channels !== "object") return channels;
67
+ const out: Record<string, unknown> = {};
68
+ const sensitive = new Set([
69
+ "appSecret",
70
+ "encryptKey",
71
+ "verificationToken",
72
+ "gatewayToken",
73
+ "gatewayPassword",
74
+ ]);
75
+ for (const [k, v] of Object.entries(channels)) {
76
+ if (v && typeof v === "object") {
77
+ const c = { ...(v as Record<string, unknown>) };
78
+ for (const key of Object.keys(c))
79
+ if (sensitive.has(key)) (c as Record<string, unknown>)[key] = "<redacted>";
80
+ if (c.accounts && typeof c.accounts === "object")
81
+ (c as Record<string, unknown>).accounts = Object.keys(c.accounts as object);
82
+ out[k] = c;
83
+ } else out[k] = v;
84
+ }
85
+ return out;
86
+ }
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // 配置加载
90
+ // ---------------------------------------------------------------------------
91
+
92
+ function loadOpenClawConfig(): Record<string, unknown> | null {
93
+ const configPaths = [path.join(getProjectRoot(), "syim.json"), path.join(os.homedir(), ".syim", "syim.json")];
94
+ for (const configPath of configPaths) {
95
+ if (!fs.existsSync(configPath)) continue;
96
+ try {
97
+ const content = fs.readFileSync(configPath, "utf-8");
98
+ const config = JSON.parse(content) as Record<string, unknown>;
99
+ console.error("[lark-stdio-bridge] 从 syim.json 加载配置:", configPath);
100
+ console.error(
101
+ "[lark-stdio-bridge] channels:",
102
+ JSON.stringify(channelsForLog(config.channels as Record<string, unknown>), null, 2)
103
+ );
104
+ return config;
105
+ } catch (err) {
106
+ console.warn("[lark-stdio-bridge] 读取配置失败:", configPath, (err as Error).message);
107
+ }
108
+ }
109
+ console.error("[lark-stdio-bridge] 未找到 syim.json,将使用环境变量");
110
+ return null;
111
+ }
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // 构建 cfg
115
+ // ---------------------------------------------------------------------------
116
+
117
+ function buildCfg(): { cfg: Record<string, unknown>; gatewayBaseUrl: string; gatewayToken: string } {
118
+ const raw = loadOpenClawConfig();
119
+ const channelConfig = (raw?.channels as Record<string, unknown>)?.[CHANNEL_KEY] as
120
+ | Record<string, unknown>
121
+ | undefined;
122
+
123
+ const envBase = (process.env.FEISHU_GATEWAY_URL || process.env.GATEWAY_URL || "").trim();
124
+ const accountsMap = channelConfig?.accounts as Record<string, unknown> | undefined;
125
+ const fileBase =
126
+ (channelConfig?.gatewayBaseUrl as string)?.trim() ||
127
+ firstStringInAccounts(accountsMap, "gatewayBaseUrl") ||
128
+ "";
129
+ const gatewayBaseUrl = (envBase || fileBase).replace(/\/+$/, "");
130
+
131
+ if (!gatewayBaseUrl) {
132
+ console.error(
133
+ JSON.stringify({
134
+ error:
135
+ "FEISHU_GATEWAY_URL or GATEWAY_URL (or syim.json channels.feishu.gatewayBaseUrl or accounts.*.gatewayBaseUrl) required",
136
+ })
137
+ );
138
+ process.exit(1);
139
+ }
140
+
141
+ const gatewayToken = (
142
+ process.env.GATEWAY_TOKEN ||
143
+ process.env.OPENCLAW_GATEWAY_TOKEN ||
144
+ process.env.OPENCLAW_GATEWAY_API_KEY ||
145
+ (channelConfig?.gatewayToken as string)?.trim() ||
146
+ firstStringInAccounts(accountsMap, "gatewayToken") ||
147
+ ""
148
+ ).trim();
149
+
150
+ console.error("[lark-stdio-bridge] gatewayBaseUrl =", gatewayBaseUrl);
151
+ console.error("[lark-stdio-bridge] gatewayToken =", gatewayToken ? "<present>" : "<absent>");
152
+
153
+ let cfg: Record<string, unknown>;
154
+
155
+ if (channelConfig) {
156
+ const base = { ...channelConfig } as Record<string, unknown>;
157
+ const accounts = base.accounts as Record<string, Record<string, unknown>> | undefined;
158
+ delete base.accounts;
159
+ base.gatewayBaseUrl = gatewayBaseUrl;
160
+ if (gatewayToken) base.gatewayToken = gatewayToken;
161
+
162
+ if (accounts && typeof accounts === "object") {
163
+ const merged: Record<string, Record<string, unknown>> = {};
164
+ for (const [id, acc] of Object.entries(accounts)) {
165
+ if (acc && typeof acc === "object")
166
+ // 不要用全局 gatewayToken 覆盖子账号自己的 gatewayToken(多机器人各用各的 token)
167
+ merged[id] = { ...base, ...acc, gatewayBaseUrl };
168
+ }
169
+ cfg = {
170
+ channels: { [CHANNEL_KEY]: { ...base, accounts: merged } },
171
+ ...(raw?.bindings ? { bindings: raw.bindings } : {}),
172
+ };
173
+ } else {
174
+ cfg = {
175
+ channels: { [CHANNEL_KEY]: base },
176
+ ...(raw?.bindings ? { bindings: raw.bindings } : {}),
177
+ };
178
+ }
179
+ } else {
180
+ // 纯环境变量模式
181
+ const appId = process.env.FEISHU_APP_ID;
182
+ const appSecret = process.env.FEISHU_APP_SECRET;
183
+ if (!appId || !appSecret) {
184
+ console.error(
185
+ JSON.stringify({
186
+ error:
187
+ "FEISHU_APP_ID and FEISHU_APP_SECRET required (set in syim.json channels.feishu or env)",
188
+ })
189
+ );
190
+ process.exit(1);
191
+ }
192
+ cfg = {
193
+ channels: {
194
+ [CHANNEL_KEY]: {
195
+ appId,
196
+ appSecret,
197
+ gatewayBaseUrl,
198
+ gatewayToken: gatewayToken || undefined,
199
+ dmPolicy: "open",
200
+ allowFrom: ["*"],
201
+ separateSessionByConversation: true,
202
+ groupSessionScope: "group",
203
+ },
204
+ },
205
+ };
206
+ }
207
+
208
+ return { cfg, gatewayBaseUrl, gatewayToken };
209
+ }
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // 设置临时 HOME(使插件内读取 ~/.syim/syim.json 时能读到 bindings)
213
+ // ---------------------------------------------------------------------------
214
+
215
+ function setupOpenClawConfigForPlugin(): void {
216
+ const projectRoot = getProjectRoot();
217
+ const projectConfigPath = path.join(projectRoot, "syim.json");
218
+ if (!fs.existsSync(projectConfigPath)) return;
219
+
220
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-lark-bridge-"));
221
+ const openclawDir = path.join(tempDir, ".syim");
222
+ fs.mkdirSync(openclawDir, { recursive: true });
223
+ const targetPath = path.join(openclawDir, "syim.json");
224
+ try {
225
+ // 只保留 feishu channel 和 bindings,去掉其他 channel(避免飞书插件 schema 校验报错)
226
+ const raw = JSON.parse(fs.readFileSync(projectConfigPath, "utf-8")) as Record<string, unknown>;
227
+ const channels = raw.channels as Record<string, unknown> | undefined;
228
+ const feishuOnly: Record<string, unknown> = {
229
+ ...(channels?.feishu ? { channels: { feishu: channels.feishu } } : {}),
230
+ ...(raw.bindings ? { bindings: raw.bindings } : {}),
231
+ };
232
+ fs.writeFileSync(targetPath, JSON.stringify(feishuOnly, null, 2), "utf-8");
233
+ } catch (err) {
234
+ console.warn("[lark-stdio-bridge] 拷贝 syim.json 到临时目录失败:", (err as Error).message);
235
+ try {
236
+ fs.rmSync(tempDir, { recursive: true, force: true });
237
+ } catch (_) {}
238
+ return;
239
+ }
240
+ process.env.HOME = tempDir;
241
+ if (process.platform === "win32") process.env.USERPROFILE = tempDir;
242
+ console.error(
243
+ "[lark-stdio-bridge] 已设置 HOME 为临时目录,bindings 将从当前项目 syim.json 读取:",
244
+ projectConfigPath
245
+ );
246
+ }
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // 最小化 runtime mock
250
+ // ---------------------------------------------------------------------------
251
+
252
+ function buildMinimalRuntime(cfg: Record<string, unknown>): unknown {
253
+ return {
254
+ log: (...args: unknown[]) => console.error("[Feishu]", ...args),
255
+ error: (...args: unknown[]) => console.error("[Feishu][ERR]", ...args),
256
+ exit: (code: number) => process.exit(code),
257
+ gateway: { port: 0 },
258
+ // config.loadConfig() 被 MonitorContext 的 get cfg() 使用
259
+ config: {
260
+ loadConfig: () => cfg,
261
+ featureFlags: {},
262
+ },
263
+ channel: {
264
+ // handler.ts 在调用 dispatchToAgent 前会访问这两个字段
265
+ // endpoint 模式下 dispatchToAgent 提前返回,不会用到 reply/routing 等
266
+ commands: {
267
+ shouldComputeCommandAuthorized: () => false,
268
+ resolveCommandAuthorizedFromAuthorizers: async () => false,
269
+ isControlCommandMessage: () => false,
270
+ },
271
+ reply: {
272
+ resolveEnvelopeFormatOptions: () => ({}),
273
+ finalizeInboundContext: () => ({}),
274
+ createReplyDispatcherWithTyping: () => ({
275
+ dispatcher: {
276
+ sendFinalReply: () => false,
277
+ sendBlockReply: () => false,
278
+ sendToolResult: () => false,
279
+ waitForIdle: async () => {},
280
+ getQueuedCounts: () => ({}),
281
+ markComplete: () => {},
282
+ },
283
+ replyOptions: {},
284
+ markDispatchIdle: () => {},
285
+ }),
286
+ dispatchReplyFromConfig: async () => ({ queuedFinal: false, counts: { final: 0 } }),
287
+ dispatchReplyWithBufferedBlockDispatcher: async () => {},
288
+ resolveHumanDelayConfig: () => null,
289
+ formatAgentEnvelope: () => "",
290
+ },
291
+ routing: {
292
+ resolveAgentRoute: () => ({ agentId: "main", sessionKey: "" }),
293
+ },
294
+ text: {
295
+ resolveTextChunkLimit: () => 4000,
296
+ resolveChunkMode: () => "paragraph",
297
+ resolveMarkdownTableMode: () => "bullets",
298
+ chunkTextWithMode: (text: string) => [text],
299
+ convertMarkdownTables: (text: string) => text,
300
+ },
301
+ activity: { record: () => {} },
302
+ },
303
+ system: {
304
+ enqueueSystemEvent: () => {},
305
+ },
306
+ messages: { groupChat: { historyLimit: 0 } },
307
+ };
308
+ }
309
+
310
+ // ---------------------------------------------------------------------------
311
+ // Main
312
+ // ---------------------------------------------------------------------------
313
+
314
+ async function main(): Promise<void> {
315
+ setupOpenClawConfigForPlugin();
316
+
317
+ const { cfg, gatewayBaseUrl } = buildCfg();
318
+
319
+ // 确保 channels.feishu.gatewayBaseUrl 在 cfg 对象上可读(插件取 channelCfg 时用)
320
+ const ch = cfg.channels as Record<string, unknown> | undefined;
321
+ const channelEntry = ch?.[CHANNEL_KEY];
322
+ if (channelEntry && typeof channelEntry === "object") {
323
+ (channelEntry as Record<string, unknown>).gatewayBaseUrl = gatewayBaseUrl;
324
+ }
325
+
326
+ console.error("[lark-stdio-bridge] 加载 ylib-openclaw-lark ...");
327
+
328
+ // 动态导入(需先运行 npm install 安装依赖)
329
+ const larkModule = await import("ylib-openclaw-lark");
330
+
331
+ // step 1: plugin.register 注入 runtime mock,让 LarkClient.setRuntime 被调用
332
+ // index.ts 里的 register() 第一行就是 LarkClient.setRuntime(api.runtime)
333
+ const plugin = (larkModule as { default?: { register?: (api: unknown) => void } }).default;
334
+ const minimalRuntime = buildMinimalRuntime(cfg);
335
+
336
+ if (typeof plugin?.register === "function") {
337
+ plugin.register({
338
+ runtime: minimalRuntime,
339
+ // 以下均是 no-op,bridge 不需要 channel/tool 注册
340
+ registerChannel: () => {},
341
+ registerTool: () => {},
342
+ registerCommand: () => {},
343
+ registerGatewayMethod: () => {},
344
+ registerCli: () => {},
345
+ on: () => {},
346
+ config: cfg,
347
+ logger: {
348
+ info: (...args: unknown[]) => console.error("[Feishu]", ...args),
349
+ warn: (...args: unknown[]) => console.warn("[Feishu]", ...args),
350
+ error: (...args: unknown[]) => console.error("[Feishu][ERR]", ...args),
351
+ debug: () => {},
352
+ },
353
+ });
354
+ console.error("[lark-stdio-bridge] plugin.register 完成,LarkClient.runtime 已注入");
355
+ } else {
356
+ console.warn("[lark-stdio-bridge] 警告:未找到 plugin.register,跳过 runtime 注入");
357
+ }
358
+
359
+ // step 2: 调用 monitorFeishuProvider 启动 WebSocket 监听
360
+ const monitorFeishuProvider = (larkModule as { monitorFeishuProvider?: (opts: unknown) => Promise<void> })
361
+ .monitorFeishuProvider;
362
+
363
+ if (typeof monitorFeishuProvider !== "function") {
364
+ console.error(
365
+ JSON.stringify({ error: "@larksuite/openclaw-lark 未导出 monitorFeishuProvider" })
366
+ );
367
+ process.exit(1);
368
+ }
369
+
370
+ const runtime = {
371
+ log: (...args: unknown[]) => console.error("[Feishu]", ...args),
372
+ error: (...args: unknown[]) => console.error("[Feishu][ERR]", ...args),
373
+ exit: (code: number) => process.exit(code),
374
+ };
375
+
376
+ console.error(
377
+ "[lark-stdio-bridge] 调用 monitorFeishuProvider,gatewayBaseUrl =",
378
+ gatewayBaseUrl
379
+ );
380
+
381
+ await monitorFeishuProvider({ config: cfg, runtime });
382
+ }
383
+
384
+ main().catch((err) => {
385
+ console.error("[lark-stdio-bridge]", err);
386
+ process.exit(1);
387
+ });
@@ -0,0 +1,12 @@
1
+ export DINGTALK_CLIENT_ID=dingwkkspuzu21bnrlot
2
+ export DINGTALK_CLIENT_SECRET=2-DLRHf2ikJCxSyl0SZ2KuyAtml5N3wydBNwWKUCv7OR6bK_0sCHLKvUuZ6rGtnQ
3
+ export IFLOW_API_KEY=sk-rlzq1k7zRkDOKJIsp3snvteuMzqEwm9CNWnp08J7TUDWlaNn
4
+ export DINGTALK_AGENT_ACCESS_TOKEN=vw82p1S1mw
5
+ export DINGTALK_AGENT_MODEL=glm_5
6
+ export DINGTALK_AGENT_URL=http://127.0.0.1:4999/api/v1/yucegpt/dingtalk/chat/
7
+
8
+ export CUSTOM_ID="test03"
9
+ export DISABLE_INTERNAL_MCP=1
10
+
11
+ # pnpm run start:dingtalk
12
+ pnpm run start:connector
package/syim.json.bak ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "channels": {
3
+ "feishu": {
4
+ "enabled": true,
5
+ "accounts": {
6
+ "bot1": {
7
+ "enabled": true,
8
+ "appId": "REPLACE_WITH_FEISHU_APP_ID",
9
+ "appSecret": "REPLACE_WITH_FEISHU_APP_SECRET",
10
+ "dmPolicy": "open",
11
+ "allowFrom": ["*"],
12
+ "gatewayBaseUrl": "http://127.0.0.1:4999",
13
+ "gatewayToken": "REPLACE_WITH_GATEWAY_TOKEN",
14
+ "separateSessionByConversation": true,
15
+ "groupSessionScope": "group",
16
+ "streaming": true,
17
+ "uploadHost": "http://127.0.0.1:4999"
18
+ },
19
+ "bot2": {
20
+ "enabled": false,
21
+ "appId": "REPLACE_WITH_FEISHU_APP_ID_2",
22
+ "appSecret": "REPLACE_WITH_FEISHU_APP_SECRET_2",
23
+ "dmPolicy": "open",
24
+ "allowFrom": ["*"],
25
+ "gatewayBaseUrl": "http://127.0.0.1:4999",
26
+ "gatewayToken": "REPLACE_WITH_GATEWAY_TOKEN_2",
27
+ "separateSessionByConversation": true,
28
+ "groupSessionScope": "group",
29
+ "streaming": true,
30
+ "uploadHost": "http://127.0.0.1:4999"
31
+ }
32
+ }
33
+ },
34
+ "dingtalk-connector": {
35
+ "enabled": true,
36
+ "accounts": {
37
+ "bot1": {
38
+ "enabled": true,
39
+ "clientId": "REPLACE_WITH_DINGTALK_CLIENT_ID",
40
+ "clientSecret": "REPLACE_WITH_DINGTALK_CLIENT_SECRET",
41
+ "gatewayToken": "REPLACE_WITH_GATEWAY_TOKEN",
42
+ "modelName": "glm_5",
43
+ "asyncMode": true,
44
+ "separateSessionByConversation": true,
45
+ "groupSessionScope": "group",
46
+ "gatewayPort": 4999,
47
+ "gatewayBaseUrl": "http://127.0.0.1:4999",
48
+ "uploadHost": "http://127.0.0.1:4999"
49
+ },
50
+ "bot2": {
51
+ "enabled": false,
52
+ "clientId": "REPLACE_WITH_DINGTALK_CLIENT_ID_2",
53
+ "clientSecret": "REPLACE_WITH_DINGTALK_CLIENT_SECRET_2",
54
+ "gatewayToken": "REPLACE_WITH_GATEWAY_TOKEN_2",
55
+ "modelName": "glm_5",
56
+ "asyncMode": true,
57
+ "separateSessionByConversation": true,
58
+ "groupSessionScope": "group",
59
+ "gatewayPort": 4999,
60
+ "gatewayBaseUrl": "http://127.0.0.1:4999",
61
+ "uploadHost": "http://127.0.0.1:4999"
62
+ }
63
+ }
64
+ }
65
+ },
66
+ "bindings": [
67
+ { "agentId": "main", "match": { "channel": "feishu" } },
68
+ { "agentId": "main", "match": { "channel": "dingtalk-connector" } }
69
+ ]
70
+ }