stigmergy 1.0.68 → 1.0.70

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.
Files changed (102) hide show
  1. package/README.en.md +306 -300
  2. package/README.md +469 -301
  3. package/package.json +97 -81
  4. package/scripts/publish.js +268 -0
  5. package/scripts/simple-publish.js +59 -0
  6. package/src/index.js +12 -0
  7. package/test/enhanced-main-alignment.test.js +298 -0
  8. package/test/hook-system-integration-test.js +307 -0
  9. package/test/natural-language-skills-test.js +320 -0
  10. package/test/nl-integration-test.js +179 -0
  11. package/test/parameter-parsing-test.js +143 -0
  12. package/test/real-test.js +435 -0
  13. package/test/system-compatibility-test.js +447 -0
  14. package/test/tdd-fixes-test.js +211 -0
  15. package/test/third-party-skills-test.js +321 -0
  16. package/test/tool-selection-integration-test.js +157 -0
  17. package/test/unit/cli-scanner.test.js +291 -0
  18. package/test/unit/cross-cli-executor.test.js +399 -0
  19. package/src/adapters/claude/__init__.py +0 -13
  20. package/src/adapters/claude/claude_skills_integration.py +0 -609
  21. package/src/adapters/claude/hook_adapter.py +0 -663
  22. package/src/adapters/claude/install_claude_integration.py +0 -265
  23. package/src/adapters/claude/skills_hook_adapter.py +0 -841
  24. package/src/adapters/claude/standalone_claude_adapter.py +0 -384
  25. package/src/adapters/cline/__init__.py +0 -20
  26. package/src/adapters/cline/config.py +0 -108
  27. package/src/adapters/cline/install_cline_integration.py +0 -617
  28. package/src/adapters/cline/mcp_server.py +0 -713
  29. package/src/adapters/cline/standalone_cline_adapter.py +0 -459
  30. package/src/adapters/codebuddy/__init__.py +0 -13
  31. package/src/adapters/codebuddy/buddy_adapter.py +0 -1125
  32. package/src/adapters/codebuddy/install_codebuddy_integration.py +0 -279
  33. package/src/adapters/codebuddy/skills_hook_adapter.py +0 -672
  34. package/src/adapters/codebuddy/skills_integration.py +0 -395
  35. package/src/adapters/codebuddy/standalone_codebuddy_adapter.py +0 -403
  36. package/src/adapters/codex/__init__.py +0 -11
  37. package/src/adapters/codex/base.py +0 -46
  38. package/src/adapters/codex/install_codex_integration.py +0 -311
  39. package/src/adapters/codex/mcp_server.py +0 -493
  40. package/src/adapters/codex/natural_language_parser.py +0 -82
  41. package/src/adapters/codex/slash_command_adapter.py +0 -326
  42. package/src/adapters/codex/standalone_codex_adapter.py +0 -362
  43. package/src/adapters/copilot/__init__.py +0 -13
  44. package/src/adapters/copilot/install_copilot_integration.py +0 -564
  45. package/src/adapters/copilot/mcp_adapter.py +0 -772
  46. package/src/adapters/copilot/mcp_server.py +0 -168
  47. package/src/adapters/copilot/standalone_copilot_adapter.py +0 -114
  48. package/src/adapters/gemini/__init__.py +0 -13
  49. package/src/adapters/gemini/extension_adapter.py +0 -690
  50. package/src/adapters/gemini/install_gemini_integration.py +0 -257
  51. package/src/adapters/gemini/standalone_gemini_adapter.py +0 -366
  52. package/src/adapters/iflow/__init__.py +0 -7
  53. package/src/adapters/iflow/hook_adapter.py +0 -1038
  54. package/src/adapters/iflow/hook_installer.py +0 -536
  55. package/src/adapters/iflow/install_iflow_integration.py +0 -271
  56. package/src/adapters/iflow/official_hook_adapter.py +0 -1272
  57. package/src/adapters/iflow/standalone_iflow_adapter.py +0 -48
  58. package/src/adapters/iflow/workflow_adapter.py +0 -793
  59. package/src/adapters/qoder/hook_installer.py +0 -732
  60. package/src/adapters/qoder/install_qoder_integration.py +0 -265
  61. package/src/adapters/qoder/notification_hook_adapter.py +0 -863
  62. package/src/adapters/qoder/standalone_qoder_adapter.py +0 -48
  63. package/src/adapters/qwen/__init__.py +0 -17
  64. package/src/adapters/qwencode/__init__.py +0 -13
  65. package/src/adapters/qwencode/inheritance_adapter.py +0 -818
  66. package/src/adapters/qwencode/install_qwencode_integration.py +0 -276
  67. package/src/adapters/qwencode/standalone_qwencode_adapter.py +0 -399
  68. package/src/atomic_collaboration_handler.py +0 -461
  69. package/src/cli_collaboration_agent.py +0 -697
  70. package/src/collaboration/hooks.py +0 -315
  71. package/src/core/__init__.py +0 -21
  72. package/src/core/ai_environment_scanner.py +0 -331
  73. package/src/core/base_adapter.py +0 -220
  74. package/src/core/cli_hook_integration.py +0 -406
  75. package/src/core/cross_cli_executor.py +0 -713
  76. package/src/core/cross_cli_mapping.py +0 -1165
  77. package/src/core/cross_platform_encoding.py +0 -365
  78. package/src/core/cross_platform_safe_cli.py +0 -894
  79. package/src/core/direct_cli_executor.py +0 -805
  80. package/src/core/direct_cli_hook_system.py +0 -958
  81. package/src/core/enhanced_init_processor.py +0 -467
  82. package/src/core/graceful_cli_executor.py +0 -912
  83. package/src/core/md_enhancer.py +0 -342
  84. package/src/core/md_generator.py +0 -619
  85. package/src/core/models.py +0 -218
  86. package/src/core/parser.py +0 -108
  87. package/src/core/real_cli_hook_system.py +0 -852
  88. package/src/core/real_cross_cli_system.py +0 -925
  89. package/src/core/verified_cross_cli_system.py +0 -961
  90. package/src/deploy.js +0 -737
  91. package/src/enhanced-main.js +0 -626
  92. package/src/enhanced_deploy.js +0 -303
  93. package/src/enhanced_universal_cli_setup.py +0 -930
  94. package/src/kimi_wrapper.py +0 -104
  95. package/src/main.js +0 -1309
  96. package/src/shell_integration.py +0 -398
  97. package/src/simple-main.js +0 -315
  98. package/src/smart_router_creator.py +0 -323
  99. package/src/universal_cli_setup.py +0 -1289
  100. package/src/utils/__init__.py +0 -12
  101. package/src/utils/cli_detector.py +0 -445
  102. package/src/utils/file_utils.py +0 -246
@@ -1,461 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- 智能体协作系统 - 原子性背景管理器
5
- 实现多智能体安全协作,防止任务重复认领
6
- """
7
-
8
- import json
9
- import time
10
- import threading
11
- import subprocess
12
- from pathlib import Path
13
- from datetime import datetime
14
- import tempfile
15
- import os
16
-
17
-
18
- class AtomicFileHandler:
19
- """原子性文件处理器 - 确保并发安全"""
20
-
21
- def __init__(self, file_path):
22
- self.file_path = Path(file_path)
23
- self.lock_path = self.file_path.with_suffix(self.file_path.suffix + '.lock')
24
- self.lock = threading.Lock() # 内存锁,防止同一进程内的并发冲突
25
-
26
- def atomic_read(self):
27
- """原子性读取文件"""
28
- max_retries = 10
29
- for attempt in range(max_retries):
30
- try:
31
- # 等待外部锁释放(通过文件的存在)
32
- while self.lock_path.exists():
33
- time.sleep(0.01)
34
-
35
- # 检查文件是否存在
36
- if not self.file_path.exists():
37
- return None
38
-
39
- with open(self.file_path, 'r', encoding='utf-8') as f:
40
- return json.load(f)
41
- except json.JSONDecodeError:
42
- # 文件可能在写入过程中,等待重试
43
- if attempt == max_retries - 1:
44
- raise
45
- time.sleep(0.01 * (attempt + 1))
46
- except Exception as e:
47
- if attempt == max_retries - 1:
48
- raise
49
- time.sleep(0.01 * (attempt + 1))
50
-
51
- def atomic_write(self, data):
52
- """原子性写入文件"""
53
- with self.lock: # 先获取内存锁
54
- # 创建临时文件
55
- temp_path = self.file_path.with_suffix(self.file_path.suffix + '.tmp')
56
-
57
- try:
58
- # 创建锁文件,表明正在进行写操作
59
- self.lock_path.touch()
60
-
61
- # 写入临时文件
62
- with open(temp_path, 'w', encoding='utf-8') as f:
63
- json.dump(data, f, ensure_ascii=False, indent=2)
64
-
65
- # 原子性移动 - 在大多数系统上是原子操作
66
- temp_path.replace(self.file_path)
67
-
68
- return True
69
-
70
- except Exception as e:
71
- print(f"原子写入失败: {e}")
72
- # 确保清理临时文件
73
- if temp_path.exists():
74
- try:
75
- temp_path.unlink()
76
- except:
77
- pass
78
- return False
79
- finally:
80
- # 无论成功与否,都要释放锁
81
- if self.lock_path.exists():
82
- try:
83
- self.lock_path.unlink()
84
- except:
85
- pass
86
-
87
-
88
- class SharedProjectContext:
89
- """共享项目背景管理器 - 实现Stigmergy机制"""
90
-
91
- def __init__(self, project_path):
92
- self.project_path = Path(project_path)
93
- self.spec_file = self.project_path / "PROJECT_SPEC.json"
94
- self.handler = AtomicFileHandler(self.spec_file)
95
-
96
- # 确保项目背景文件存在
97
- self._ensure_spec_exists()
98
-
99
- def _ensure_spec_exists(self):
100
- """确保项目背景文件存在"""
101
- if not self.spec_file.exists():
102
- default_spec = {
103
- "project_name": self.project_path.name,
104
- "created_at": datetime.now().isoformat(),
105
- "status": "active",
106
- "tasks": {},
107
- "collaboration_history": [],
108
- "current_state": {
109
- "active_task": None,
110
- "completed_tasks": [],
111
- "pending_tasks": [],
112
- "assigned_tasks": {} # 活跃分配,用于防止重复认领
113
- },
114
- "last_updated": datetime.now().isoformat()
115
- }
116
- self.handler.atomic_write(default_spec)
117
-
118
- def claim_available_task(self, agent_name):
119
- """智能体认领可用任务 - 原子性操作防止重复认领"""
120
- max_retries = 5
121
-
122
- for attempt in range(max_retries):
123
- try:
124
- # 读取最新状态
125
- spec = self.handler.atomic_read()
126
- if not spec:
127
- return None, None
128
-
129
- # 优先获取直接分配给此智能体的任务
130
- for task_id, task in spec["tasks"].items():
131
- if task.get("assigned_to") == agent_name and task["status"] == "pending":
132
- # 尝试设置为进行中状态
133
- if self._set_task_in_progress(spec, task_id, agent_name):
134
- return task_id, task
135
-
136
- # 然后获取未分配但可处理的任务
137
- for task_id, task in spec["tasks"].items():
138
- if (task["status"] == "pending" and
139
- task.get("assigned_to") is None and
140
- self._can_handle_task(task, agent_name)):
141
-
142
- # 尝试认领此任务
143
- if self._claim_task_for_agent(spec, task_id, agent_name):
144
- # 记录协作日志
145
- self._add_collaboration_log(
146
- spec,
147
- f"智能体 {agent_name} 认领任务 {task_id}: {task['description']}"
148
- )
149
- return task_id, task
150
-
151
- # 没有任务可认领
152
- return None, None
153
-
154
- except Exception as e:
155
- if attempt == max_retries - 1:
156
- print(f"认领任务失败: {e}")
157
- return None, None
158
- time.sleep(0.01 * (attempt + 1))
159
-
160
- return None, None
161
-
162
- def _claim_task_for_agent(self, spec, task_id, agent_name):
163
- """认领任务 - 确保原子性"""
164
- # 检查是否已被他人认领
165
- current_task = spec["tasks"][task_id]
166
- if current_task.get("assigned_to") is not None:
167
- return False # 任务已被其他人认领
168
-
169
- # 检查活跃分配列表(额外安全检查)
170
- if task_id in spec["current_state"]["assigned_tasks"]:
171
- return False # 任务已在活跃分配中
172
-
173
- # 认领任务
174
- spec["tasks"][task_id]["assigned_to"] = agent_name
175
- spec["tasks"][task_id]["status"] = "in_progress"
176
- spec["tasks"][task_id]["started_at"] = datetime.now().isoformat()
177
-
178
- # 添加到活跃分配列表
179
- spec["current_state"]["assigned_tasks"][task_id] = {
180
- "claimed_by": agent_name,
181
- "claimed_at": datetime.now().isoformat()
182
- }
183
-
184
- spec["last_updated"] = datetime.now().isoformat()
185
-
186
- # 原子性写入
187
- return self.handler.atomic_write(spec)
188
-
189
- def _set_task_in_progress(self, spec, task_id, agent_name):
190
- """设置已分配任务为进行中状态"""
191
- if spec["tasks"][task_id]["status"] == "in_progress":
192
- return False # 任务已在处理中
193
-
194
- spec["tasks"][task_id]["status"] = "in_progress"
195
- spec["tasks"][task_id]["started_at"] = datetime.now().isoformat()
196
-
197
- spec["current_state"]["active_task"] = task_id
198
- spec["last_updated"] = datetime.now().isoformat()
199
-
200
- return self.handler.atomic_write(spec)
201
-
202
- def update_task_status(self, task_id, status, result=None, completed_by=None):
203
- """更新任务状态 - 原子性操作"""
204
- max_retries = 5
205
-
206
- for attempt in range(max_retries):
207
- try:
208
- spec = self.handler.atomic_read()
209
- if not spec or task_id not in spec["tasks"]:
210
- return False
211
-
212
- old_status = spec["tasks"][task_id]["status"]
213
-
214
- # 更新状态
215
- spec["tasks"][task_id]["status"] = status
216
- spec["tasks"][task_id]["result"] = result
217
- spec["tasks"][task_id]["completed_by"] = completed_by
218
- spec["tasks"][task_id]["completed_at"] = datetime.now().isoformat() if status == "completed" else None
219
-
220
- # 更新全局状态
221
- if status == "completed":
222
- if task_id in spec["current_state"]["assigned_tasks"]:
223
- del spec["current_state"]["assigned_tasks"][task_id]
224
- spec["current_state"]["completed_tasks"].append(task_id)
225
- if task_id in spec["current_state"]["pending_tasks"]:
226
- spec["current_state"]["pending_tasks"].remove(task_id)
227
- spec["current_state"]["active_task"] = None
228
- elif status == "failed":
229
- if task_id in spec["current_state"]["assigned_tasks"]:
230
- del spec["current_state"]["assigned_tasks"][task_id]
231
- spec["current_state"]["active_task"] = None
232
-
233
- spec["last_updated"] = datetime.now().isoformat()
234
-
235
- if self.handler.atomic_write(spec):
236
- # 添加完成日志
237
- if status == "completed":
238
- self._add_collaboration_log(
239
- spec,
240
- f"任务 {task_id} 已由 {completed_by} 完成: {spec['tasks'][task_id]['description'][:100]}..."
241
- )
242
- elif status == "failed":
243
- self._add_collaboration_log(
244
- spec,
245
- f"任务 {task_id} 执行失败: {result[:100] if result else 'Unknown error'}"
246
- )
247
- return True
248
- else:
249
- return False
250
-
251
- except Exception as e:
252
- if attempt == max_retries - 1:
253
- print(f"更新任务状态失败: {e}")
254
- return False
255
- time.sleep(0.01 * (attempt + 1))
256
-
257
- return False
258
-
259
- def _can_handle_task(self, task, agent_name):
260
- """判断智能体是否能处理任务"""
261
- task_desc = task["description"].lower()
262
-
263
- # 根据智能体名称判断处理能力
264
- agent_capabilities = {
265
- "claude": ["analyze", "review", "explain", "logic", "reasoning", "debug"],
266
- "gemini": ["translate", "document", "write", "story", "creative"],
267
- "kimi": ["long", "research", "content", "analyze"],
268
- "qwen": ["chinese", "中文", "translate", "chat", "dialogue"],
269
- "codebuddy": ["code", "function", "program", "bug", "refactor", "optimize"],
270
- "qodercli": ["generate", "create", "template", "scaffold"],
271
- "iflow": ["workflow", "process", "automate", "task"],
272
- "ollama": ["local", "offline", "private", "model"]
273
- }
274
-
275
- capabilities = agent_capabilities.get(agent_name.lower(), [])
276
- return any(cap in task_desc for cap in capabilities)
277
-
278
- def _add_collaboration_log(self, spec, message):
279
- """添加协作日志"""
280
- log_entry = {
281
- "timestamp": datetime.now().isoformat(),
282
- "message": message,
283
- "updated_at": datetime.now().isoformat()
284
- }
285
- spec["collaboration_history"].append(log_entry)
286
- spec["last_updated"] = datetime.now().isoformat()
287
-
288
- def create_task(self, task_type, description, assigned_to=None, priority="medium"):
289
- """创建新任务 - 确保原子性"""
290
- task_id = f"{task_type}_{int(time.time())}_{len(self.handler.atomic_read()['tasks'])}"
291
-
292
- max_retries = 5
293
- for attempt in range(max_retries):
294
- try:
295
- spec = self.handler.atomic_read()
296
- if not spec:
297
- spec = {
298
- "project_name": self.project_path.name,
299
- "tasks": {},
300
- "collaboration_history": [],
301
- "current_state": {
302
- "active_task": None,
303
- "completed_tasks": [],
304
- "pending_tasks": [],
305
- "assigned_tasks": {}
306
- }
307
- }
308
-
309
- task = {
310
- "id": task_id,
311
- "type": task_type,
312
- "description": description,
313
- "assigned_to": assigned_to,
314
- "status": "pending",
315
- "priority": priority,
316
- "created_at": datetime.now().isoformat(),
317
- "result": None,
318
- "completed_by": None,
319
- "completed_at": None
320
- }
321
-
322
- spec["tasks"][task_id] = task
323
- spec["current_state"]["pending_tasks"].append(task_id)
324
-
325
- # 添加创建日志
326
- self._add_collaboration_log(
327
- spec,
328
- f"创建任务 {task_id} ({task_type}): {description}"
329
- )
330
-
331
- if self.handler.atomic_write(spec):
332
- return task_id
333
- else:
334
- time.sleep(0.01 * (attempt + 1))
335
-
336
- except Exception as e:
337
- if attempt == max_retries - 1:
338
- print(f"创建任务失败: {e}")
339
- return None
340
- time.sleep(0.01 * (attempt + 1))
341
-
342
- return None
343
-
344
-
345
- class CLICollaborationAgent:
346
- """CLI协作智能体 - 基于共享背景的协作"""
347
-
348
- def __init__(self, agent_name, project_path):
349
- self.agent_name = agent_name
350
- self.project_context = SharedProjectContext(project_path)
351
-
352
- def work_on_context(self):
353
- """基于共享背景工作"""
354
- # 尝试认领任务
355
- task_id, task = self.project_context.claim_available_task(self.agent_name)
356
-
357
- if not task_id:
358
- return False # 没有可处理的任务
359
-
360
- print(f"智能体 {self.agent_name} 开始处理任务 {task_id}")
361
-
362
- # 执行任务
363
- success, result = self._execute_task(task)
364
-
365
- # 更新任务状态
366
- if success:
367
- self.project_context.update_task_status(task_id, "completed", result, self.agent_name)
368
- print(f"智能体 {self.agent_name} 成功完成任务 {task_id}")
369
- else:
370
- self.project_context.update_task_status(task_id, "failed", result, self.agent_name)
371
- print(f"智能体 {self.agent_name} 任务 {task_id} 执行失败")
372
-
373
- return success
374
-
375
- def _execute_task(self, task):
376
- """执行具体任务"""
377
- # 这里实现具体的任务执行逻辑
378
- # 根据任务类型调用相应的CLI工具
379
- try:
380
- # 这里是一个模拟执行
381
- # 实际实现会根据任务类型调用对应的工具
382
- import subprocess
383
- result = subprocess.run(
384
- ["echo", f"Processed: {task['description']} by {self.agent_name}"],
385
- capture_output=True,
386
- text=True
387
- )
388
- return True, result.stdout
389
- except Exception as e:
390
- return False, f"执行失败: {e}"
391
-
392
-
393
- def demo_concurrent_agents():
394
- """演示并发智能体协作"""
395
- import threading
396
- import random
397
-
398
- # 创建项目目录
399
- project_dir = Path("demo_concurrent_collaboration")
400
- project_dir.mkdir(exist_ok=True)
401
-
402
- # 创建一个共享背景管理器
403
- context = SharedProjectContext(project_dir)
404
-
405
- # 创建一些任务
406
- context.create_task("coding", "编写计算器应用的加法功能", priority="high")
407
- context.create_task("review", "审查登录功能的代码", priority="medium")
408
- context.create_task("documentation", "为API生成使用文档", priority="low")
409
- context.create_task("testing", "为订单处理系统生成单元测试", priority="high")
410
-
411
- print("📝 创建了4个任务:")
412
- spec = context.handler.atomic_read()
413
- for task_id, task in spec["tasks"].items():
414
- print(f" {task_id}: {task['description']} (status: {task['status']})")
415
-
416
- # 模拟多个智能体并发工作
417
- agents = ["claude", "gemini", "codebuddy", "qwen"]
418
-
419
- def agent_worker(agent_name):
420
- """智能体工作线程"""
421
- agent = CLICollaborationAgent(agent_name, project_dir)
422
-
423
- # 工作多个轮次
424
- for round_num in range(3): # 每个智能体循环工作3轮
425
- success = agent.work_on_context()
426
- if success:
427
- time.sleep(random.uniform(0.1, 0.5)) # 随机延迟模拟工作时间
428
- else:
429
- # 没有任务可处理,延迟后再次尝试
430
- time.sleep(0.2)
431
-
432
- # 启动多个智能体线程
433
- threads = []
434
- for agent_name in agents:
435
- thread = threading.Thread(target=agent_worker, args=(agent_name,))
436
- thread.daemon = True
437
- threads.append(thread)
438
- thread.start()
439
- print(f"🏃‍♂️ 启动智能体 {agent_name}")
440
-
441
- # 等待所有线程完成
442
- for thread in threads:
443
- thread.join(timeout=10) # 10秒超时
444
-
445
- print("\n📋 最终项目状态:")
446
- final_spec = context.handler.atomic_read()
447
- for task_id, task in final_spec["tasks"].items():
448
- print(f" {task_id}: {task['status']} (assigned to: {task.get('assigned_to', 'none')})")
449
-
450
- print(f" 协作历史记录: {len(final_spec['collaboration_history'])} 条")
451
-
452
- # 清理演示目录
453
- import shutil
454
- shutil.rmtree(project_dir)
455
-
456
-
457
- if __name__ == "__main__":
458
- print("🎯 演示原子性协作机制防止任务重复认领")
459
- print("="*60)
460
- demo_concurrent_agents()
461
- print("\n✅ 演示完成 - 并发认领已成功防範")