iflow-feishu 1.0.0 → 1.0.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 CHANGED
@@ -9,41 +9,56 @@
9
9
  - **会话管理** - 自动保存上下文历史
10
10
  - **模式切换** - 支持 default/yolo/plan/smart 模式
11
11
  - **自动搜索** - 检测搜索关键词自动启用网络搜索
12
+ - **交互式配置** - 首次运行自动引导配置
13
+
14
+ ## 安装
15
+
16
+ ```bash
17
+ npm install -g iflow-feishu
18
+ ```
12
19
 
13
20
  ## 快速开始
14
21
 
15
- ### 一键启动
22
+ ### 方式一:交互式配置(推荐)
23
+
24
+ 直接运行,首次使用会引导你配置飞书凭证:
16
25
 
17
26
  ```bash
18
27
  iflow-feishu
19
28
  ```
20
29
 
21
- 启动脚本会自动完成以下操作:
22
-
23
- 1. **检查 iFlow CLI** - 未安装时询问是否安装
24
- 2. **安装插件依赖** - 自动安装 npm 依赖
25
- 3. **安装 PM2** - 自动安装进程管理器
26
- 4. **配置飞书凭证** - 首次使用时引导输入
27
- 5. **启动服务**
30
+ 按提示输入飞书机器人的 App ID 和 App Secret 即可。
28
31
 
29
- ### 前置要求
30
-
31
- - Node.js >= 16.0.0
32
+ ### 方式二:环境变量
32
33
 
33
- ### 手动配置
34
+ ```bash
35
+ export FEISHU_APP_ID="cli_xxxxxxxxxxxx"
36
+ export FEISHU_APP_SECRET="xxxxxxxxxxxxxxxx"
37
+ iflow-feishu
38
+ ```
34
39
 
35
- 如需手动配置飞书凭证:
40
+ ### 方式三:配置文件
36
41
 
37
42
  ```bash
38
43
  mkdir -p ~/.feishu-config
39
- echo '{
40
- "appId": "your-app-id",
41
- "appSecret": "your-app-secret"
42
- }' > ~/.feishu-config/feishu-app.json
44
+ cat > ~/.feishu-config/feishu-app.json << 'EOF'
45
+ {
46
+ "appId": "cli_xxxxxxxxxxxx",
47
+ "appSecret": "xxxxxxxxxxxxxxxx"
48
+ }
49
+ EOF
50
+ iflow-feishu
43
51
  ```
44
52
 
53
+ ## 前置要求
54
+
55
+ - Node.js >= 16.0.0
56
+ - iFlow CLI(可选,用于本地开发)
57
+
45
58
  ## 命令列表
46
59
 
60
+ 在飞书中给机器人发送以下命令:
61
+
47
62
  | 命令 | 说明 |
48
63
  |------|------|
49
64
  | `/help` | 显示帮助信息 |
@@ -52,6 +67,44 @@ echo '{
52
67
  | `/mode <模式>` | 切换模式 (default/yolo/plan/smart) |
53
68
  | `/status` | 查看会话状态 |
54
69
 
70
+ ## 环境变量
71
+
72
+ | 变量 | 说明 | 默认值 |
73
+ |------|------|--------|
74
+ | `FEISHU_APP_ID` | 飞书应用 ID | - |
75
+ | `FEISHU_APP_SECRET` | 飞书应用密钥 | - |
76
+ | `PORT` | HTTP 服务端口 | 18080 |
77
+ | `LOG_LEVEL` | 日志级别 (DEBUG/INFO/WARN/ERROR) | INFO |
78
+
79
+ ## 常用操作
80
+
81
+ ```bash
82
+ # 健康检查
83
+ curl http://localhost:18080/health
84
+
85
+ # 后台运行
86
+ nohup iflow-feishu > iflow-feishu.log 2>&1 &
87
+
88
+ # 查看日志
89
+ tail -f iflow-feishu.log
90
+
91
+ # 使用 PM2 管理
92
+ pm2 start iflow-feishu
93
+ pm2 logs iflow-feishu
94
+ pm2 restart iflow-feishu
95
+ pm2 stop iflow-feishu
96
+ ```
97
+
98
+ ## 飞书机器人配置
99
+
100
+ 1. 访问 [飞书开放平台](https://open.feishu.cn/)
101
+ 2. 创建企业自建应用
102
+ 3. 开通机器人能力
103
+ 4. 配置事件订阅:
104
+ - URL: `http://your-server:18080/webhook`
105
+ - 事件:接收消息
106
+ 5. 获取 App ID 和 App Secret
107
+
55
108
  ## 项目结构
56
109
 
57
110
  ```
@@ -81,67 +134,6 @@ iflow-feishu/
81
134
  └── README.md
82
135
  ```
83
136
 
84
- ## 架构说明
85
-
86
- ### 模块职责
87
-
88
- | 模块 | 职责 |
89
- |------|------|
90
- | service.js | 协调各模块,管理服务生命周期 |
91
- | message-processor.js | 消息解析、上下文构建 |
92
- | stream-handler.js | 流式响应处理、token 提取 |
93
- | http-server.js | HTTP 服务,健康检查,事件回调 |
94
- | websocket-client.js | 飞书 WebSocket 连接 |
95
- | feishu-client.js | 飞书 API 封装 |
96
- | iflow-client.js | iFlow CLI 调用封装 |
97
- | session.js | 会话持久化存储 |
98
- | card-builder.js | 飞书卡片构建 |
99
- | commands.js | 命令处理逻辑 |
100
-
101
- ### 数据流
102
-
103
- ```
104
- 飞书消息 -> WebSocket -> service.handleMessageEvent()
105
- -> messageProcessor.parseMessage()
106
- -> commandHandler.handle() 或 processMessage()
107
- -> iflowClient.execute() (流式)
108
- -> streamHandler.extractResponse()
109
- -> feishuClient.updateCardMessage()
110
- ```
111
-
112
- ## 配置选项
113
-
114
- | 选项 | 说明 | 默认值 |
115
- |------|------|--------|
116
- | `feishu.appId` | 飞书应用 ID | - |
117
- | `feishu.appSecret` | 飞书应用密钥 | - |
118
- | `server.port` | HTTP 服务端口 | 18080 |
119
- | `sessions.maxHistory` | 最大历史消息数 | 15 |
120
- | `iflow.timeout` | CLI 超时时间(ms) | 300000 |
121
-
122
- ## 环境变量
123
-
124
- | 变量 | 说明 |
125
- |------|------|
126
- | `PORT` | 服务端口 |
127
- | `LOG_LEVEL` | 日志级别 (DEBUG/INFO/WARN/ERROR) |
128
-
129
- ## 常用操作
130
-
131
- ```bash
132
- # 查看服务状态
133
- pm2 status iflow-feishu
134
-
135
- # 查看日志
136
- pm2 logs iflow-feishu
137
-
138
- # 重启服务
139
- pm2 restart iflow-feishu
140
-
141
- # 健康检查
142
- curl http://localhost:18080/health
143
- ```
144
-
145
137
  ## 许可证
146
138
 
147
139
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iflow-feishu",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "iFlow CLI 飞书插件 - 将 iFlow AI 助手接入飞书机器人",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -1,23 +1,38 @@
1
1
  /**
2
2
  * 配置管理模块
3
3
  *
4
- * 负责加载和验证配置
4
+ * 负责加载和验证配置,支持交互式配置向导
5
5
  */
6
6
 
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
+ const readline = require('readline');
9
10
  const { DEFAULT_MODEL, DEFAULT_MAX_TOKENS, MODEL_MAX_TOKENS } = require('../core/constants');
10
11
 
12
+ const CONFIG_DIR = path.join(process.env.HOME, '.feishu-config');
13
+ const CONFIG_PATH = path.join(CONFIG_DIR, 'feishu-app.json');
14
+
15
+ // 获取版本号
16
+ function getVersion() {
17
+ try {
18
+ const pkgPath = path.join(__dirname, '..', '..', 'package.json');
19
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
20
+ return pkg.version || '1.0.0';
21
+ } catch {
22
+ return '1.0.0';
23
+ }
24
+ }
25
+
26
+ const VERSION = getVersion();
27
+
11
28
  /**
12
29
  * 加载飞书配置
13
30
  * @returns {Object|null}
14
31
  */
15
32
  function loadFeishuConfig() {
16
- const configPath = path.join(process.env.HOME, '.feishu-config', 'feishu-app.json');
17
-
18
33
  try {
19
- if (fs.existsSync(configPath)) {
20
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
34
+ if (fs.existsSync(CONFIG_PATH)) {
35
+ const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
21
36
  return {
22
37
  appId: config.appId || config.app_id,
23
38
  appSecret: config.appSecret || config.app_secret
@@ -30,6 +45,61 @@ function loadFeishuConfig() {
30
45
  return null;
31
46
  }
32
47
 
48
+ /**
49
+ * 保存飞书配置
50
+ * @param {string} appId
51
+ * @param {string} appSecret
52
+ */
53
+ function saveFeishuConfig(appId, appSecret) {
54
+ if (!fs.existsSync(CONFIG_DIR)) {
55
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
56
+ }
57
+
58
+ const config = { appId, appSecret };
59
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
60
+ console.log(`\n✅ 配置已保存到: ${CONFIG_PATH}\n`);
61
+ }
62
+
63
+ /**
64
+ * 配置向导 - 交互式创建配置
65
+ */
66
+ async function setupWizard() {
67
+ const rl = readline.createInterface({
68
+ input: process.stdin,
69
+ output: process.stdout
70
+ });
71
+
72
+ const question = (prompt) => new Promise((resolve) => {
73
+ rl.question(prompt, resolve);
74
+ });
75
+
76
+ console.log('\n╔══════════════════════════════════════╗');
77
+ console.log('║ iFlow Feishu 配置向导 ║');
78
+ console.log('╚══════════════════════════════════════╝\n');
79
+ console.log('请输入飞书机器人凭证(从飞书开放平台获取):');
80
+ console.log('文档: https://open.feishu.cn/document/home/introduction-to-feishu-open-platform\n');
81
+
82
+ const appId = await question('📱 App ID: ');
83
+ if (!appId || appId.trim() === '') {
84
+ console.error('\n❌ App ID 不能为空');
85
+ rl.close();
86
+ process.exit(1);
87
+ }
88
+
89
+ const appSecret = await question('🔐 App Secret: ');
90
+ if (!appSecret || appSecret.trim() === '') {
91
+ console.error('\n❌ App Secret 不能为空');
92
+ rl.close();
93
+ process.exit(1);
94
+ }
95
+
96
+ rl.close();
97
+
98
+ saveFeishuConfig(appId.trim(), appSecret.trim());
99
+
100
+ return { appId: appId.trim(), appSecret: appSecret.trim() };
101
+ }
102
+
33
103
  /**
34
104
  * 验证配置
35
105
  * @param {Object} config - 配置对象
@@ -51,53 +121,81 @@ function validateConfig(config) {
51
121
  return true;
52
122
  }
53
123
 
54
- // 加载飞书配置
55
- const feishuConfig = loadFeishuConfig();
56
-
57
- if (!feishuConfig) {
58
- console.error('\n错误: 未找到飞书配置文件');
59
- console.error('\n请先运行: iflow-feishu');
60
- console.error('首次运行时会引导你配置飞书机器人凭证\n');
61
- process.exit(1);
124
+ /**
125
+ * 构建完整配置对象
126
+ */
127
+ function buildConfig(feishuConfig) {
128
+ return {
129
+ version: VERSION,
130
+ feishu: {
131
+ appId: feishuConfig.appId,
132
+ appSecret: feishuConfig.appSecret,
133
+ },
134
+ iflow: {
135
+ command: 'iflow',
136
+ timeout: 300000,
137
+ workDir: process.env.HOME || '/data/data/com.termux/files/home',
138
+ maxTokens: DEFAULT_MAX_TOKENS,
139
+ modelMaxTokens: MODEL_MAX_TOKENS
140
+ },
141
+ server: {
142
+ port: parseInt(process.env.PORT, 10) || 18080,
143
+ host: '0.0.0.0'
144
+ },
145
+ sessions: {
146
+ dir: path.join(process.env.HOME || '/tmp', '.iflow-feishu', 'sessions'),
147
+ maxHistory: 15,
148
+ },
149
+ card: {
150
+ titleFontSize: 'small',
151
+ colors: {
152
+ model: 'blue',
153
+ generating: 'orange',
154
+ completed: 'green'
155
+ }
156
+ }
157
+ };
62
158
  }
63
159
 
64
- // 构建完整配置
65
- const config = {
66
- feishu: {
67
- appId: feishuConfig.appId,
68
- appSecret: feishuConfig.appSecret,
69
- },
70
- iflow: {
71
- command: 'iflow',
72
- timeout: 300000,
73
- workDir: process.env.HOME || '/data/data/com.termux/files/home',
74
- maxTokens: DEFAULT_MAX_TOKENS,
75
- modelMaxTokens: MODEL_MAX_TOKENS
76
- },
77
- server: {
78
- port: parseInt(process.env.PORT, 10) || 18080,
79
- host: '0.0.0.0'
80
- },
81
- sessions: {
82
- dir: path.join(process.env.HOME || '/tmp', '.iflow-feishu', 'sessions'),
83
- maxHistory: 15,
84
- },
85
- card: {
86
- titleFontSize: 'small',
87
- colors: {
88
- model: 'blue',
89
- generating: 'orange',
90
- completed: 'green'
91
- }
160
+ /**
161
+ * 初始化配置(异步,支持交互式向导)
162
+ * @returns {Promise<Object>} 配置对象
163
+ */
164
+ async function initConfig() {
165
+ let feishuConfig = loadFeishuConfig();
166
+
167
+ // 检查环境变量
168
+ if (!feishuConfig && process.env.FEISHU_APP_ID && process.env.FEISHU_APP_SECRET) {
169
+ feishuConfig = {
170
+ appId: process.env.FEISHU_APP_ID,
171
+ appSecret: process.env.FEISHU_APP_SECRET
172
+ };
92
173
  }
93
- };
94
-
95
- // 验证配置
96
- validateConfig(config);
97
-
98
- // 确保会话目录存在
99
- if (!fs.existsSync(config.sessions.dir)) {
100
- fs.mkdirSync(config.sessions.dir, { recursive: true });
174
+
175
+ // 配置缺失,启动向导
176
+ if (!feishuConfig) {
177
+ console.log('\n⚠️ 未找到飞书配置文件');
178
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
179
+
180
+ feishuConfig = await setupWizard();
181
+ }
182
+
183
+ const config = buildConfig(feishuConfig);
184
+
185
+ // 验证配置
186
+ validateConfig(config);
187
+
188
+ // 确保会话目录存在
189
+ if (!fs.existsSync(config.sessions.dir)) {
190
+ fs.mkdirSync(config.sessions.dir, { recursive: true });
191
+ }
192
+
193
+ return config;
101
194
  }
102
195
 
103
- module.exports = config;
196
+ module.exports = {
197
+ initConfig,
198
+ getVersion,
199
+ VERSION,
200
+ CONFIG_PATH
201
+ };
package/src/index.js CHANGED
@@ -1,14 +1,17 @@
1
1
  /**
2
- * iFlow Feishu - v1.0.0
2
+ * iFlow Feishu
3
3
  * 将 iFlow CLI 接入飞书机器人
4
4
  */
5
5
 
6
6
  const { FeishuService } = require('./core/service');
7
- const config = require('./config/config');
7
+ const { initConfig, VERSION } = require('./config/config');
8
8
  const { logger } = require('./utils/logger');
9
9
 
10
10
  async function main() {
11
- console.log('\n🚀 iFlow Feishu v1.0.0');
11
+ // 初始化配置(支持交互式向导)
12
+ const config = await initConfig();
13
+
14
+ console.log(`\n🚀 iFlow Feishu v${VERSION}`);
12
15
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
13
16
  console.log(`📱 飞书 App ID: ${config.feishu.appId.substring(0, 15)}...`);
14
17
  console.log(`🌐 服务端口: ${config.server.port}`);