@agentunion/kite 1.3.1 → 1.4.0

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 (78) hide show
  1. package/CHANGELOG.md +287 -1
  2. package/cli.js +76 -0
  3. package/extensions/agents/assistant/entry.py +111 -1
  4. package/extensions/agents/assistant/server.py +263 -197
  5. package/extensions/channels/acp_channel/entry.py +111 -1
  6. package/extensions/channels/acp_channel/module.md +23 -22
  7. package/extensions/channels/acp_channel/server.py +263 -197
  8. package/extensions/event_hub_bench/entry.py +107 -1
  9. package/extensions/services/backup/entry.py +408 -72
  10. package/extensions/services/backup/module.md +24 -22
  11. package/extensions/services/model_service/entry.py +255 -71
  12. package/extensions/services/model_service/module.md +21 -22
  13. package/extensions/services/watchdog/entry.py +344 -90
  14. package/extensions/services/watchdog/monitor.py +237 -21
  15. package/extensions/services/web/WEBSOCKET_STATUS.md +143 -0
  16. package/extensions/services/web/config_example.py +35 -0
  17. package/extensions/services/web/config_loader.py +110 -0
  18. package/extensions/services/web/entry.py +114 -26
  19. package/extensions/services/web/module.md +35 -24
  20. package/extensions/services/web/pairing.py +250 -0
  21. package/extensions/services/web/pairing_codes.jsonl +16 -0
  22. package/extensions/services/web/relay.py +643 -0
  23. package/extensions/services/web/relay_config.json5 +67 -0
  24. package/extensions/services/web/routes/routes_management_ws.py +127 -0
  25. package/extensions/services/web/routes/routes_rpc.py +89 -0
  26. package/extensions/services/web/routes/routes_test.py +61 -0
  27. package/extensions/services/web/server.py +445 -99
  28. package/extensions/services/web/static/css/style.css +138 -2
  29. package/extensions/services/web/static/index.html +295 -2
  30. package/extensions/services/web/static/js/app.js +1579 -5
  31. package/extensions/services/web/static/js/kernel-client-example.js +161 -0
  32. package/extensions/services/web/static/js/kernel-client.js +383 -0
  33. package/extensions/services/web/static/js/registry-tests.js +558 -0
  34. package/extensions/services/web/static/js/token-manager.js +175 -0
  35. package/extensions/services/web/static/pairing.html +248 -0
  36. package/extensions/services/web/static/test_registry.html +262 -0
  37. package/extensions/services/web/web_config.json5 +29 -0
  38. package/kernel/entry.py +120 -32
  39. package/kernel/event_hub.py +159 -16
  40. package/kernel/module.md +36 -33
  41. package/kernel/registry_store.py +70 -20
  42. package/kernel/rpc_router.py +134 -57
  43. package/kernel/server.py +292 -15
  44. package/kite_cli/__init__.py +3 -0
  45. package/kite_cli/__main__.py +5 -0
  46. package/kite_cli/commands/__init__.py +1 -0
  47. package/kite_cli/commands/clean.py +101 -0
  48. package/kite_cli/commands/doctor.py +35 -0
  49. package/kite_cli/commands/history.py +111 -0
  50. package/kite_cli/commands/info.py +96 -0
  51. package/kite_cli/commands/install.py +313 -0
  52. package/kite_cli/commands/list.py +143 -0
  53. package/kite_cli/commands/log.py +81 -0
  54. package/kite_cli/commands/rollback.py +88 -0
  55. package/kite_cli/commands/search.py +73 -0
  56. package/kite_cli/commands/uninstall.py +85 -0
  57. package/kite_cli/commands/update.py +118 -0
  58. package/kite_cli/core/__init__.py +1 -0
  59. package/kite_cli/core/checker.py +142 -0
  60. package/kite_cli/core/dependency.py +229 -0
  61. package/kite_cli/core/downloader.py +209 -0
  62. package/kite_cli/core/install_info.py +40 -0
  63. package/kite_cli/core/tool_installer.py +397 -0
  64. package/kite_cli/core/validator.py +78 -0
  65. package/kite_cli/main.py +289 -0
  66. package/kite_cli/utils/__init__.py +1 -0
  67. package/kite_cli/utils/i18n.py +252 -0
  68. package/kite_cli/utils/interactive.py +63 -0
  69. package/kite_cli/utils/operation_log.py +77 -0
  70. package/kite_cli/utils/paths.py +34 -0
  71. package/kite_cli/utils/version.py +308 -0
  72. package/launcher/count_lines.py +34 -0
  73. package/launcher/entry.py +905 -166
  74. package/launcher/logging_setup.py +104 -0
  75. package/launcher/module.md +37 -37
  76. package/launcher/process_manager.py +12 -1
  77. package/package.json +2 -1
  78. package/scripts/plan_manager.py +315 -0
@@ -0,0 +1,88 @@
1
+ """rollback 命令实现 - 回滚最后一次操作"""
2
+ import shutil
3
+ from pathlib import Path
4
+ from kite_cli.utils.operation_log import get_last_operation, log_operation
5
+ from kite_cli.utils.interactive import confirm_action
6
+ from kite_cli.utils.paths import get_install_path
7
+ from kite_cli.utils.i18n import t
8
+
9
+
10
+ def run_rollback(args):
11
+ """执行回滚命令"""
12
+ skip_confirm = args.yes if hasattr(args, 'yes') else False
13
+
14
+ # 获取最后一次成功的操作
15
+ last_op = get_last_operation()
16
+
17
+ if not last_op:
18
+ print("[Error] 没有可回滚的操作")
19
+ return 1
20
+
21
+ if not last_op.get("success"):
22
+ print("[Error] 最后一次操作失败,无法回滚")
23
+ return 1
24
+
25
+ operation = last_op.get("operation")
26
+ details = last_op.get("details", {})
27
+
28
+ if operation == "install":
29
+ return rollback_install(details, skip_confirm)
30
+ elif operation == "uninstall":
31
+ print("[Error] 卸载操作无法自动回滚")
32
+ print("[Info] 请手动重新安装模块")
33
+ return 1
34
+ elif operation == "update":
35
+ print("[Error] 更新操作无法自动回滚")
36
+ print("[Info] 请手动安装旧版本")
37
+ return 1
38
+ else:
39
+ print(f"[Error] 不支持回滚操作类型: {operation}")
40
+ return 1
41
+
42
+
43
+ def rollback_install(details: dict, skip_confirm: bool) -> int:
44
+ """回滚安装操作"""
45
+ module = details.get("module", "unknown")
46
+ location = details.get("location", "")
47
+ path = details.get("path", "")
48
+
49
+ if not path:
50
+ print("[Error] 无法确定模块路径")
51
+ return 1
52
+
53
+ module_path = Path(path)
54
+
55
+ if not module_path.exists():
56
+ print(f"[Warning] 模块已不存在: {module_path}")
57
+ return 0
58
+
59
+ # 确认回滚
60
+ if not skip_confirm:
61
+ if not confirm_action(f"确认回滚安装 {module} (删除 {location})?"):
62
+ print("[Cancelled] 已取消")
63
+ return 1
64
+
65
+ # 删除模块
66
+ try:
67
+ shutil.rmtree(module_path)
68
+ print(f"[Done] 已回滚安装: {module} from {location}")
69
+
70
+ # 记录回滚操作
71
+ log_operation("rollback", {
72
+ "original_operation": "install",
73
+ "module": module,
74
+ "location": location,
75
+ "path": str(module_path)
76
+ }, success=True)
77
+
78
+ return 0
79
+
80
+ except Exception as e:
81
+ print(f"[Error] 回滚失败: {e}")
82
+
83
+ log_operation("rollback", {
84
+ "original_operation": "install",
85
+ "module": module
86
+ }, success=False, error=str(e))
87
+
88
+ return 1
@@ -0,0 +1,73 @@
1
+ """search 命令实现"""
2
+ from kite_cli.core.checker import PlatformChecker
3
+ from kite_cli.utils.i18n import t
4
+
5
+
6
+ def run_search(args):
7
+ """执行搜索命令"""
8
+ keyword = args.keyword
9
+ from_platform = args.from_platform
10
+
11
+ print(t('searching_for', keyword=keyword) + "\n")
12
+
13
+ if from_platform:
14
+ # 指定平台搜索
15
+ results = search_single_platform(keyword, from_platform)
16
+ else:
17
+ # 搜索所有平台
18
+ results = PlatformChecker.check_all(keyword)
19
+
20
+ # 显示结果
21
+ found_count = 0
22
+
23
+ # PyPI
24
+ if results.get("pypi"):
25
+ found_count += 1
26
+ pypi = results["pypi"]
27
+ print(f"【{t('search_pypi')}】")
28
+ print(f" • {pypi['name']}")
29
+ print(f" {t('search_latest_version')}: {pypi['latest']}")
30
+ if len(pypi['versions']) > 1:
31
+ print(f" {t('search_available_versions')}: {', '.join(pypi['versions'][:5])}")
32
+ print()
33
+
34
+ # npm
35
+ if results.get("npm"):
36
+ found_count += 1
37
+ npm = results["npm"]
38
+ print(f"【{t('search_npm')}】")
39
+ print(f" • {npm['name']}")
40
+ print(f" {t('search_version')}: {npm['latest']}")
41
+ print()
42
+
43
+ # Git
44
+ if results.get("git"):
45
+ found_count += len(results["git"])
46
+ print(f"【{t('search_git')}】")
47
+ for repo in results["git"]:
48
+ print(f" • {repo['full_name']}")
49
+ if repo.get("description"):
50
+ print(f" {repo['description']}")
51
+ print(f" {repo['url']}")
52
+ print()
53
+
54
+ if found_count == 0:
55
+ print(t('no_results'))
56
+ return 1
57
+ else:
58
+ print(t('found_results', count=found_count))
59
+ return 0
60
+
61
+
62
+ def search_single_platform(keyword: str, platform: str):
63
+ """搜索单个平台"""
64
+ results = {"pypi": None, "npm": None, "git": None}
65
+
66
+ if platform == "pypi":
67
+ results["pypi"] = PlatformChecker.check_pypi(keyword)
68
+ elif platform == "npm":
69
+ results["npm"] = PlatformChecker.check_npm(keyword)
70
+ elif platform == "git":
71
+ results["git"] = PlatformChecker.check_git(keyword)
72
+
73
+ return results
@@ -0,0 +1,85 @@
1
+ """uninstall 命令实现"""
2
+ import shutil
3
+ from pathlib import Path
4
+ from kite_cli.utils.paths import get_install_path
5
+ from kite_cli.utils.interactive import confirm_action
6
+ from kite_cli.utils.i18n import t
7
+ from kite_cli.utils.operation_log import log_operation
8
+
9
+
10
+ def run_uninstall(args):
11
+ """执行卸载命令"""
12
+ module_name = args.name
13
+ location = args.location
14
+ uninstall_all = args.all
15
+ skip_confirm = args.yes
16
+
17
+ print(t('uninstalling', name=module_name))
18
+
19
+ # 查找模块
20
+ if uninstall_all:
21
+ # 卸载所有位置
22
+ locations = ["dev", "local", "global"]
23
+ elif location:
24
+ # 指定位置
25
+ locations = [location]
26
+ else:
27
+ # 自动查找
28
+ locations = find_module_locations(module_name)
29
+ if not locations:
30
+ print(t('module_not_found', name=module_name))
31
+ return 1
32
+
33
+ # 确认卸载
34
+ if not skip_confirm:
35
+ location_names = ", ".join(locations)
36
+ if not confirm_action(f"{t('uninstalling', name=module_name)} ({location_names})?"):
37
+ print(t('update_cancelled'))
38
+ return 1
39
+
40
+ # 执行卸载
41
+ success_count = 0
42
+ uninstalled_paths = []
43
+ for loc in locations:
44
+ module_path = get_install_path(loc, module_name)
45
+ if module_path.exists():
46
+ try:
47
+ shutil.rmtree(module_path)
48
+ print(t('uninstalled', location=loc, path=module_path))
49
+ success_count += 1
50
+ uninstalled_paths.append({"location": loc, "path": str(module_path)})
51
+ except Exception as e:
52
+ print(f"[Error] {t('update_failed', error=str(e))} ({loc})")
53
+ else:
54
+ print(f"[Warning] {t('module_not_found', name='')} ({loc}): {module_path}")
55
+
56
+ if success_count > 0:
57
+ # 记录操作日志
58
+ log_operation("uninstall", {
59
+ "module": module_name,
60
+ "locations": uninstalled_paths
61
+ }, success=True)
62
+
63
+ print(t('uninstall_complete', count=success_count))
64
+ print(t('restart_hint'))
65
+ return 0
66
+ else:
67
+ log_operation("uninstall", {
68
+ "module": module_name
69
+ }, success=False, error="No modules found")
70
+
71
+ print(t('uninstall_none'))
72
+ return 1
73
+
74
+
75
+ def find_module_locations(module_name: str):
76
+ """查找模块在哪些位置存在"""
77
+ locations = []
78
+ for loc in ["dev", "local", "global"]:
79
+ try:
80
+ module_path = get_install_path(loc, module_name)
81
+ if module_path.exists():
82
+ locations.append(loc)
83
+ except Exception:
84
+ pass
85
+ return locations
@@ -0,0 +1,118 @@
1
+ """update 命令实现"""
2
+ import sys
3
+ import subprocess
4
+ from pathlib import Path
5
+ from kite_cli.utils.paths import get_install_path
6
+ from kite_cli.core.install_info import read_install_info
7
+ from kite_cli.utils.interactive import confirm_action
8
+ from kite_cli.utils.i18n import t
9
+
10
+
11
+ def run_update(args):
12
+ """执行更新命令"""
13
+ module_name = args.name if hasattr(args, 'name') else None
14
+ location = args.location if hasattr(args, 'location') else None
15
+ to_version = args.to_version if hasattr(args, 'to_version') else None
16
+ update_all = args.all if hasattr(args, 'all') else False
17
+ skip_confirm = args.yes if hasattr(args, 'yes') else False
18
+
19
+ if update_all:
20
+ print(t('update_not_implemented'))
21
+ return 1
22
+
23
+ if not module_name:
24
+ print(t('update_specify_name'))
25
+ return 1
26
+
27
+ # 显示更新信息
28
+ if to_version:
29
+ print(t('updating_module', name=f"{module_name} → {to_version}"))
30
+ else:
31
+ print(t('updating_module', name=module_name))
32
+
33
+ # 查找模块
34
+ if location:
35
+ locations = [location]
36
+ else:
37
+ locations = find_module_locations(module_name)
38
+ if not locations:
39
+ print(t('update_not_found', name=module_name))
40
+ return 1
41
+
42
+ # 只更新第一个找到的位置
43
+ loc = locations[0]
44
+ module_path = get_install_path(loc, module_name)
45
+
46
+ # 读取安装信息
47
+ install_info = read_install_info(module_path)
48
+ if not install_info:
49
+ print(t('update_no_install_info'))
50
+ print(t('update_manual_reinstall', name=module_name, location=loc))
51
+ return 1
52
+
53
+ source = install_info.get("source", {})
54
+ source_type = source.get("type")
55
+
56
+ if not source_type:
57
+ print(t('update_incomplete_info'))
58
+ return 1
59
+
60
+ # 构建安装命令
61
+ if source_type == "pypi":
62
+ source_arg = source.get("package", module_name)
63
+ # 如果指定了版本,添加版本号
64
+ if to_version:
65
+ source_arg = f"{source_arg}@{to_version}"
66
+ from_arg = "-f pypi"
67
+ elif source_type == "npm":
68
+ source_arg = source.get("package", module_name)
69
+ # 如果指定了版本,添加版本号
70
+ if to_version:
71
+ source_arg = f"{source_arg}@{to_version}"
72
+ from_arg = "-f npm"
73
+ elif source_type == "git":
74
+ source_arg = source.get("url", "")
75
+ from_arg = "-f git"
76
+ # Git 源不支持版本号
77
+ if to_version:
78
+ print("[Warning] Git 源不支持 --to 参数,将更新到最新提交")
79
+ elif source_type == "local":
80
+ print(t('update_local_no_auto'))
81
+ return 1
82
+ else:
83
+ print(t('update_unknown_source', type=source_type))
84
+ return 1
85
+
86
+ if not skip_confirm:
87
+ confirm_msg = t('update_confirm', name=module_name, source=source_type)
88
+ if to_version:
89
+ confirm_msg = f"确认更新 {module_name} 到版本 {to_version}?"
90
+ if not confirm_action(confirm_msg):
91
+ print(t('update_cancelled'))
92
+ return 1
93
+
94
+ # 调用 install 命令
95
+ print(t('reinstalling', name=module_name))
96
+ try:
97
+ cmd = [
98
+ sys.executable, "-m", "kite_cli", "install",
99
+ source_arg, "-l", loc, from_arg, "-y"
100
+ ]
101
+ result = subprocess.run(cmd, capture_output=False, text=True)
102
+ return result.returncode
103
+ except Exception as e:
104
+ print(t('update_failed', error=str(e)))
105
+ return 1
106
+
107
+
108
+ def find_module_locations(module_name: str):
109
+ """查找模块在哪些位置存在"""
110
+ locations = []
111
+ for loc in ["dev", "local", "global"]:
112
+ try:
113
+ module_path = get_install_path(loc, module_name)
114
+ if module_path.exists():
115
+ locations.append(loc)
116
+ except Exception:
117
+ pass
118
+ return locations
@@ -0,0 +1 @@
1
+ """核心功能模块"""
@@ -0,0 +1,142 @@
1
+ """平台检查器 - 检查模块在各平台是否存在"""
2
+ import subprocess
3
+ import json
4
+ from typing import Optional, List, Dict
5
+ from concurrent.futures import ThreadPoolExecutor, as_completed
6
+
7
+
8
+ class PlatformChecker:
9
+ """检查模块在各平台的存在性"""
10
+
11
+ @staticmethod
12
+ def check_pypi(name: str) -> Optional[Dict]:
13
+ """检查 PyPI 是否存在该包"""
14
+ try:
15
+ # 使用 pip index versions
16
+ result = subprocess.run(
17
+ ["pip", "index", "versions", name],
18
+ capture_output=True,
19
+ text=True,
20
+ timeout=10
21
+ )
22
+ if result.returncode == 0 and "Available versions:" in result.stdout:
23
+ # 解析版本
24
+ lines = result.stdout.split("\n")
25
+ for line in lines:
26
+ if "Available versions:" in line:
27
+ versions_str = line.split(":", 1)[1].strip()
28
+ versions = [v.strip() for v in versions_str.split(",")]
29
+ return {
30
+ "platform": "pypi",
31
+ "name": name,
32
+ "versions": versions,
33
+ "latest": versions[0] if versions else None
34
+ }
35
+ except (subprocess.TimeoutExpired, FileNotFoundError):
36
+ pass
37
+ return None
38
+
39
+ @staticmethod
40
+ def check_npm(name: str) -> Optional[Dict]:
41
+ """检查 npm 是否存在该包"""
42
+ try:
43
+ # 获取所有版本
44
+ result = subprocess.run(
45
+ ["npm", "view", name, "versions", "--json"],
46
+ capture_output=True,
47
+ text=True,
48
+ timeout=10,
49
+ shell=True # Windows 兼容性
50
+ )
51
+ if result.returncode == 0:
52
+ try:
53
+ versions_data = json.loads(result.stdout)
54
+ # versions 可能是字符串(单版本)或列表(多版本)
55
+ if isinstance(versions_data, str):
56
+ versions = [versions_data]
57
+ elif isinstance(versions_data, list):
58
+ versions = versions_data
59
+ else:
60
+ versions = []
61
+
62
+ if versions:
63
+ return {
64
+ "platform": "npm",
65
+ "name": name,
66
+ "versions": versions,
67
+ "latest": versions[-1] if versions else None # npm 返回的版本是升序
68
+ }
69
+ except json.JSONDecodeError:
70
+ # 降级到只获取最新版本
71
+ result = subprocess.run(
72
+ ["npm", "view", name, "version"],
73
+ capture_output=True,
74
+ text=True,
75
+ timeout=10,
76
+ shell=True
77
+ )
78
+ if result.returncode == 0:
79
+ version = result.stdout.strip()
80
+ return {
81
+ "platform": "npm",
82
+ "name": name,
83
+ "versions": [version],
84
+ "latest": version
85
+ }
86
+ except (subprocess.TimeoutExpired, FileNotFoundError):
87
+ pass
88
+ return None
89
+
90
+ @staticmethod
91
+ def check_git(name: str) -> Optional[List[Dict]]:
92
+ """检查 GitHub 是否存在相关仓库"""
93
+ try:
94
+ # 搜索 GitHub 仓库
95
+ result = subprocess.run(
96
+ ["curl", "-s", f"https://api.github.com/search/repositories?q={name}+kite"],
97
+ capture_output=True,
98
+ text=True,
99
+ timeout=10
100
+ )
101
+ if result.returncode == 0:
102
+ data = json.loads(result.stdout)
103
+ if data.get("total_count", 0) > 0:
104
+ repos = []
105
+ for item in data.get("items", [])[:5]: # 最多返回 5 个
106
+ repos.append({
107
+ "platform": "git",
108
+ "name": item["name"],
109
+ "full_name": item["full_name"],
110
+ "url": item["clone_url"],
111
+ "description": item.get("description", "")
112
+ })
113
+ return repos
114
+ except (subprocess.TimeoutExpired, FileNotFoundError, json.JSONDecodeError):
115
+ pass
116
+ return None
117
+
118
+ @classmethod
119
+ def check_all(cls, name: str) -> Dict[str, any]:
120
+ """并行检查所有平台"""
121
+ results = {
122
+ "pypi": None,
123
+ "npm": None,
124
+ "git": None
125
+ }
126
+
127
+ with ThreadPoolExecutor(max_workers=3) as executor:
128
+ futures = {
129
+ executor.submit(cls.check_pypi, name): "pypi",
130
+ executor.submit(cls.check_npm, name): "npm",
131
+ executor.submit(cls.check_git, name): "git"
132
+ }
133
+
134
+ for future in as_completed(futures):
135
+ platform = futures[future]
136
+ try:
137
+ result = future.result()
138
+ results[platform] = result
139
+ except Exception:
140
+ pass
141
+
142
+ return results