iflow-feishu 1.0.2 → 1.0.3

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.
@@ -2,33 +2,262 @@
2
2
 
3
3
  /**
4
4
  * iFlow Feishu CLI 入口
5
+ *
6
+ * 启动流程:
7
+ * 1. 检测 iFlow CLI -> 未安装则引导安装
8
+ * 2. 检测 PM2 -> 未安装则自动安装
9
+ * 3. 检测飞书配置 -> 未配置则引导输入
10
+ * 4. 启动服务
5
11
  */
6
12
 
13
+ const { spawn, execSync } = require('child_process');
14
+ const fs = require('fs');
7
15
  const path = require('path');
8
- const { spawn } = require('child_process');
16
+ const readline = require('readline');
9
17
 
10
- // 启动脚本路径
11
- const scriptPath = path.join(__dirname, '..', 'iflow-feishu.sh');
18
+ // 颜色输出
19
+ const colors = {
20
+ red: '\x1b[0;31m',
21
+ green: '\x1b[0;32m',
22
+ yellow: '\x1b[1;33m',
23
+ blue: '\x1b[0;34m',
24
+ cyan: '\x1b[0;36m',
25
+ nc: '\x1b[0m'
26
+ };
12
27
 
13
- // 如果启动脚本不存在,直接启动服务
14
- const fs = require('fs');
15
- if (!fs.existsSync(scriptPath)) {
16
- // 直接运行 node 服务
17
- require('../src/index.js');
18
- return;
28
+ const log = {
29
+ info: (msg) => console.log(`${colors.blue}[INFO]${colors.nc} ${msg}`),
30
+ success: (msg) => console.log(`${colors.green}[SUCCESS]${colors.nc} ${msg}`),
31
+ warn: (msg) => console.log(`${colors.yellow}[WARN]${colors.nc} ${msg}`),
32
+ error: (msg) => console.log(`${colors.red}[ERROR]${colors.nc} ${msg}`),
33
+ step: (msg) => console.log(`${colors.cyan}==>${colors.nc} ${msg}`)
34
+ };
35
+
36
+ // 获取版本号
37
+ function getVersion() {
38
+ try {
39
+ const pkgPath = path.join(__dirname, '..', 'package.json');
40
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
41
+ return pkg.version || '1.0.0';
42
+ } catch {
43
+ return '1.0.0';
44
+ }
19
45
  }
20
46
 
21
- // 运行启动脚本
22
- const child = spawn('bash', [scriptPath], {
23
- stdio: 'inherit',
24
- env: process.env
25
- });
47
+ const VERSION = getVersion();
26
48
 
27
- child.on('close', (code) => {
28
- process.exit(code || 0);
29
- });
49
+ // 检查命令是否存在
50
+ function commandExists(cmd) {
51
+ try {
52
+ execSync(`which ${cmd} 2>/dev/null || command -v ${cmd} 2>/dev/null`, { stdio: 'ignore' });
53
+ return true;
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+
59
+ // 获取命令版本
60
+ function getCommandVersion(cmd) {
61
+ try {
62
+ const output = execSync(`${cmd} --version 2>/dev/null`, { encoding: 'utf8' }).trim();
63
+ return output.split('\n')[0];
64
+ } catch {
65
+ return '未知版本';
66
+ }
67
+ }
68
+
69
+ // 交互式问题
70
+ async function question(prompt, defaultVal = 'n') {
71
+ const rl = readline.createInterface({
72
+ input: process.stdin,
73
+ output: process.stdout
74
+ });
75
+
76
+ return new Promise((resolve) => {
77
+ const hint = defaultVal === 'y' ? '[Y/n]' : '[y/N]';
78
+ rl.question(`${prompt} ${hint} `, (answer) => {
79
+ rl.close();
80
+ const reply = (answer || defaultVal).toLowerCase();
81
+ resolve(reply === 'y' || reply === 'yes');
82
+ });
83
+ });
84
+ }
85
+
86
+ // 检测 iFlow CLI
87
+ async function checkIFlowCLI() {
88
+ log.step('检查 iFlow CLI...');
89
+
90
+ if (commandExists('iflow')) {
91
+ const version = getCommandVersion('iflow');
92
+ log.success(`iFlow CLI 已安装 (版本: ${version})`);
93
+ return true;
94
+ }
95
+
96
+ log.warn('iFlow CLI 未安装');
97
+ console.log('');
98
+ console.log('iFlow CLI 是运行此插件必需的依赖。');
99
+ console.log('官网: https://iflow.dev');
100
+ console.log('');
101
+
102
+ const install = await question('是否现在安装 iFlow CLI?', 'y');
103
+
104
+ if (install) {
105
+ log.info('正在安装 iFlow CLI...');
106
+ try {
107
+ execSync('npm install -g @iflow-ai/iflow-cli', { stdio: 'inherit' });
108
+ log.success('iFlow CLI 安装成功');
109
+ return true;
110
+ } catch (err) {
111
+ log.error(`安装失败: ${err.message}`);
112
+ console.log('');
113
+ console.log('请手动安装: npm install -g @iflow-ai/iflow-cli');
114
+ return false;
115
+ }
116
+ }
117
+
118
+ return false;
119
+ }
120
+
121
+ // 检测 PM2
122
+ async function checkPM2() {
123
+ log.step('检查 PM2...');
124
+
125
+ if (commandExists('pm2')) {
126
+ const version = getCommandVersion('pm2');
127
+ log.success(`PM2 已安装 (版本: ${version})`);
128
+ return true;
129
+ }
130
+
131
+ log.warn('PM2 未安装');
132
+ console.log('');
133
+ console.log('PM2 用于进程管理,建议安装。');
134
+ console.log('');
135
+
136
+ const install = await question('是否现在安装 PM2?', 'y');
137
+
138
+ if (install) {
139
+ log.info('正在安装 PM2...');
140
+ try {
141
+ execSync('npm install -g pm2', { stdio: 'inherit' });
142
+ log.success('PM2 安装成功');
143
+ return true;
144
+ } catch (err) {
145
+ log.warn(`PM2 安装失败: ${err.message}`);
146
+ console.log('服务将以前台模式运行');
147
+ return true; // PM2 可选,继续运行
148
+ }
149
+ }
150
+
151
+ return true; // PM2 可选
152
+ }
153
+
154
+ // 配置文件路径
155
+ const CONFIG_DIR = path.join(process.env.HOME, '.feishu-config');
156
+ const CONFIG_PATH = path.join(CONFIG_DIR, 'feishu-app.json');
157
+
158
+ // 检测飞书配置
159
+ async function checkFeishuConfig() {
160
+ log.step('检查飞书配置...');
161
+
162
+ // 检查环境变量
163
+ if (process.env.FEISHU_APP_ID && process.env.FEISHU_APP_SECRET) {
164
+ log.success('检测到环境变量配置');
165
+ return true;
166
+ }
167
+
168
+ // 检查配置文件
169
+ if (fs.existsSync(CONFIG_PATH)) {
170
+ try {
171
+ const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
172
+ if (config.appId && config.appSecret) {
173
+ log.success('飞书配置已存在');
174
+ return true;
175
+ }
176
+ } catch (err) {
177
+ log.warn(`配置文件格式错误: ${err.message}`);
178
+ }
179
+ }
180
+
181
+ log.warn('未找到飞书配置');
182
+ console.log('');
183
+ console.log('请输入飞书机器人凭证(从飞书开放平台获取):');
184
+ console.log('文档: https://open.feishu.cn/document/home/introduction-to-feishu-open-platform');
185
+ console.log('');
186
+
187
+ const rl = readline.createInterface({
188
+ input: process.stdin,
189
+ output: process.stdout
190
+ });
191
+
192
+ const ask = (prompt) => new Promise((resolve) => {
193
+ rl.question(prompt, resolve);
194
+ });
195
+
196
+ const appId = await ask('📱 App ID: ');
197
+ if (!appId || appId.trim() === '') {
198
+ log.error('App ID 不能为空');
199
+ rl.close();
200
+ return false;
201
+ }
202
+
203
+ const appSecret = await ask('🔐 App Secret: ');
204
+ if (!appSecret || appSecret.trim() === '') {
205
+ log.error('App Secret 不能为空');
206
+ rl.close();
207
+ return false;
208
+ }
209
+
210
+ rl.close();
211
+
212
+ // 保存配置
213
+ if (!fs.existsSync(CONFIG_DIR)) {
214
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
215
+ }
216
+
217
+ const config = { appId: appId.trim(), appSecret: appSecret.trim() };
218
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
219
+ log.success(`配置已保存到: ${CONFIG_PATH}`);
220
+
221
+ return true;
222
+ }
223
+
224
+ // 启动服务
225
+ function startService() {
226
+ log.step('启动服务...');
227
+
228
+ // 直接运行服务
229
+ require('../src/index.js');
230
+ }
231
+
232
+ // 主函数
233
+ async function main() {
234
+ console.log('');
235
+ console.log('╔══════════════════════════════════════╗');
236
+ console.log(`║ iFlow Feishu Bridge ║`);
237
+ console.log(`║ 版本 ${VERSION.padEnd(20)}║`);
238
+ console.log('╚══════════════════════════════════════╝');
239
+ console.log('');
240
+
241
+ // 1. 检测 iFlow CLI
242
+ if (!await checkIFlowCLI()) {
243
+ process.exit(1);
244
+ }
245
+
246
+ // 2. 检测 PM2(可选)
247
+ await checkPM2();
248
+
249
+ // 3. 检测飞书配置
250
+ if (!await checkFeishuConfig()) {
251
+ process.exit(1);
252
+ }
253
+
254
+ console.log('');
255
+
256
+ // 4. 启动服务
257
+ startService();
258
+ }
30
259
 
31
- child.on('error', (err) => {
32
- console.error('启动失败:', err.message);
260
+ main().catch((err) => {
261
+ log.error(err.message);
33
262
  process.exit(1);
34
263
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iflow-feishu",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "iFlow CLI 飞书插件 - 将 iFlow AI 助手接入飞书机器人",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -2,6 +2,9 @@
2
2
  * 常量定义
3
3
  */
4
4
 
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
5
8
  const SEARCH_KEYWORDS = [
6
9
  '搜索', '查找', '查询', '最新', '新闻', '天气',
7
10
  '股价', '汇率', '今天', '明天', '本周', '本月',
@@ -35,7 +38,18 @@ const MODEL_MAX_TOKENS = {
35
38
  'mistral-large': 32768
36
39
  };
37
40
 
38
- const VERSION = '1.0.0';
41
+ // package.json 读取版本号
42
+ function getVersion() {
43
+ try {
44
+ const pkgPath = path.join(__dirname, '..', '..', 'package.json');
45
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
46
+ return pkg.version || '1.0.0';
47
+ } catch {
48
+ return '1.0.0';
49
+ }
50
+ }
51
+
52
+ const VERSION = getVersion();
39
53
 
40
54
  module.exports = {
41
55
  SEARCH_KEYWORDS,