@iflow-ai/iflow-cli 0.4.16-beta-20260108 → 0.4.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iflow-ai/iflow-cli",
3
- "version": "0.4.16-beta-20260108",
3
+ "version": "0.4.16",
4
4
  "engines": {
5
5
  "node": ">=20.0.0"
6
6
  },
@@ -63,7 +63,6 @@
63
63
  "LICENSE"
64
64
  ],
65
65
  "devDependencies": {
66
- "@types/jsdom": "^27.0.0",
67
66
  "@types/marked": "^5.0.2",
68
67
  "@types/micromatch": "^4.0.9",
69
68
  "@types/mime-types": "^3.0.1",
@@ -119,11 +118,7 @@
119
118
  "access": "public"
120
119
  },
121
120
  "dependencies": {
122
- "asciify-image": "^0.1.10",
123
- "gifuct-js": "^2.1.2",
124
121
  "ink": "^6.5.0",
125
- "ink-picture": "^1.3.3",
126
- "is-unicode-supported": "^2.1.0",
127
122
  "react-devtools-core": "^6.1.5",
128
123
  "shell-quote": "^1.8.3"
129
124
  }
@@ -4,17 +4,8 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import {
8
- existsSync,
9
- mkdirSync,
10
- createWriteStream,
11
- statSync,
12
- readdirSync,
13
- createReadStream,
14
- unlinkSync,
15
- rmSync,
16
- } from 'fs';
17
- import { join } from 'path';
7
+ import { existsSync, mkdirSync, createWriteStream, statSync, readdirSync, createReadStream, unlinkSync, rmSync } from 'fs';
8
+ import { join, dirname, resolve } from 'path';
18
9
  import { fileURLToPath } from 'url';
19
10
  import os from 'os';
20
11
  import https from 'https';
@@ -24,29 +15,48 @@ import { pipeline } from 'stream/promises';
24
15
  import { Extract } from 'unzipper';
25
16
 
26
17
  // 常量定义
27
- const PLUGIN_URL =
28
- 'https://cloud.iflow.cn/iflow-cli/idea-plugin/iflow-idea-0.0.5.zip';
18
+ const PLUGIN_URL = 'https://cloud.iflow.cn/iflow-cli/idea-plugin/iflow-idea-0.0.3.zip';
29
19
  const PLUGIN_DIR_NAME = 'iflow-idea';
30
20
  const TEMP_DIR_NAME = 'tstar-cli-idea-plugin';
31
21
  const LOG_PREFIX = '[JetBrains Extension]';
32
22
  // 扩展支持的JetBrains IDE产品
33
23
  const IDE_PATTERNS = [
34
- 'IntelliJIdea',
35
- 'IdeaIC', // IntelliJ IDEA
36
- 'PyCharm',
37
- 'PyCharmCE', // PyCharm
38
- 'GoLand', // GoLand
39
- 'WebStorm', // WebStorm
40
- 'PhpStorm', // PhpStorm
41
- 'CLion', // CLion
42
- 'RubyMine', // RubyMine
43
- 'DataGrip', // DataGrip
44
- 'Rider', // Rider
45
- 'AndroidStudio', // Android Studio
24
+ 'IntelliJIdea', 'IdeaIC', // IntelliJ IDEA
25
+ 'PyCharm', 'PyCharmCE', // PyCharm
26
+ 'GoLand', // GoLand
27
+ 'WebStorm', // WebStorm
28
+ 'PhpStorm', // PhpStorm
29
+ 'CLion', // CLion
30
+ 'RubyMine', // RubyMine
31
+ 'DataGrip', // DataGrip
32
+ 'Rider', // Rider
33
+ 'AndroidStudio' // Android Studio
46
34
  ];
47
35
 
48
36
  // 获取当前脚本的目录
49
37
  const __filename = fileURLToPath(import.meta.url);
38
+ const __dirname = dirname(__filename);
39
+
40
+ // 验证路径是否安全
41
+ function validatePath(path) {
42
+ if (!path || typeof path !== 'string') {
43
+ return false;
44
+ }
45
+
46
+ // 防止路径遍历攻击
47
+ const normalizedPath = resolve(path);
48
+ return !normalizedPath.includes('..');
49
+ }
50
+
51
+ // 检查文件是否存在且可执行
52
+ function isExecutable(filePath) {
53
+ try {
54
+ const stats = statSync(filePath);
55
+ return stats.isFile() && (stats.mode & parseInt('111', 8)) !== 0;
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
50
60
 
51
61
  // 获取 JetBrains IDE 插件目录的跨平台函数
52
62
  function getJetBrainsPluginsDirectory() {
@@ -77,17 +87,14 @@ function findLatestJetBrainsDirectories() {
77
87
  try {
78
88
  // 获取所有匹配的IDE目录,并按修改时间排序
79
89
  const dirs = readdirSync(jetbrainsDir)
80
- .filter((dir) => IDE_PATTERNS.some((pattern) => dir.startsWith(pattern)))
81
- .map((dir) => {
90
+ .filter(dir => IDE_PATTERNS.some(pattern => dir.startsWith(pattern)))
91
+ .map(dir => {
82
92
  const fullPath = join(jetbrainsDir, dir);
83
93
  try {
84
94
  const stats = statSync(fullPath);
85
95
  return { path: fullPath, mtime: stats.mtime, name: dir };
86
96
  } catch (error) {
87
- console.warn(
88
- `${LOG_PREFIX} Cannot access directory ${fullPath}:`,
89
- error.message,
90
- );
97
+ console.warn(`${LOG_PREFIX} Cannot access directory ${fullPath}:`, error.message);
91
98
  return null;
92
99
  }
93
100
  })
@@ -101,10 +108,8 @@ function findLatestJetBrainsDirectories() {
101
108
 
102
109
  // 按IDE类型分组,每种IDE只保留最新版本
103
110
  const latestByType = {};
104
- dirs.forEach((dir) => {
105
- const ideType = IDE_PATTERNS.find((pattern) =>
106
- dir.name.startsWith(pattern),
107
- );
111
+ dirs.forEach(dir => {
112
+ const ideType = IDE_PATTERNS.find(pattern => dir.name.startsWith(pattern));
108
113
  if (ideType && !latestByType[ideType]) {
109
114
  latestByType[ideType] = dir;
110
115
  }
@@ -112,10 +117,7 @@ function findLatestJetBrainsDirectories() {
112
117
 
113
118
  return Object.values(latestByType);
114
119
  } catch (error) {
115
- console.error(
116
- `${LOG_PREFIX} Error finding JetBrains IDE directories:`,
117
- error.message,
118
- );
120
+ console.error(`${LOG_PREFIX} Error finding JetBrains IDE directories:`, error.message);
119
121
  return [];
120
122
  }
121
123
  }
@@ -128,22 +130,18 @@ async function downloadPlugin(url, destPath) {
128
130
  // 根据URL协议选择适当的模块
129
131
  const protocol = url.startsWith('https:') ? https : http;
130
132
 
131
- protocol
132
- .get(url, (response) => {
133
- if (response.statusCode !== 200) {
134
- reject(
135
- new Error(`Failed to download plugin: ${response.statusCode}`),
136
- );
137
- return;
138
- }
133
+ protocol.get(url, (response) => {
134
+ if (response.statusCode !== 200) {
135
+ reject(new Error(`Failed to download plugin: ${response.statusCode}`));
136
+ return;
137
+ }
139
138
 
140
- pipeline(response, file)
141
- .then(() => resolve())
142
- .catch(reject);
143
- })
144
- .on('error', (err) => {
145
- reject(err);
146
- });
139
+ pipeline(response, file)
140
+ .then(() => resolve())
141
+ .catch(reject);
142
+ }).on('error', (err) => {
143
+ reject(err);
144
+ });
147
145
  });
148
146
  }
149
147
 
@@ -179,9 +177,7 @@ async function installJetBrainsExtension() {
179
177
  // 查找所有支持的 JetBrains IDE 目录
180
178
  const ideDirs = findLatestJetBrainsDirectories();
181
179
  if (ideDirs.length === 0) {
182
- console.warn(
183
- `${LOG_PREFIX} Could not find any JetBrains IDE installation, skipping plugin installation`,
184
- );
180
+ console.warn(`${LOG_PREFIX} Could not find any JetBrains IDE installation, skipping plugin installation`);
185
181
  return;
186
182
  }
187
183
 
@@ -191,10 +187,7 @@ async function installJetBrainsExtension() {
191
187
  try {
192
188
  mkdirSync(tempDir, { recursive: true });
193
189
  } catch (error) {
194
- console.error(
195
- `${LOG_PREFIX} Failed to create temporary directory: ${tempDir}`,
196
- error.message,
197
- );
190
+ console.error(`${LOG_PREFIX} Failed to create temporary directory: ${tempDir}`, error.message);
198
191
  return;
199
192
  }
200
193
  }
@@ -224,10 +217,7 @@ async function installJetBrainsExtension() {
224
217
  try {
225
218
  mkdirSync(pluginsDir, { recursive: true });
226
219
  } catch (error) {
227
- console.error(
228
- `${LOG_PREFIX} Failed to create plugins directory: ${pluginsDir}`,
229
- error.message,
230
- );
220
+ console.error(`${LOG_PREFIX} Failed to create plugins directory: ${pluginsDir}`, error.message);
231
221
  continue; // 跳过此IDE,继续下一个
232
222
  }
233
223
  }
@@ -236,15 +226,10 @@ async function installJetBrainsExtension() {
236
226
  const existingPluginDir = join(pluginsDir, PLUGIN_DIR_NAME);
237
227
  if (existsSync(existingPluginDir)) {
238
228
  try {
239
- console.info(
240
- `${LOG_PREFIX} Removing existing plugin directory: ${existingPluginDir}`,
241
- );
229
+ console.info(`${LOG_PREFIX} Removing existing plugin directory: ${existingPluginDir}`);
242
230
  rmSync(existingPluginDir, { recursive: true, force: true });
243
231
  } catch (error) {
244
- console.error(
245
- `${LOG_PREFIX} Failed to remove existing plugin directory: ${existingPluginDir}`,
246
- error.message,
247
- );
232
+ console.error(`${LOG_PREFIX} Failed to remove existing plugin directory: ${existingPluginDir}`, error.message);
248
233
  // 继续安装,即使删除失败
249
234
  }
250
235
  }
@@ -255,14 +240,9 @@ async function installJetBrainsExtension() {
255
240
  try {
256
241
  // 直接解压到插件目录,不创建额外的子目录
257
242
  await extractPlugin(pluginFilePath, pluginsDir);
258
- console.info(
259
- `${LOG_PREFIX} ✔ Plugin installed successfully to: ${pluginsDir}`,
260
- );
243
+ console.info(`${LOG_PREFIX} ✔ Plugin installed successfully to: ${pluginsDir}`);
261
244
  } catch (error) {
262
- console.error(
263
- `${LOG_PREFIX} Failed to install plugin for ${ideDir.name}:`,
264
- error.message,
265
- );
245
+ console.error(`${LOG_PREFIX} Failed to install plugin for ${ideDir.name}:`, error.message);
266
246
  }
267
247
  }
268
248
 
@@ -270,27 +250,22 @@ async function installJetBrainsExtension() {
270
250
  try {
271
251
  unlinkSync(pluginFilePath);
272
252
  } catch (error) {
273
- console.warn(
274
- `${LOG_PREFIX} Failed to clean up temporary file: ${pluginFilePath}`,
275
- error.message,
276
- );
253
+ console.warn(`${LOG_PREFIX} Failed to clean up temporary file: ${pluginFilePath}`, error.message);
277
254
  }
255
+
278
256
  } catch (error) {
279
257
  console.error(`${LOG_PREFIX} Failed to install plugin:`, error.message);
280
258
  console.debug(`${LOG_PREFIX} Stack trace:`, error.stack);
281
259
  }
282
260
  } catch (error) {
283
- console.error(
284
- `${LOG_PREFIX} Unexpected error during JetBrains extension installation:`,
285
- error.message,
286
- );
261
+ console.error(`${LOG_PREFIX} Unexpected error during JetBrains extension installation:`, error.message);
287
262
  console.debug(`${LOG_PREFIX} Stack trace:`, error.stack);
288
263
  }
289
264
  }
290
265
 
291
266
  // 只在非 CI 环境执行
292
267
  if (!process.env.CI) {
293
- installJetBrainsExtension().catch((error) => {
268
+ installJetBrainsExtension().catch(error => {
294
269
  console.error(`${LOG_PREFIX} Installation failed:`, error.message);
295
270
  });
296
271
  }