@hupan56/wlkj 3.3.1 → 3.3.2

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.
@@ -1,158 +1,158 @@
1
- #!/usr/bin/env python
2
- """wlkj 项目切换脚本:选项目 → 拉平台 token → 写 mcp_config.json。
3
-
4
- 用法:
5
- python switch_project.py # 交互式:列出项目 → 选 → 写配置
6
- python switch_project.py --email a@b.c --pw xxx # 非交互:直接指定
7
- python switch_project.py --project-uuid <UUID> # 非交互:直接指定项目
8
-
9
- 需工作台后端在跑(默认 http://10.89.7.120 云)。
10
- """
11
- import json
12
- import os
13
- import sys
14
- import urllib.request
15
- import urllib.error
16
-
17
- # 宿主根:脚本部署在 {host}/scripts/domain/kg/,4 级 dirname = {host}(.qoder)
18
- HOST_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
19
- REPO_ROOT = os.path.dirname(HOST_DIR) # qoderAll/
20
-
21
-
22
- def _find_config_path():
23
- """按宿主探测 mcp_config.json:当前宿主根 → .qoder。"""
24
- for p in (
25
- os.path.join(HOST_DIR, "mcp_config.json"), # 当前宿主根
26
- os.path.join(REPO_ROOT, ".qoder", "mcp_config.json"),
27
- ):
28
- if os.path.isfile(p):
29
- return p
30
- return os.path.join(HOST_DIR, "mcp_config.json") # 都没有则写当前宿主根
31
-
32
-
33
- CONFIG_PATH = _find_config_path()
34
-
35
- # 平台地址(默认 10010,可 env 覆盖)
36
- BASE_URL = os.environ.get("WLKJ_BASE_URL", "http://10.89.7.120")
37
-
38
-
39
- def bind(email, password, base_url=BASE_URL):
40
- """调平台 /api/auth/bind,返回 {projects:[{id,name,token,mcp_config}], base_url}。"""
41
- data = json.dumps({"email": email, "password": password, "base_url": base_url}).encode()
42
- req = urllib.request.Request(
43
- f"{base_url}/api/auth/bind",
44
- data=data, method="POST",
45
- headers={"Content-Type": "application/json"},
46
- )
47
- try:
48
- resp = urllib.request.urlopen(req, timeout=10)
49
- return json.loads(resp.read())
50
- except urllib.error.HTTPError as e:
51
- body = e.read().decode("utf-8", errors="replace")[:200]
52
- print(f"ERROR: 平台返回 {e.code}: {body}", file=sys.stderr)
53
- sys.exit(1)
54
- except urllib.error.URLError as e:
55
- print(f"ERROR: 连不上平台 {base_url}: {e}", file=sys.stderr)
56
- print(f"提示: 确保工作台在跑(start_pg.bat),或设 WLKJ_BASE_URL 环境变量", file=sys.stderr)
57
- sys.exit(1)
58
-
59
-
60
- def write_config(project, base_url):
61
- """把选中项目的 mcp_config 写入 mcp_config.json(保留 return_endpoint)。"""
62
- # 读现有配置(保留注释和非 mcpServers 字段)
63
- existing = {}
64
- if os.path.isfile(CONFIG_PATH):
65
- try:
66
- with open(CONFIG_PATH, encoding="utf-8") as f:
67
- existing = json.load(f)
68
- except Exception:
69
- pass
70
-
71
- # 用平台的 mcp_config 覆盖
72
- mcp_cfg = project.get("mcp_config", {})
73
- if not mcp_cfg:
74
- # 平台没返回完整 config,手动拼
75
- mcp_cfg = {
76
- "mcpServers": {"wlinkj-knowledge": {
77
- "kind": "http",
78
- "url": f"{base_url}/mcp",
79
- "token": project.get("token", ""),
80
- "env": {"WLKJ_PROJECT_ID": project.get("id", "")},
81
- }},
82
- "return_endpoint": {
83
- "url": f"{base_url}/api/projects/{project.get('id','')}/returns",
84
- "method": "POST",
85
- "headers": {"X-Engine-Token": project.get("token", "")},
86
- },
87
- }
88
-
89
- existing.update(mcp_cfg)
90
- # 确保 return_endpoint 的端口正确
91
- if "return_endpoint" in existing:
92
- existing["return_endpoint"]["url"] = f"{base_url}/api/projects/{project['id']}/returns"
93
-
94
- os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
95
- with open(CONFIG_PATH, "w", encoding="utf-8") as f:
96
- json.dump(existing, f, ensure_ascii=False, indent=2)
97
-
98
- print(f"OK: 已绑定项目「{project.get('name', project.get('id',''))}」")
99
- print(f" token: {project.get('token','')[:12]}...")
100
- print(f" project_id: {project.get('id','')}")
101
- print(f" 配置写入: {CONFIG_PATH}")
102
- print(f" 平台地址: {base_url}")
103
-
104
-
105
- def main():
106
- import argparse
107
- parser = argparse.ArgumentParser(description="切换 wlkj 项目绑定")
108
- parser.add_argument("--email", help="平台邮箱")
109
- parser.add_argument("--pw", "--password", dest="password", help="平台密码")
110
- parser.add_argument("--project-uuid", help="直接指定项目 UUID(跳过选择)")
111
- parser.add_argument("--base-url", default=BASE_URL, help=f"平台地址(默认 {BASE_URL})")
112
- parser.add_argument("--list", action="store_true", help="只列出项目,不写配置")
113
- args = parser.parse_args()
114
-
115
- # 1. 收集邮箱密码
116
- email = args.email or os.environ.get("WLKJ_EMAIL") or input("平台邮箱: ").strip()
117
- password = args.password or os.environ.get("WLKJ_PASSWORD") or input("平台密码: ").strip()
118
-
119
- # 2. 拉项目列表
120
- print(f"连接平台 {args.base_url} ...")
121
- result = bind(email, password, args.base_url)
122
- projects = result.get("projects", [])
123
- if not projects:
124
- print("该用户没有任何项目,请先在平台创建项目。")
125
- sys.exit(1)
126
-
127
- # 3. 列出项目
128
- print(f"\n找到 {len(projects)} 个项目:")
129
- for i, p in enumerate(projects):
130
- print(f" {i+1}. {p.get('name','?')} (id={p.get('id','?')[:8]})")
131
-
132
- if args.list:
133
- return
134
-
135
- # 4. 选择项目
136
- chosen = None
137
- if args.project_uuid:
138
- for p in projects:
139
- if p.get("id") == args.project_uuid:
140
- chosen = p
141
- break
142
- if not chosen:
143
- print(f"ERROR: 项目 UUID '{args.project_uuid}' 不在列表中", file=sys.stderr)
144
- sys.exit(1)
145
- else:
146
- try:
147
- idx = int(input(f"\n选哪个项目?(1-{len(projects)}): ")) - 1
148
- chosen = projects[idx]
149
- except (ValueError, IndexError):
150
- print("ERROR: 无效选择", file=sys.stderr)
151
- sys.exit(1)
152
-
153
- # 5. 写配置
154
- write_config(chosen, args.base_url)
155
-
156
-
157
- if __name__ == "__main__":
158
- main()
1
+ #!/usr/bin/env python
2
+ """wlkj 项目切换脚本:选项目 → 拉平台 token → 写 mcp_config.json。
3
+
4
+ 用法:
5
+ python switch_project.py # 交互式:列出项目 → 选 → 写配置
6
+ python switch_project.py --email a@b.c --pw xxx # 非交互:直接指定
7
+ python switch_project.py --project-uuid <UUID> # 非交互:直接指定项目
8
+
9
+ 需工作台后端在跑(默认 http://127.0.0.1:10010)。
10
+ """
11
+ import json
12
+ import os
13
+ import sys
14
+ import urllib.request
15
+ import urllib.error
16
+
17
+ # 宿主根:脚本部署在 {host}/scripts/domain/kg/,4 级 dirname = {host}(.qoder)
18
+ HOST_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
19
+ REPO_ROOT = os.path.dirname(HOST_DIR) # qoderAll/
20
+
21
+
22
+ def _find_config_path():
23
+ """按宿主探测 mcp_config.json:当前宿主根 → .qoder。"""
24
+ for p in (
25
+ os.path.join(HOST_DIR, "mcp_config.json"), # 当前宿主根
26
+ os.path.join(REPO_ROOT, ".qoder", "mcp_config.json"),
27
+ ):
28
+ if os.path.isfile(p):
29
+ return p
30
+ return os.path.join(HOST_DIR, "mcp_config.json") # 都没有则写当前宿主根
31
+
32
+
33
+ CONFIG_PATH = _find_config_path()
34
+
35
+ # 平台地址(默认 10010,可 env 覆盖)
36
+ BASE_URL = os.environ.get("WLKJ_BASE_URL", "http://127.0.0.1:10010")
37
+
38
+
39
+ def bind(email, password, base_url=BASE_URL):
40
+ """调平台 /api/auth/bind,返回 {projects:[{id,name,token,mcp_config}], base_url}。"""
41
+ data = json.dumps({"email": email, "password": password, "base_url": base_url}).encode()
42
+ req = urllib.request.Request(
43
+ f"{base_url}/api/auth/bind",
44
+ data=data, method="POST",
45
+ headers={"Content-Type": "application/json"},
46
+ )
47
+ try:
48
+ resp = urllib.request.urlopen(req, timeout=10)
49
+ return json.loads(resp.read())
50
+ except urllib.error.HTTPError as e:
51
+ body = e.read().decode("utf-8", errors="replace")[:200]
52
+ print(f"ERROR: 平台返回 {e.code}: {body}", file=sys.stderr)
53
+ sys.exit(1)
54
+ except urllib.error.URLError as e:
55
+ print(f"ERROR: 连不上平台 {base_url}: {e}", file=sys.stderr)
56
+ print(f"提示: 确保工作台在跑(start_pg.bat),或设 WLKJ_BASE_URL 环境变量", file=sys.stderr)
57
+ sys.exit(1)
58
+
59
+
60
+ def write_config(project, base_url):
61
+ """把选中项目的 mcp_config 写入 mcp_config.json(保留 return_endpoint)。"""
62
+ # 读现有配置(保留注释和非 mcpServers 字段)
63
+ existing = {}
64
+ if os.path.isfile(CONFIG_PATH):
65
+ try:
66
+ with open(CONFIG_PATH, encoding="utf-8") as f:
67
+ existing = json.load(f)
68
+ except Exception:
69
+ pass
70
+
71
+ # 用平台的 mcp_config 覆盖
72
+ mcp_cfg = project.get("mcp_config", {})
73
+ if not mcp_cfg:
74
+ # 平台没返回完整 config,手动拼
75
+ mcp_cfg = {
76
+ "mcpServers": {"wlinkj-knowledge": {
77
+ "kind": "http",
78
+ "url": f"{base_url}/mcp",
79
+ "token": project.get("token", ""),
80
+ "env": {"WLKJ_PROJECT_ID": project.get("id", "")},
81
+ }},
82
+ "return_endpoint": {
83
+ "url": f"{base_url}/api/projects/{project.get('id','')}/returns",
84
+ "method": "POST",
85
+ "headers": {"X-Engine-Token": project.get("token", "")},
86
+ },
87
+ }
88
+
89
+ existing.update(mcp_cfg)
90
+ # 确保 return_endpoint 的端口正确
91
+ if "return_endpoint" in existing:
92
+ existing["return_endpoint"]["url"] = f"{base_url}/api/projects/{project['id']}/returns"
93
+
94
+ os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
95
+ with open(CONFIG_PATH, "w", encoding="utf-8") as f:
96
+ json.dump(existing, f, ensure_ascii=False, indent=2)
97
+
98
+ print(f"OK: 已绑定项目「{project.get('name', project.get('id',''))}」")
99
+ print(f" token: {project.get('token','')[:12]}...")
100
+ print(f" project_id: {project.get('id','')}")
101
+ print(f" 配置写入: {CONFIG_PATH}")
102
+ print(f" 平台地址: {base_url}")
103
+
104
+
105
+ def main():
106
+ import argparse
107
+ parser = argparse.ArgumentParser(description="切换 wlkj 项目绑定")
108
+ parser.add_argument("--email", help="平台邮箱")
109
+ parser.add_argument("--pw", "--password", dest="password", help="平台密码")
110
+ parser.add_argument("--project-uuid", help="直接指定项目 UUID(跳过选择)")
111
+ parser.add_argument("--base-url", default=BASE_URL, help=f"平台地址(默认 {BASE_URL})")
112
+ parser.add_argument("--list", action="store_true", help="只列出项目,不写配置")
113
+ args = parser.parse_args()
114
+
115
+ # 1. 收集邮箱密码
116
+ email = args.email or os.environ.get("WLKJ_EMAIL") or input("平台邮箱: ").strip()
117
+ password = args.password or os.environ.get("WLKJ_PASSWORD") or input("平台密码: ").strip()
118
+
119
+ # 2. 拉项目列表
120
+ print(f"连接平台 {args.base_url} ...")
121
+ result = bind(email, password, args.base_url)
122
+ projects = result.get("projects", [])
123
+ if not projects:
124
+ print("该用户没有任何项目,请先在平台创建项目。")
125
+ sys.exit(1)
126
+
127
+ # 3. 列出项目
128
+ print(f"\n找到 {len(projects)} 个项目:")
129
+ for i, p in enumerate(projects):
130
+ print(f" {i+1}. {p.get('name','?')} (id={p.get('id','?')[:8]})")
131
+
132
+ if args.list:
133
+ return
134
+
135
+ # 4. 选择项目
136
+ chosen = None
137
+ if args.project_uuid:
138
+ for p in projects:
139
+ if p.get("id") == args.project_uuid:
140
+ chosen = p
141
+ break
142
+ if not chosen:
143
+ print(f"ERROR: 项目 UUID '{args.project_uuid}' 不在列表中", file=sys.stderr)
144
+ sys.exit(1)
145
+ else:
146
+ try:
147
+ idx = int(input(f"\n选哪个项目?(1-{len(projects)}): ")) - 1
148
+ chosen = projects[idx]
149
+ except (ValueError, IndexError):
150
+ print("ERROR: 无效选择", file=sys.stderr)
151
+ sys.exit(1)
152
+
153
+ # 5. 写配置
154
+ write_config(chosen, args.base_url)
155
+
156
+
157
+ if __name__ == "__main__":
158
+ main()