stigmergy 1.0.64 → 1.0.66

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": "stigmergy",
3
- "version": "1.0.64",
3
+ "version": "1.0.66",
4
4
  "type": "module",
5
5
  "description": "Stigmergy CLI - Multi-Agents跨AI CLI工具协作系统",
6
6
  "main": "src/main.js",
@@ -79,4 +79,4 @@
79
79
  "bugs": {
80
80
  "url": "https://github.com/ptreezh/stigmergy-CLI-Multi-Agents/issues"
81
81
  }
82
- }
82
+ }
@@ -0,0 +1,290 @@
1
+ /**
2
+ * CLI协同检测器 - 轻量级拦截,增强现有适配器
3
+ * 增量设计,不影响现有系统
4
+ */
5
+
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+ import { spawn, spawnSync } from 'child_process';
9
+ import { EnvironmentStigmergySystem } from './environment_stigmergy_system.js';
10
+
11
+ class CLIInteractionDetector {
12
+ constructor() {
13
+ this.stigmergySystem = new EnvironmentStigmergySystem();
14
+ this.interactionLogFile = path.join(process.cwd(), '.stigmergy-project', 'interactions.log');
15
+
16
+ // 检测配置 - 轻量级,不修改现有CLI行为
17
+ this.detectionConfig = {
18
+ enableCollaborationDetection: true,
19
+ enableContextSharing: true,
20
+ enableSuggestion: true,
21
+ minimalLogging: true
22
+ };
23
+
24
+ // CLI命令映射
25
+ this.cliCommands = {
26
+ 'claude': ['claude', '@anthropic/claude-code'],
27
+ 'gemini': ['gemini', '@google/gemini-cli'],
28
+ 'qwen': ['qwen', 'qwencode'],
29
+ 'iflow': ['iflow', '@iflow-ai/iflow-cli'],
30
+ 'qoder': ['qodercli', 'qoder'],
31
+ 'codebuddy': ['codebuddy', '@tencent-ai/codebuddy-code'],
32
+ 'copilot': ['copilot', 'gh copilot'],
33
+ 'codex': ['codex', 'openai-codex']
34
+ };
35
+ }
36
+
37
+ /**
38
+ * 初始化检测器 - 增量到现有系统
39
+ */
40
+ async initialize() {
41
+ try {
42
+ // 初始化环境线索系统
43
+ await this.stigmergySystem.initializeEnvironmentSystem();
44
+
45
+ // 创建交互日志目录
46
+ const logDir = path.dirname(this.interactionLogFile);
47
+ await fs.mkdir(logDir, { recursive: true });
48
+
49
+ console.log('✅ CLI协同检测器初始化完成');
50
+ return true;
51
+ } catch (error) {
52
+ console.error('❌ CLI协同检测器初始化失败:', error.message);
53
+ return false;
54
+ }
55
+ }
56
+
57
+ /**
58
+ * 检测CLI调用 - 轻量级监控
59
+ */
60
+ async detectCliInvocation(command, args, workingDir = process.cwd()) {
61
+ const cliName = this.detectCliFromCommand(command);
62
+
63
+ if (!cliName) {
64
+ return null;
65
+ }
66
+
67
+ const userInput = args.join(' ');
68
+
69
+ // 检测协作意图
70
+ const collaborationIntent = await this.stigmergySystem.writeEnvironmentSignal(
71
+ cliName,
72
+ userInput,
73
+ { workingDir, command }
74
+ );
75
+
76
+ // 记录交互
77
+ await this.logInteraction({
78
+ type: 'cli_invocation',
79
+ cliName,
80
+ command,
81
+ args: userInput,
82
+ workingDir,
83
+ collaborationIntent,
84
+ timestamp: new Date().toISOString()
85
+ });
86
+
87
+ // 读取环境线索
88
+ const environmentContext = await this.stigmergySystem.readEnvironmentSignals(cliName);
89
+
90
+ return {
91
+ cliName,
92
+ userInput,
93
+ collaborationIntent,
94
+ environmentContext,
95
+ suggestions: environmentContext.collaborationSuggestions
96
+ };
97
+ }
98
+
99
+ /**
100
+ * 从命令检测CLI名称
101
+ */
102
+ detectCliFromCommand(command) {
103
+ const cmd = command.toLowerCase();
104
+
105
+ for (const [cliName, commands] of Object.entries(this.cliCommands)) {
106
+ if (commands.some(cmdStr => cmd.includes(cmdStr))) {
107
+ return cliName;
108
+ }
109
+ }
110
+
111
+ return null;
112
+ }
113
+
114
+ /**
115
+ * 生成上下文增强参数
116
+ */
117
+ async generateContextEnhancedArgs(cliName, originalArgs, context) {
118
+ const enhancedArgs = [...originalArgs];
119
+
120
+ // 如果检测到协作意图,添加上下文
121
+ if (context.collaborationIntent && context.collaborationSuggestions.length > 0) {
122
+ // 生成上下文提示
123
+ const contextHint = this.generateContextHint(context);
124
+ if (contextHint) {
125
+ enhancedArgs.push(`[环境线索: ${contextHint}]`);
126
+ }
127
+ }
128
+
129
+ return enhancedArgs;
130
+ }
131
+
132
+ /**
133
+ * 生成上下文提示
134
+ */
135
+ generateContextHint(context) {
136
+ const suggestions = context.collaborationSuggestions;
137
+
138
+ if (suggestions.length === 0) {
139
+ return '';
140
+ }
141
+
142
+ // 选择最相关的建议
143
+ const topSuggestion = suggestions[0];
144
+
145
+ switch (topSuggestion.type) {
146
+ case 'frequent_collaboration':
147
+ return `最近频繁与${topSuggestion.cli}协作,考虑继续协作`;
148
+ case 'topic_based':
149
+ return `最近在处理"${topSuggestion.topic}"任务,可结合相关工具`;
150
+ default:
151
+ return topSuggestion.suggestion;
152
+ }
153
+ }
154
+
155
+ /**
156
+ * 记录交互日志
157
+ */
158
+ async logInteraction(interaction) {
159
+ try {
160
+ const logLine = JSON.stringify(interaction) + '\n';
161
+ await fs.appendFile(this.interactionLogFile, logLine);
162
+ } catch (error) {
163
+ console.error('❌ 记录交互日志失败:', error.message);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * 创建CLI包装函数 - 最小化包装
169
+ */
170
+ createCliWrapper(cliName) {
171
+ return async (args, options = {}) => {
172
+ // 检测调用
173
+ const detection = await this.detectCliInvocation(cliName, args, options.cwd);
174
+
175
+ // 生成增强参数
176
+ const enhancedArgs = detection
177
+ ? await this.generateContextEnhancedArgs(cliName, args, detection.environmentContext)
178
+ : args;
179
+
180
+ // 执行原始命令
181
+ const command = this.cliCommands[cliName][0]; // 使用第一个命令
182
+ const result = spawnSync(command, enhancedArgs, {
183
+ stdio: 'inherit',
184
+ cwd: options.cwd || process.cwd(),
185
+ env: { ...process.env, ...options.env }
186
+ });
187
+
188
+ // 记录结果
189
+ if (detection) {
190
+ await this.logInteraction({
191
+ type: 'cli_completion',
192
+ cliName,
193
+ args: args.join(' '),
194
+ enhancedArgs: enhancedArgs.join(' '),
195
+ exitCode: result.status,
196
+ timestamp: new Date().toISOString()
197
+ });
198
+ }
199
+
200
+ return result;
201
+ };
202
+ }
203
+
204
+ /**
205
+ * 获取CLI建议
206
+ */
207
+ async getCliSuggestions(cliName) {
208
+ try {
209
+ const environmentContext = await this.stigmergySystem.getCliContext(cliName);
210
+
211
+ return {
212
+ collaborationSuggestions: environmentContext.suggestions,
213
+ recentCollaborations: environmentContext.recentCollaborations,
214
+ contextHints: environmentContext.environmentContext,
215
+ sharedFiles: environmentContext.sharedFiles
216
+ };
217
+ } catch (error) {
218
+ console.error('❌ 获取CLI建议失败:', error.message);
219
+ return { suggestions: [], context: {}, sharedFiles: {} };
220
+ }
221
+ }
222
+
223
+ /**
224
+ * 共享文件到环境
225
+ */
226
+ async shareFileToEnvironment(cliName, filePath, metadata = {}) {
227
+ try {
228
+ const contextDir = path.join(process.cwd(), '.stigmergy-project', 'context-cache');
229
+ await fs.mkdir(contextDir, { recursive: true });
230
+
231
+ const shareData = {
232
+ cliName,
233
+ filePath,
234
+ fileName: path.basename(filePath),
235
+ content: await fs.readFile(filePath, 'utf8'),
236
+ metadata: {
237
+ ...metadata,
238
+ timestamp: new Date().toISOString(),
239
+ size: (await fs.stat(filePath)).size
240
+ }
241
+ };
242
+
243
+ const shareFileName = `${cliName}_${path.basename(filePath)}_${Date.now()}.json`;
244
+ const shareFilePath = path.join(contextDir, shareFileName);
245
+
246
+ await fs.writeFile(shareFilePath, JSON.stringify(shareData, null, 2));
247
+
248
+ console.log(`✅ 文件已共享到环境: ${shareFileName}`);
249
+ return shareFilePath;
250
+ } catch (error) {
251
+ console.error('❌ 共享文件失败:', error.message);
252
+ return null;
253
+ }
254
+ }
255
+
256
+ /**
257
+ * 从环境获取共享文件
258
+ */
259
+ async getSharedFilesFromEnvironment(targetCli = null) {
260
+ try {
261
+ const contextDir = path.join(process.cwd(), '.stigmergy-project', 'context-cache');
262
+ const files = await fs.readdir(contextDir);
263
+
264
+ const sharedFiles = [];
265
+ for (const file of files) {
266
+ if (file.endsWith('.json')) {
267
+ const filePath = path.join(contextDir, file);
268
+ const content = await fs.readFile(filePath, 'utf8');
269
+ const shareData = JSON.parse(content);
270
+
271
+ if (!targetCli || shareData.cliName === targetCli) {
272
+ sharedFiles.push(shareData);
273
+ }
274
+ }
275
+ }
276
+
277
+ // 按时间排序
278
+ sharedFiles.sort((a, b) =>
279
+ new Date(b.metadata.timestamp) - new Date(a.metadata.timestamp)
280
+ );
281
+
282
+ return sharedFiles;
283
+ } catch (error) {
284
+ console.error('❌ 获取共享文件失败:', error.message);
285
+ return [];
286
+ }
287
+ }
288
+ }
289
+
290
+ export { CLIInteractionDetector };
@@ -0,0 +1,454 @@
1
+ /**
2
+ * 环境线索式协同系统 - 增量设计
3
+ * 不影响现有系统功能,增强环境共享机制
4
+ */
5
+
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+ import { homedir } from 'os';
9
+ import { createHash } from 'crypto';
10
+
11
+ class EnvironmentStigmergySystem {
12
+ constructor() {
13
+ // 现有系统路径保持不变
14
+ this.projectRoot = process.cwd();
15
+ this.stigmergyDir = path.join(this.projectRoot, '.stigmergy-project');
16
+ this.contextDir = path.join(this.stigmergyDir, 'context-cache');
17
+ this.collaborationLog = path.join(this.stigmergyDir, 'collaboration.log');
18
+ this.environmentCache = path.join(this.stigmergyDir, 'environment-cache.json');
19
+
20
+ // CLI工具配置映射
21
+ this.cliConfig = {
22
+ 'claude': {
23
+ configFile: '~/.config/claude/config.json',
24
+ historyFile: '~/.config/claude/history.json',
25
+ contextPatterns: ['claude', 'anthropic']
26
+ },
27
+ 'gemini': {
28
+ configFile: '~/.config/gemini/config.json',
29
+ historyFile: '~/.config/gemini/history.json',
30
+ contextPatterns: ['gemini', 'google', 'bard']
31
+ },
32
+ 'qwen': {
33
+ configFile: '~/.config/qwen/config.json',
34
+ historyFile: '~/.config/qwen/history.json',
35
+ contextPatterns: ['qwen', 'qwencode', 'alibaba']
36
+ },
37
+ 'iflow': {
38
+ configFile: '~/.config/iflow/config.json',
39
+ historyFile: '~/.config/iflow/history.json',
40
+ contextPatterns: ['iflow', 'flow', 'mindflow']
41
+ },
42
+ 'qoder': {
43
+ configFile: '~/.config/qoder/config.json',
44
+ historyFile: '~/.config/qoder/history.json',
45
+ contextPatterns: ['qoder', 'code-assistant']
46
+ },
47
+ 'codebuddy': {
48
+ configFile: '~/.config/codebuddy/config.json',
49
+ historyFile: '~/.config/codebuddy/history.json',
50
+ contextPatterns: ['codebuddy', 'tencent', 'buddy']
51
+ },
52
+ 'copilot': {
53
+ configFile: '~/.config/copilot/config.json',
54
+ historyFile: '~/.config/copilot/history.json',
55
+ contextPatterns: ['copilot', 'github', 'gh']
56
+ },
57
+ 'codex': {
58
+ configFile: '~/.config/codex/config.json',
59
+ historyFile: '~/.config/codex/history.json',
60
+ contextPatterns: ['codex', 'openai', 'gpt']
61
+ }
62
+ };
63
+ }
64
+
65
+ /**
66
+ * 初始化环境线索系统 - 增量创建
67
+ */
68
+ async initializeEnvironmentSystem() {
69
+ try {
70
+ // 创建必要的目录(不影响现有结构)
71
+ await fs.mkdir(this.contextDir, { recursive: true });
72
+
73
+ // 初始化环境缓存文件
74
+ await this.initializeEnvironmentCache();
75
+
76
+ console.log('✅ 环境线索协同系统初始化完成');
77
+ return true;
78
+ } catch (error) {
79
+ console.error('❌ 环境线索系统初始化失败:', error.message);
80
+ return false;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * 初始化环境缓存
86
+ */
87
+ async initializeEnvironmentCache() {
88
+ const cacheExists = await fs.access(this.environmentCache)
89
+ .then(() => true)
90
+ .catch(() => false);
91
+
92
+ if (!cacheExists) {
93
+ const initialCache = {
94
+ version: '1.0.0',
95
+ createdAt: new Date().toISOString(),
96
+ lastUpdate: new Date().toISOString(),
97
+ sharedContext: {},
98
+ collaborationHistory: [],
99
+ environmentSignals: {}
100
+ };
101
+
102
+ await fs.writeFile(this.environmentCache, JSON.stringify(initialCache, null, 2));
103
+ }
104
+ }
105
+
106
+ /**
107
+ * 写入环境线索 - CLI调用时自动调用
108
+ */
109
+ async writeEnvironmentSignal(cliName, userInput, context = {}) {
110
+ try {
111
+ const signal = {
112
+ timestamp: new Date().toISOString(),
113
+ cliName,
114
+ userInput,
115
+ context,
116
+ intent: this.detectCollaborationIntent(userInput),
117
+ sessionId: this.generateSessionId()
118
+ };
119
+
120
+ // 更新环境缓存
121
+ await this.updateEnvironmentCache('signal', signal);
122
+
123
+ // 记录协作日志
124
+ await this.logCollaboration(signal);
125
+
126
+ return signal;
127
+ } catch (error) {
128
+ console.error('❌ 写入环境线索失败:', error.message);
129
+ return null;
130
+ }
131
+ }
132
+
133
+ /**
134
+ * 读取环境线索 - CLI启动时自动调用
135
+ */
136
+ async readEnvironmentSignals(cliName) {
137
+ try {
138
+ const cache = await this.loadEnvironmentCache();
139
+ const signals = cache.environmentSignals || {};
140
+
141
+ // 获取最近的协作信号
142
+ const recentSignals = this.getRecentCollaborationSignals(signals, cliName);
143
+
144
+ // 分析环境上下文
145
+ const context = this.analyzeEnvironmentContext(signals, cliName);
146
+
147
+ return {
148
+ signals: recentSignals,
149
+ context,
150
+ collaborationSuggestions: this.generateCollaborationSuggestions(signals, cliName)
151
+ };
152
+ } catch (error) {
153
+ console.error('❌ 读取环境线索失败:', error.message);
154
+ return { signals: [], context: {}, suggestions: [] };
155
+ }
156
+ }
157
+
158
+ /**
159
+ * 检测协作意图
160
+ */
161
+ detectCollaborationIntent(userInput) {
162
+ const patterns = [
163
+ /(?:call|invoke|use|run|execute|ask|tell|request)\s+(?:the\s+)?([a-z]+)\s+(?:cli|tool|assistant|ai)/i,
164
+ /(?:with|using|via|through)\s+([a-z]+)/i,
165
+ /(?:let|have|can|should)\s+([a-z]+)\s+(?:help|assist|process|handle|deal)/i,
166
+ /(?:switch|change|switch to)\s+([a-z]+)/i,
167
+ /(?:in|using)\s+([a-z]+)\s+(?:mode|context)/i
168
+ ];
169
+
170
+ for (const pattern of patterns) {
171
+ const match = userInput.match(pattern);
172
+ if (match) {
173
+ const targetCli = match[1].toLowerCase();
174
+ // 映射到标准CLI名称
175
+ return this.mapToStandardCliName(targetCli);
176
+ }
177
+ }
178
+
179
+ return null;
180
+ }
181
+
182
+ /**
183
+ * 映射到标准CLI名称
184
+ */
185
+ mapToStandardCliName(cliName) {
186
+ const mapping = {
187
+ 'anthropic': 'claude',
188
+ 'google': 'gemini',
189
+ 'bard': 'gemini',
190
+ 'qwencode': 'qwen',
191
+ 'alibaba': 'qwen',
192
+ 'flow': 'iflow',
193
+ 'mindflow': 'iflow',
194
+ 'tencent': 'codebuddy',
195
+ 'buddy': 'codebuddy',
196
+ 'github': 'copilot',
197
+ 'gh': 'copilot',
198
+ 'openai': 'codex',
199
+ 'gpt': 'codex'
200
+ };
201
+
202
+ return mapping[cliName] || cliName;
203
+ }
204
+
205
+ /**
206
+ * 获取最近的协作信号
207
+ */
208
+ getRecentCollaborationSignals(signals, currentCli) {
209
+ const allSignals = Object.values(signals).flat();
210
+ const collaborationSignals = allSignals.filter(signal =>
211
+ signal.intent && signal.intent !== currentCli
212
+ );
213
+
214
+ // 按时间排序,返回最近的5个
215
+ return collaborationSignals
216
+ .sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
217
+ .slice(0, 5);
218
+ }
219
+
220
+ /**
221
+ * 分析环境上下文
222
+ */
223
+ analyzeEnvironmentContext(signals, currentCli) {
224
+ const allSignals = Object.values(signals).flat();
225
+ const recentSignals = allSignals
226
+ .sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp))
227
+ .slice(0, 10);
228
+
229
+ // 分析模式
230
+ const patterns = {
231
+ frequentCollaboration: {},
232
+ commonTopics: [],
233
+ projectContext: {},
234
+ workflowHints: []
235
+ };
236
+
237
+ // 分析协作频率
238
+ recentSignals.forEach(signal => {
239
+ const target = signal.intent;
240
+ if (target && target !== currentCli) {
241
+ patterns.frequentCollaboration[target] =
242
+ (patterns.frequentCollaboration[target] || 0) + 1;
243
+ }
244
+ });
245
+
246
+ // 分析常见主题
247
+ const topics = recentSignals
248
+ .map(signal => this.extractTopics(signal.userInput))
249
+ .flat();
250
+ patterns.commonTopics = this.getMostFrequent(topics, 3);
251
+
252
+ return patterns;
253
+ }
254
+
255
+ /**
256
+ * 生成协作建议
257
+ */
258
+ generateCollaborationSuggestions(signals, currentCli) {
259
+ const context = this.analyzeEnvironmentContext(signals, currentCli);
260
+ const suggestions = [];
261
+
262
+ // 基于协作频率的建议
263
+ Object.entries(context.frequentCollaboration).forEach(([cli, count]) => {
264
+ if (count >= 2) {
265
+ suggestions.push({
266
+ type: 'frequent_collaboration',
267
+ cli,
268
+ reason: `最近频繁与${cli}协作 (${count}次)`,
269
+ suggestion: `考虑使用${cli}继续当前任务`
270
+ });
271
+ }
272
+ });
273
+
274
+ // 基于主题的建议
275
+ context.commonTopics.forEach(topic => {
276
+ suggestions.push({
277
+ type: 'topic_based',
278
+ topic,
279
+ reason: `最近在处理"${topic}"相关任务`,
280
+ suggestion: `考虑使用专门的工具处理${topic}任务`
281
+ });
282
+ });
283
+
284
+ return suggestions;
285
+ }
286
+
287
+ /**
288
+ * 更新环境缓存
289
+ */
290
+ async updateEnvironmentCache(type, data) {
291
+ try {
292
+ const cache = await this.loadEnvironmentCache();
293
+ const timestamp = new Date().toISOString();
294
+
295
+ if (type === 'signal') {
296
+ if (!cache.environmentSignals) {
297
+ cache.environmentSignals = {};
298
+ }
299
+
300
+ const cliKey = data.cliName;
301
+ if (!cache.environmentSignals[cliKey]) {
302
+ cache.environmentSignals[cliKey] = [];
303
+ }
304
+
305
+ cache.environmentSignals[cliKey].push(data);
306
+
307
+ // 保持每个CLI最多100个信号
308
+ if (cache.environmentSignals[cliKey].length > 100) {
309
+ cache.environmentSignals[cliKey] = cache.environmentSignals[cliKey].slice(-100);
310
+ }
311
+ }
312
+
313
+ cache.lastUpdate = timestamp;
314
+ await fs.writeFile(this.environmentCache, JSON.stringify(cache, null, 2));
315
+ } catch (error) {
316
+ console.error('❌ 更新环境缓存失败:', error.message);
317
+ }
318
+ }
319
+
320
+ /**
321
+ * 加载环境缓存
322
+ */
323
+ async loadEnvironmentCache() {
324
+ try {
325
+ const data = await fs.readFile(this.environmentCache, 'utf8');
326
+ return JSON.parse(data);
327
+ } catch (error) {
328
+ console.error('❌ 加载环境缓存失败:', error.message);
329
+ return {};
330
+ }
331
+ }
332
+
333
+ /**
334
+ * 记录协作日志
335
+ */
336
+ async logCollaboration(signal) {
337
+ const logEntry = {
338
+ timestamp: signal.timestamp,
339
+ type: 'collaboration_signal',
340
+ cli: signal.cliName,
341
+ intent: signal.intent,
342
+ userInput: signal.userInput,
343
+ sessionId: signal.sessionId
344
+ };
345
+
346
+ const logLine = JSON.stringify(logEntry) + '\n';
347
+ await fs.appendFile(this.collaborationLog, logLine);
348
+ }
349
+
350
+ /**
351
+ * 生成会话ID
352
+ */
353
+ generateSessionId() {
354
+ return createHash('md5')
355
+ .update(`${Date.now()}-${Math.random()}`)
356
+ .digest('hex')
357
+ .substring(0, 16);
358
+ }
359
+
360
+ /**
361
+ * 提取主题
362
+ */
363
+ extractTopics(userInput) {
364
+ const topics = [];
365
+ const topicPatterns = {
366
+ '代码生成': ['generate', 'create', 'write', 'build', 'implement', 'code'],
367
+ '代码分析': ['analyze', 'review', 'check', 'examine', 'audit'],
368
+ '调试': ['debug', 'fix', 'error', 'issue', 'problem'],
369
+ '文档': ['document', 'explain', 'comment', 'readme'],
370
+ '测试': ['test', 'spec', 'validate', 'verify'],
371
+ '部署': ['deploy', 'build', 'release', 'publish'],
372
+ 'API': ['api', 'endpoint', 'route', 'service'],
373
+ '数据库': ['database', 'db', 'sql', 'query', 'schema'],
374
+ '前端': ['frontend', 'ui', 'component', 'react', 'vue'],
375
+ '后端': ['backend', 'server', 'service', 'microservice']
376
+ };
377
+
378
+ const input = userInput.toLowerCase();
379
+ Object.entries(topicPatterns).forEach(([topic, keywords]) => {
380
+ if (keywords.some(keyword => input.includes(keyword))) {
381
+ topics.push(topic);
382
+ }
383
+ });
384
+
385
+ return topics;
386
+ }
387
+
388
+ /**
389
+ * 获取最频繁的元素
390
+ */
391
+ getMostFrequent(arr, count) {
392
+ const frequency = {};
393
+ arr.forEach(item => {
394
+ frequency[item] = (frequency[item] || 0) + 1;
395
+ });
396
+
397
+ return Object.entries(frequency)
398
+ .sort(([,a], [,b]) => b - a)
399
+ .slice(0, count)
400
+ .map(([item]) => item);
401
+ }
402
+
403
+ /**
404
+ * 为CLI提供环境上下文
405
+ */
406
+ async getCliContext(cliName) {
407
+ const signals = await this.readEnvironmentSignals(cliName);
408
+ return {
409
+ currentSession: this.generateSessionId(),
410
+ recentCollaborations: signals.signals,
411
+ environmentContext: signals.context,
412
+ suggestions: signals.collaborationSuggestions,
413
+ sharedFiles: await this.getSharedFiles(),
414
+ projectSpec: await this.getProjectSpec()
415
+ };
416
+ }
417
+
418
+ /**
419
+ * 获取共享文件
420
+ */
421
+ async getSharedFiles() {
422
+ try {
423
+ const files = await fs.readdir(this.contextDir);
424
+ const sharedFiles = {};
425
+
426
+ for (const file of files) {
427
+ if (file.endsWith('.json')) {
428
+ const filePath = path.join(this.contextDir, file);
429
+ const content = await fs.readFile(filePath, 'utf8');
430
+ sharedFiles[file] = JSON.parse(content);
431
+ }
432
+ }
433
+
434
+ return sharedFiles;
435
+ } catch (error) {
436
+ return {};
437
+ }
438
+ }
439
+
440
+ /**
441
+ * 获取项目规格
442
+ */
443
+ async getProjectSpec() {
444
+ try {
445
+ const specFile = path.join(this.projectRoot, '.stigmergy-project', 'stigmergy-config.json');
446
+ const content = await fs.readFile(specFile, 'utf8');
447
+ return JSON.parse(content);
448
+ } catch (error) {
449
+ return {};
450
+ }
451
+ }
452
+ }
453
+
454
+ export { EnvironmentStigmergySystem };
@@ -0,0 +1,282 @@
1
+ /**
2
+ * 轻量级CLI增强器 - 增量到现有CLI
3
+ * 不修改CLI原生行为,增加协同能力
4
+ */
5
+
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+ import { spawn, spawnSync } from 'child_process';
9
+ import { CLIInteractionDetector } from './cli_interaction_detector.js';
10
+
11
+ class LightweightCLIEnhancer {
12
+ constructor() {
13
+ this.detector = new CLIInteractionDetector();
14
+ this.enhancementConfig = {
15
+ enableContextSharing: true,
16
+ enableCollaborationHints: true,
17
+ enableAutomaticFileSharing: true,
18
+ minimalIntervention: true
19
+ };
20
+ }
21
+
22
+ /**
23
+ * 增强CLI命令 - 最小化介入
24
+ */
25
+ async enhanceCliCommand(cliName, args, options = {}) {
26
+ // 初始化检测器
27
+ await this.detector.initialize();
28
+
29
+ // 检测CLI调用
30
+ const detection = await this.detector.detectCliInvocation(cliName, args, options.cwd);
31
+
32
+ if (!detection) {
33
+ // 如果没有检测到特殊意图,直接执行原命令
34
+ return this.executeOriginalCommand(cliName, args, options);
35
+ }
36
+
37
+ // 生成增强参数
38
+ const enhancedArgs = await this.generateEnhancedArgs(detection);
39
+
40
+ // 执行增强命令
41
+ return this.executeEnhancedCommand(cliName, enhancedArgs, options, detection);
42
+ }
43
+
44
+ /**
45
+ * 执行原始命令 - 完全不改变行为
46
+ */
47
+ async executeOriginalCommand(cliName, args, options = {}) {
48
+ const cliCommands = {
49
+ 'claude': ['claude', '@anthropic/claude-code'],
50
+ 'gemini': ['gemini', '@google/gemini-cli'],
51
+ 'qwen': ['qwen', 'qwencode'],
52
+ 'iflow': ['iflow', '@iflow-ai/iflow-cli'],
53
+ 'qoder': ['qodercli', 'qoder'],
54
+ 'codebuddy': ['codebuddy', '@tencent-ai/codebuddy-code'],
55
+ 'copilot': ['copilot', 'gh copilot'],
56
+ 'codex': ['codex', 'openai-codex']
57
+ };
58
+
59
+ const command = cliCommands[cliName]?.[0] || cliName;
60
+
61
+ return spawnSync(command, args, {
62
+ stdio: 'inherit',
63
+ cwd: options.cwd || process.cwd(),
64
+ env: { ...process.env, ...options.env }
65
+ });
66
+ }
67
+
68
+ /**
69
+ * 生成增强参数
70
+ */
71
+ async generateEnhancedArgs(detection) {
72
+ const enhancedArgs = [...detection.userInput.split(' ')];
73
+
74
+ // 添加上下文线索
75
+ if (this.enhancementConfig.enableContextSharing && detection.environmentContext) {
76
+ const contextHint = this.generateContextHint(detection);
77
+ if (contextHint) {
78
+ enhancedArgs.push(`[上下文: ${contextHint}]`);
79
+ }
80
+ }
81
+
82
+ // 添加协作提示
83
+ if (this.enhancementConfig.enableCollaborationHints && detection.suggestions.length > 0) {
84
+ const collaborationHint = this.generateCollaborationHint(detection.suggestions[0]);
85
+ if (collaborationHint) {
86
+ enhancedArgs.push(`[协作提示: ${collaborationHint}]`);
87
+ }
88
+ }
89
+
90
+ return enhancedArgs;
91
+ }
92
+
93
+ /**
94
+ * 生成上下文提示
95
+ */
96
+ generateContextHint(detection) {
97
+ const context = detection.environmentContext;
98
+
99
+ if (context.frequentCollaboration && Object.keys(context.frequentCollaboration).length > 0) {
100
+ const frequentCli = Object.keys(context.frequentCollaboration)[0];
101
+ return `最近经常与${frequentCli}协作`;
102
+ }
103
+
104
+ if (context.commonTopics && context.commonTopics.length > 0) {
105
+ return `最近在处理${context.commonTopics[0]}相关任务`;
106
+ }
107
+
108
+ return '';
109
+ }
110
+
111
+ /**
112
+ * 生成协作提示
113
+ */
114
+ generateCollaborationHint(suggestion) {
115
+ switch (suggestion.type) {
116
+ case 'frequent_collaboration':
117
+ return `建议后续可使用${suggestion.cli}继续`;
118
+ case 'topic_based':
119
+ return `建议使用专门工具处理${suggestion.topic}任务`;
120
+ default:
121
+ return suggestion.suggestion;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * 执行增强命令
127
+ */
128
+ async executeEnhancedCommand(cliName, enhancedArgs, options, detection) {
129
+ // 先执行原始命令
130
+ const result = await this.executeOriginalCommand(cliName, enhancedArgs, options);
131
+
132
+ // 后台处理协作逻辑
133
+ if (this.enhancementConfig.enableAutomaticFileSharing) {
134
+ await this.handleAutomaticFileSharing(detection);
135
+ }
136
+
137
+ // 记录协作结果
138
+ await this.logCollaborationResult(detection, result);
139
+
140
+ return result;
141
+ }
142
+
143
+ /**
144
+ * 处理自动文件共享
145
+ */
146
+ async handleAutomaticFileSharing(detection) {
147
+ if (!detection.collaborationIntent) {
148
+ return;
149
+ }
150
+
151
+ try {
152
+ // 检测当前目录中的重要文件
153
+ const importantFiles = await this.detectImportantFiles();
154
+
155
+ // 自动共享相关文件到环境
156
+ for (const file of importantFiles) {
157
+ await this.detector.shareFileToEnvironment(
158
+ detection.cliName,
159
+ file.filePath,
160
+ {
161
+ autoShared: true,
162
+ collaborationIntent: detection.collaborationIntent,
163
+ relevanceScore: file.relevanceScore
164
+ }
165
+ );
166
+ }
167
+ } catch (error) {
168
+ console.error('❌ 自动文件共享失败:', error.message);
169
+ }
170
+ }
171
+
172
+ /**
173
+ * 检测重要文件
174
+ */
175
+ async detectImportantFiles() {
176
+ const workingDir = process.cwd();
177
+ const files = await fs.readdir(workingDir);
178
+
179
+ const importantPatterns = {
180
+ 'README': ['README.md', 'README.txt', 'readme.md'],
181
+ 'Config': ['package.json', 'requirements.txt', 'pyproject.toml', 'Cargo.toml'],
182
+ 'Code': ['src/', 'lib/', 'app/', 'main.py', 'main.js', 'index.js', 'index.py'],
183
+ 'Project': ['project.json', 'project.toml', '.stigmergy-project/']
184
+ };
185
+
186
+ const importantFiles = [];
187
+
188
+ for (const file of files) {
189
+ let relevanceScore = 0;
190
+ let fileType = '';
191
+
192
+ for (const [type, patterns] of Object.entries(importantPatterns)) {
193
+ if (patterns.some(pattern => file.includes(pattern) || file.startsWith(pattern))) {
194
+ relevanceScore += 2;
195
+ fileType = type;
196
+ }
197
+ }
198
+
199
+ if (relevanceScore > 0) {
200
+ const filePath = path.join(workingDir, file);
201
+ try {
202
+ const stats = await fs.stat(filePath);
203
+ importantFiles.push({
204
+ fileName: file,
205
+ filePath,
206
+ fileType,
207
+ relevanceScore,
208
+ size: stats.size,
209
+ modified: stats.mtime
210
+ });
211
+ } catch (error) {
212
+ // 忽略无法访问的文件
213
+ }
214
+ }
215
+ }
216
+
217
+ // 按相关性排序
218
+ return importantFiles
219
+ .sort((a, b) => b.relevanceScore - a.relevanceScore)
220
+ .slice(0, 5); // 最多共享5个文件
221
+ }
222
+
223
+ /**
224
+ * 记录协作结果
225
+ */
226
+ async logCollaborationResult(detection, result) {
227
+ try {
228
+ const logEntry = {
229
+ timestamp: new Date().toISOString(),
230
+ type: 'collaboration_result',
231
+ cliName: detection.cliName,
232
+ userInput: detection.userInput,
233
+ collaborationIntent: detection.collaborationIntent,
234
+ exitCode: result.status,
235
+ success: result.status === 0,
236
+ enhanced: true
237
+ };
238
+
239
+ const logFile = path.join(process.cwd(), '.stigmergy-project', 'collaboration_results.log');
240
+ await fs.mkdir(path.dirname(logFile), { recursive: true });
241
+
242
+ const logLine = JSON.stringify(logEntry) + '\n';
243
+ await fs.appendFile(logFile, logLine);
244
+ } catch (error) {
245
+ console.error('❌ 记录协作结果失败:', error.message);
246
+ }
247
+ }
248
+
249
+ /**
250
+ * 创建CLI命令包装器
251
+ */
252
+ createCliWrapper(cliName) {
253
+ return async (...args) => {
254
+ return await this.enhanceCliCommand(cliName, args);
255
+ };
256
+ }
257
+
258
+ /**
259
+ * 获取当前环境状态
260
+ */
261
+ async getEnvironmentStatus() {
262
+ try {
263
+ const suggestions = await this.detector.getCliSuggestions('claude'); // 以claude为例
264
+ const sharedFiles = await this.detector.getSharedFilesFromEnvironment();
265
+
266
+ return {
267
+ systemInitialized: true,
268
+ featuresEnabled: this.enhancementConfig,
269
+ availableSuggestions: suggestions.collaborationSuggestions.length,
270
+ sharedFilesCount: sharedFiles.length,
271
+ recentCollaborations: suggestions.recentCollaborations.length
272
+ };
273
+ } catch (error) {
274
+ return {
275
+ systemInitialized: false,
276
+ error: error.message
277
+ };
278
+ }
279
+ }
280
+ }
281
+
282
+ export { LightweightCLIEnhancer };
@@ -17,7 +17,7 @@ import re
17
17
 
18
18
  # 导入编码安全模块
19
19
  sys.path.append(str(Path(__file__).parent))
20
- from cross_platform_encoding import safe_file_write, safe_file_read
20
+ from cross_platform_encoding import SafeFileWriter, SafeFileReader
21
21
 
22
22
  @dataclass
23
23
  class RealCLISpecs:
@@ -198,14 +198,9 @@ class VerifiedCrossCLISystem:
198
198
  )
199
199
  }
200
200
 
201
- # 内存系统
202
- self.memory_dir = Path.home() / '.verified_cross_cli'
203
- self.memory_dir.mkdir(exist_ok=True)
204
- self.context_dir = self.memory_dir / 'context_files'
205
- self.context_dir.mkdir(exist_ok=True)
206
-
207
- self.call_history_file = self.memory_dir / 'verified_call_history.json'
208
- self.context_cache_file = self.memory_dir / 'context_cache.json'
201
+ # 初始化文件操作工具
202
+ self.file_writer = SafeFileWriter()
203
+ self.file_reader = SafeFileReader()
209
204
 
210
205
  def check_cli_availability(self, cli_name: str) -> Dict[str, Any]:
211
206
  """检查CLI可用性 - 基于真实规范"""
@@ -740,11 +735,7 @@ export {status['api_env']}='your-api-key-here'
740
735
  """
741
736
  for i, method in enumerate(status['available_methods']):
742
737
  cmd = self._build_verified_command(method, spec, request, context_file, True)
743
- manual_guidance += f"#### 方法 {i+1}:
744
- ```bash
745
- {cmd}
746
- ```
747
- \\n"
738
+ manual_guidance += f"#### 方法 {i+1}:\n```bash\n{cmd}\n```\n"
748
739
 
749
740
  manual_guidance += f"""
750
741
  ### 原始错误信息:
@@ -276,6 +276,39 @@ async function copyPluginExtensions(availableCLIs) {
276
276
  console.log('✅ 插件扩展复制完成');
277
277
  }
278
278
 
279
+ // 生成全局配置文件
280
+ async function generateGlobalConfig(availableCLIs) {
281
+ console.log('\n📝 生成全局配置文件...');
282
+
283
+ const globalConfigDir = join(homedir(), '.stigmergy-cli');
284
+ const globalConfigPath = join(globalConfigDir, 'global-config.json');
285
+
286
+ const timestamp = new Date().toISOString();
287
+ const config = {
288
+ version: '1.0.0',
289
+ generatedAt: timestamp,
290
+ platform: process.platform,
291
+ nodeVersion: process.version,
292
+ availableTools: availableCLIs.filter(cli => cli.available).map(cli => ({
293
+ name: cli.name,
294
+ displayName: cli.displayName,
295
+ path: cli.path.replace(/\r$/, ''), // 清理路径中的回车符
296
+ description: cli.description,
297
+ required: cli.required
298
+ })),
299
+ scanResults: availableCLIs
300
+ };
301
+
302
+ try {
303
+ await fs.writeFile(globalConfigPath, JSON.stringify(config, null, 2), 'utf8');
304
+ console.log(`✅ 全局配置文件已生成: ${globalConfigPath}`);
305
+ return true;
306
+ } catch (error) {
307
+ console.log(`⚠️ 无法生成全局配置文件: ${error.message}`);
308
+ return false;
309
+ }
310
+ }
311
+
279
312
  // 生成全局记忆配置MD文件
280
313
  async function generateGlobalMemoryConfigMD(availableCLIs) {
281
314
  console.log('\n📝 生成全局记忆配置MD文件...');
@@ -356,12 +389,18 @@ async function main() {
356
389
  // 5. 复制各个CLI工具所必须的插件扩展到各个CLI安装的路径中
357
390
  await copyPluginExtensions(updatedAvailableCLIs);
358
391
 
359
- // 6. 生成全局记忆配置MD文件
360
- await generateGlobalMemoryConfigMD(updatedAvailableCLIs);
392
+ // 6. 生成全局配置文件和全局记忆配置MD文件
393
+ const configGenerated = await generateGlobalConfig(updatedAvailableCLIs);
394
+ if (configGenerated) {
395
+ await generateGlobalMemoryConfigMD(updatedAvailableCLIs);
396
+ }
361
397
  } else {
362
398
  // 如果没有安装新工具,直接处理已有的工具
363
- await copyPluginExtensions(availableCLIs);
364
- await generateGlobalMemoryConfigMD(availableCLIs);
399
+ const configGenerated = await generateGlobalConfig(availableCLIs);
400
+ if (configGenerated) {
401
+ await copyPluginExtensions(availableCLIs);
402
+ await generateGlobalMemoryConfigMD(availableCLIs);
403
+ }
365
404
  }
366
405
 
367
406
  console.log('\n🎉 Stigmergy CLI 安装后设置完成!');
@@ -377,9 +416,7 @@ async function main() {
377
416
  }
378
417
 
379
418
  // 运行主函数
380
- if (import.meta.url === `file://${process.argv[1]}`) {
381
- main().catch(error => {
382
- console.error(`❌ 脚本执行失败: ${error.message}`);
383
- process.exit(1);
384
- });
385
- }
419
+ main().catch(error => {
420
+ console.error(`❌ 脚本执行失败: ${error.message}`);
421
+ process.exit(1);
422
+ });