multi-lang-build 0.2.0__py3-none-any.whl
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.
- multi_lang_build/__init__.py +57 -0
- multi_lang_build/cli.py +256 -0
- multi_lang_build/compiler/__init__.py +22 -0
- multi_lang_build/compiler/base.py +196 -0
- multi_lang_build/compiler/go.py +452 -0
- multi_lang_build/compiler/pnpm.py +431 -0
- multi_lang_build/compiler/python.py +530 -0
- multi_lang_build/mirror/__init__.py +21 -0
- multi_lang_build/mirror/config.py +251 -0
- multi_lang_build/py.typed +2 -0
- multi_lang_build/register.py +383 -0
- multi_lang_build/types.py +43 -0
- multi_lang_build-0.2.0.dist-info/METADATA +383 -0
- multi_lang_build-0.2.0.dist-info/RECORD +17 -0
- multi_lang_build-0.2.0.dist-info/WHEEL +4 -0
- multi_lang_build-0.2.0.dist-info/entry_points.txt +6 -0
- multi_lang_build-0.2.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"""Mirror configuration for domestic acceleration."""
|
|
2
|
+
|
|
3
|
+
from typing import TypedDict, Literal
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# ============================================================================
|
|
8
|
+
# Constants for mainstream domestic mirrors
|
|
9
|
+
# ============================================================================
|
|
10
|
+
|
|
11
|
+
# NPM/PNPM mirrors
|
|
12
|
+
NPM_REGISTRY_NPMMIRROR: Literal["https://registry.npmmirror.com"] = "https://registry.npmmirror.com"
|
|
13
|
+
NPM_REGISTRY_TAOBAO: Literal["https://registry.npmmirror.com"] = "https://registry.npmmirror.com" # Taobao mirrors npmmirror
|
|
14
|
+
|
|
15
|
+
# Go mirrors (including Qiniu cloud)
|
|
16
|
+
GO_PROXY_GOPROXY_CN: Literal["https://goproxy.cn"] = "https://goproxy.cn"
|
|
17
|
+
GO_PROXY_GOPROXY_IO: Literal["https://goproxy.io"] = "https://goproxy.io"
|
|
18
|
+
GO_PROXY_GOVIP_CN: Literal["https://goproxy.vip.cn"] = "https://goproxy.vip.cn"
|
|
19
|
+
GO_PROXY_FASTGOPROXY: Literal["https://goproxy.cn,direct"] = "https://goproxy.cn,direct"
|
|
20
|
+
|
|
21
|
+
# Go sumdb mirrors
|
|
22
|
+
GO_SUMDB_GOLANG: Literal["sum.golang.org"] = "sum.golang.org"
|
|
23
|
+
GO_SUMDB_GOLANG_GOOGLE_CN: Literal["sum.golang.google.cn"] = "sum.golang.google.cn"
|
|
24
|
+
|
|
25
|
+
# PyPI/Pip mirrors
|
|
26
|
+
PYPI_MIRROR_TSINGHUA: Literal["https://pypi.tuna.tsinghua.edu.cn"] = "https://pypi.tuna.tsinghua.edu.cn"
|
|
27
|
+
PYPI_MIRROR_ALIYUN: Literal["https://mirrors.aliyun.com/pypi/simple"] = "https://mirrors.aliyun.com/pypi/simple"
|
|
28
|
+
PYPI_MIRROR_DOUBAN: Literal["https://pypi.doubanio.com/simple"] = "https://pypi.doubanio.com/simple"
|
|
29
|
+
PYPI_MIRROR_HUAWEI: Literal["https://repo.huaweicloud.com/repository/pypi/simple"] = "https://repo.huaweicloud.com/repository/pypi/simple"
|
|
30
|
+
PYPI_MIRROR_NETEASE: Literal["https://mirrors.163.com/pypi/simple"] = "https://mirrors.163.com/pypi/simple"
|
|
31
|
+
PYPI_MIRROR_SAU: Literal["https://pypi.sau.edu.cn/simple"] = "https://pypi.sau.edu.cn/simple"
|
|
32
|
+
|
|
33
|
+
# Poetry mirrors (uses same PyPI mirrors)
|
|
34
|
+
POETRY_REPO_TSINGHUA: Literal["https://pypi.tuna.tsinghua.edu.cn/simple"] = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
|
35
|
+
POETRY_REPO_ALIYUN: Literal["https://mirrors.aliyun.com/pypi/simple"] = "https://mirrors.aliyun.com/pypi/simple"
|
|
36
|
+
|
|
37
|
+
# Default mirror selection
|
|
38
|
+
DEFAULT_GO_MIRROR: str = GO_PROXY_GOPROXY_CN
|
|
39
|
+
DEFAULT_PIP_MIRROR: str = PYPI_MIRROR_TSINGHUA
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class MirrorConfig(TypedDict):
|
|
43
|
+
"""Mirror configuration for package managers."""
|
|
44
|
+
name: str
|
|
45
|
+
url: str
|
|
46
|
+
environment_prefix: str
|
|
47
|
+
environment_variables: dict[str, str]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Predefined mirror configurations for different package managers
|
|
51
|
+
MIRROR_CONFIGS: dict[str, MirrorConfig] = {
|
|
52
|
+
"npm": {
|
|
53
|
+
"name": "NPM China Mirror (npmmirror)",
|
|
54
|
+
"url": NPM_REGISTRY_NPMMIRROR,
|
|
55
|
+
"environment_prefix": "NPM",
|
|
56
|
+
"environment_variables": {
|
|
57
|
+
"NPM_CONFIG_REGISTRY": NPM_REGISTRY_NPMMIRROR,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
"pnpm": {
|
|
61
|
+
"name": "PNPM China Mirror (npmmirror)",
|
|
62
|
+
"url": NPM_REGISTRY_NPMMIRROR,
|
|
63
|
+
"environment_prefix": "PNPM",
|
|
64
|
+
"environment_variables": {
|
|
65
|
+
"PNPM_CONFIG_REGISTRY": NPM_REGISTRY_NPMMIRROR,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
"yarn": {
|
|
69
|
+
"name": "Yarn China Mirror (npmmirror)",
|
|
70
|
+
"url": NPM_REGISTRY_NPMMIRROR,
|
|
71
|
+
"environment_prefix": "YARN",
|
|
72
|
+
"environment_variables": {
|
|
73
|
+
"YARN_NPM_MIRROR": NPM_REGISTRY_NPMMIRROR,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
"go": {
|
|
77
|
+
"name": "Go China Mirror (goproxy.cn)",
|
|
78
|
+
"url": GO_PROXY_GOPROXY_CN,
|
|
79
|
+
"environment_prefix": "GOPROXY",
|
|
80
|
+
"environment_variables": {
|
|
81
|
+
"GOPROXY": f"{GO_PROXY_GOPROXY_CN},direct",
|
|
82
|
+
"GOSUMDB": GO_SUMDB_GOLANG_GOOGLE_CN,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
"go_qiniu": {
|
|
86
|
+
"name": "Go China Mirror (goproxy.io)",
|
|
87
|
+
"url": GO_PROXY_GOPROXY_IO,
|
|
88
|
+
"environment_prefix": "GOPROXY",
|
|
89
|
+
"environment_variables": {
|
|
90
|
+
"GOPROXY": f"{GO_PROXY_GOPROXY_IO},direct",
|
|
91
|
+
"GOSUMDB": GO_SUMDB_GOLANG_GOOGLE_CN,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
"go_vip": {
|
|
95
|
+
"name": "Go China Mirror (goproxy.vip.cn)",
|
|
96
|
+
"url": GO_PROXY_GOVIP_CN,
|
|
97
|
+
"environment_prefix": "GOPROXY",
|
|
98
|
+
"environment_variables": {
|
|
99
|
+
"GOPROXY": f"{GO_PROXY_GOVIP_CN},direct",
|
|
100
|
+
"GOSUMDB": GO_SUMDB_GOLANG_GOOGLE_CN,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
"pip": {
|
|
104
|
+
"name": "Pip China Mirror (Tsinghua)",
|
|
105
|
+
"url": PYPI_MIRROR_TSINGHUA,
|
|
106
|
+
"environment_prefix": "PIP",
|
|
107
|
+
"environment_variables": {
|
|
108
|
+
"PIP_INDEX_URL": f"{PYPI_MIRROR_TSINGHUA}/simple",
|
|
109
|
+
"PIP_TRUSTED_HOST": "pypi.tuna.tsinghua.edu.cn",
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
"pip_aliyun": {
|
|
113
|
+
"name": "Pip China Mirror (Aliyun)",
|
|
114
|
+
"url": PYPI_MIRROR_ALIYUN,
|
|
115
|
+
"environment_prefix": "PIP",
|
|
116
|
+
"environment_variables": {
|
|
117
|
+
"PIP_INDEX_URL": f"{PYPI_MIRROR_ALIYUN}/simple",
|
|
118
|
+
"PIP_TRUSTED_HOST": "mirrors.aliyun.com",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
"pip_douban": {
|
|
122
|
+
"name": "Pip China Mirror (Douban)",
|
|
123
|
+
"url": PYPI_MIRROR_DOUBAN,
|
|
124
|
+
"environment_prefix": "PIP",
|
|
125
|
+
"environment_variables": {
|
|
126
|
+
"PIP_INDEX_URL": f"{PYPI_MIRROR_DOUBAN}/simple",
|
|
127
|
+
"PIP_TRUSTED_HOST": "pypi.doubanio.com",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
"pip_huawei": {
|
|
131
|
+
"name": "Pip China Mirror (Huawei)",
|
|
132
|
+
"url": PYPI_MIRROR_HUAWEI,
|
|
133
|
+
"environment_prefix": "PIP",
|
|
134
|
+
"environment_variables": {
|
|
135
|
+
"PIP_INDEX_URL": f"{PYPI_MIRROR_HUAWEI}/simple",
|
|
136
|
+
"PIP_TRUSTED_HOST": "repo.huaweicloud.com",
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
"python": {
|
|
140
|
+
"name": "PyPI China Mirror (Tsinghua)",
|
|
141
|
+
"url": PYPI_MIRROR_TSINGHUA,
|
|
142
|
+
"environment_prefix": "PIP",
|
|
143
|
+
"environment_variables": {
|
|
144
|
+
"PIP_INDEX_URL": f"{PYPI_MIRROR_TSINGHUA}/simple",
|
|
145
|
+
"PIP_TRUSTED_HOST": "pypi.tuna.tsinghua.edu.cn",
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
"poetry": {
|
|
149
|
+
"name": "Poetry China Mirror (Tsinghua)",
|
|
150
|
+
"url": PYPI_MIRROR_TSINGHUA,
|
|
151
|
+
"environment_prefix": "POETRY",
|
|
152
|
+
"environment_variables": {
|
|
153
|
+
"POETRY_REPOSITORIES_PYPI_URL": f"{POETRY_REPO_TSINGHUA}/simple",
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def get_mirror_config(package_manager: str) -> MirrorConfig | None:
|
|
160
|
+
"""Get mirror configuration for a specific package manager.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
package_manager: Name of the package manager (e.g., "npm", "go", "pip")
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
MirrorConfig if found, None otherwise.
|
|
167
|
+
"""
|
|
168
|
+
normalized_name = package_manager.lower().strip()
|
|
169
|
+
return MIRROR_CONFIGS.get(normalized_name)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def apply_mirror_environment(
|
|
173
|
+
package_manager: str,
|
|
174
|
+
environment: dict[str, str]
|
|
175
|
+
) -> dict[str, str]:
|
|
176
|
+
"""Apply mirror environment variables to the environment dict.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
package_manager: Name of the package manager
|
|
180
|
+
environment: Existing environment variables
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Updated environment with mirror variables added.
|
|
184
|
+
"""
|
|
185
|
+
mirror_config = get_mirror_config(package_manager)
|
|
186
|
+
if mirror_config is None:
|
|
187
|
+
return environment
|
|
188
|
+
|
|
189
|
+
mirror_vars = mirror_config.get("environment_variables", {})
|
|
190
|
+
updated_env = environment.copy()
|
|
191
|
+
updated_env.update(mirror_vars)
|
|
192
|
+
|
|
193
|
+
return updated_env
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def reset_mirror_environment(
|
|
197
|
+
package_manager: str,
|
|
198
|
+
environment: dict[str, str]
|
|
199
|
+
) -> dict[str, str]:
|
|
200
|
+
"""Remove mirror environment variables from the environment dict.
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
package_manager: Name of the package manager
|
|
204
|
+
environment: Existing environment variables
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Environment with mirror variables removed.
|
|
208
|
+
"""
|
|
209
|
+
mirror_config = get_mirror_config(package_manager)
|
|
210
|
+
if mirror_config is None:
|
|
211
|
+
return environment
|
|
212
|
+
|
|
213
|
+
mirror_vars = mirror_config.get("environment_variables", {})
|
|
214
|
+
updated_env = environment.copy()
|
|
215
|
+
|
|
216
|
+
for key in mirror_vars:
|
|
217
|
+
updated_env.pop(key, None)
|
|
218
|
+
|
|
219
|
+
return updated_env
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def get_all_mirror_names() -> list[str]:
|
|
223
|
+
"""Get list of all available mirror names.
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
List of package manager names with mirror support.
|
|
227
|
+
"""
|
|
228
|
+
return list(MIRROR_CONFIGS.keys())
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def validate_mirror_config(mirror_config: MirrorConfig) -> bool:
|
|
232
|
+
"""Validate a mirror configuration.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
mirror_config: Mirror configuration to validate
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
True if valid, False otherwise.
|
|
239
|
+
"""
|
|
240
|
+
required_fields = ["name", "url", "environment_prefix", "environment_variables"]
|
|
241
|
+
|
|
242
|
+
for field in required_fields:
|
|
243
|
+
if field not in mirror_config or not mirror_config[field]:
|
|
244
|
+
return False
|
|
245
|
+
|
|
246
|
+
# Validate URL format
|
|
247
|
+
url = mirror_config["url"]
|
|
248
|
+
if not (url.startswith("http://") or url.startswith("https://")):
|
|
249
|
+
return False
|
|
250
|
+
|
|
251
|
+
return True
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"""Register multi-lang-build as a skill for various IDEs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Literal
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_cli_path() -> str:
|
|
14
|
+
"""Get the path to the multi-lang-build CLI."""
|
|
15
|
+
# Try to find the CLI in PATH
|
|
16
|
+
result = subprocess.run(
|
|
17
|
+
["which", "multi-lang-build"],
|
|
18
|
+
capture_output=True,
|
|
19
|
+
text=True,
|
|
20
|
+
)
|
|
21
|
+
if result.returncode == 0:
|
|
22
|
+
return result.stdout.strip()
|
|
23
|
+
|
|
24
|
+
# Fallback: use Python module
|
|
25
|
+
return f"{sys.executable} -m multi_lang_build"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def register_claude_code() -> bool:
|
|
29
|
+
"""Register as Claude Code skill.
|
|
30
|
+
|
|
31
|
+
Claude Code uses ~/.claude/CLAU.md for global instructions
|
|
32
|
+
and project-specific skills via the API.
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
# Check if claude CLI is available
|
|
36
|
+
result = subprocess.run(
|
|
37
|
+
["which", "claude"],
|
|
38
|
+
capture_output=True,
|
|
39
|
+
text=True,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if result.returncode != 0:
|
|
43
|
+
print("❌ Claude Code CLI not found. Please install it first:")
|
|
44
|
+
print(" npm install -g @anthropic-ai/claude-code")
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
# Create global instructions directory
|
|
48
|
+
claude_dir = Path.home() / ".claude"
|
|
49
|
+
claude_dir.mkdir(exist_ok=True)
|
|
50
|
+
|
|
51
|
+
# Read existing CLAU.md or create new
|
|
52
|
+
claude_md = claude_dir / "CLAUDE.md"
|
|
53
|
+
existing_content = ""
|
|
54
|
+
if claude_md.exists():
|
|
55
|
+
existing_content = claude_md.read_text()
|
|
56
|
+
|
|
57
|
+
# Add multi-lang-build skill section
|
|
58
|
+
skill_section = """
|
|
59
|
+
|
|
60
|
+
## Multi-Lang Build Tool
|
|
61
|
+
|
|
62
|
+
You can use the `multi-lang-build` tool to compile projects:
|
|
63
|
+
|
|
64
|
+
### Available Commands:
|
|
65
|
+
- `multi-lang-build pnpm <source> --output <dir>` - Build pnpm projects
|
|
66
|
+
- `multi-lang-build go <source> --output <bin>` - Build Go projects
|
|
67
|
+
- `multi-lang-build python <source> --output <dir>` - Build Python projects
|
|
68
|
+
|
|
69
|
+
### Examples:
|
|
70
|
+
```bash
|
|
71
|
+
# Build Go project
|
|
72
|
+
multi-lang-build go ./src --output ./bin/app --mirror
|
|
73
|
+
|
|
74
|
+
# Build with specific target (multi-entry support)
|
|
75
|
+
multi-lang-build go ./src --output ./bin/server --target cmd/server/main.go
|
|
76
|
+
|
|
77
|
+
# Build Python project
|
|
78
|
+
multi-lang-build python ./src --output ./dist --mirror
|
|
79
|
+
|
|
80
|
+
# Build pnpm project
|
|
81
|
+
multi-lang-build pnpm ./src --output ./dist --mirror
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
When working with Go projects, check if there are multiple main packages and use the `--target` flag to specify which one to build.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
if "## Multi-Lang Build Tool" not in existing_content:
|
|
88
|
+
with open(claude_md, "a") as f:
|
|
89
|
+
f.write(skill_section)
|
|
90
|
+
print(f"✅ Registered with Claude Code (added to {claude_md})")
|
|
91
|
+
else:
|
|
92
|
+
print(f"ℹ️ Already registered with Claude Code ({claude_md})")
|
|
93
|
+
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
print(f"❌ Failed to register with Claude Code: {e}")
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def register_opencode() -> bool:
|
|
102
|
+
"""Register as OpenCode skill.
|
|
103
|
+
|
|
104
|
+
OpenCode typically uses ~/.config/opencode/ for configuration.
|
|
105
|
+
"""
|
|
106
|
+
try:
|
|
107
|
+
# Check if opencode CLI is available
|
|
108
|
+
result = subprocess.run(
|
|
109
|
+
["which", "opencode"],
|
|
110
|
+
capture_output=True,
|
|
111
|
+
text=True,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if result.returncode != 0:
|
|
115
|
+
print("❌ OpenCode CLI not found. Please install it first.")
|
|
116
|
+
return False
|
|
117
|
+
|
|
118
|
+
# Create OpenCode config directory
|
|
119
|
+
config_dir = Path.home() / ".config" / "opencode"
|
|
120
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
121
|
+
|
|
122
|
+
# Create or update skills.json
|
|
123
|
+
skills_file = config_dir / "skills.json"
|
|
124
|
+
skills: dict = {}
|
|
125
|
+
|
|
126
|
+
if skills_file.exists():
|
|
127
|
+
with open(skills_file) as f:
|
|
128
|
+
skills = json.load(f)
|
|
129
|
+
|
|
130
|
+
# Add multi-lang-build skill
|
|
131
|
+
skills["multi-lang-build"] = {
|
|
132
|
+
"name": "multi-lang-build",
|
|
133
|
+
"description": "Multi-language automated build tool with mirror acceleration",
|
|
134
|
+
"commands": {
|
|
135
|
+
"build-go": "multi-lang-build go <source> --output <output> [--mirror] [--target <target>]",
|
|
136
|
+
"build-python": "multi-lang-build python <source> --output <output> [--mirror]",
|
|
137
|
+
"build-pnpm": "multi-lang-build pnpm <source> --output <output> [--mirror]",
|
|
138
|
+
},
|
|
139
|
+
"examples": [
|
|
140
|
+
"multi-lang-build go ./src --output ./bin/app --mirror",
|
|
141
|
+
"multi-lang-build go ./src --output ./bin/server --target cmd/server/main.go",
|
|
142
|
+
"multi-lang-build python ./src --output ./dist --mirror",
|
|
143
|
+
"multi-lang-build pnpm ./src --output ./dist --mirror",
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
with open(skills_file, "w") as f:
|
|
148
|
+
json.dump(skills, f, indent=2)
|
|
149
|
+
|
|
150
|
+
print(f"✅ Registered with OpenCode (config: {skills_file})")
|
|
151
|
+
return True
|
|
152
|
+
|
|
153
|
+
except Exception as e:
|
|
154
|
+
print(f"❌ Failed to register with OpenCode: {e}")
|
|
155
|
+
return False
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def register_trae() -> bool:
|
|
159
|
+
"""Register as Trae skill.
|
|
160
|
+
|
|
161
|
+
Trae typically uses ~/.trae/ for configuration.
|
|
162
|
+
"""
|
|
163
|
+
try:
|
|
164
|
+
# Check if trae CLI is available
|
|
165
|
+
result = subprocess.run(
|
|
166
|
+
["which", "trae"],
|
|
167
|
+
capture_output=True,
|
|
168
|
+
text=True,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if result.returncode != 0:
|
|
172
|
+
print("❌ Trae CLI not found. Please install it first.")
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
# Create Trae config directory
|
|
176
|
+
config_dir = Path.home() / ".trae"
|
|
177
|
+
config_dir.mkdir(exist_ok=True)
|
|
178
|
+
|
|
179
|
+
# Create or update skills.json
|
|
180
|
+
skills_file = config_dir / "skills.json"
|
|
181
|
+
skills: dict = {}
|
|
182
|
+
|
|
183
|
+
if skills_file.exists():
|
|
184
|
+
with open(skills_file) as f:
|
|
185
|
+
skills = json.load(f)
|
|
186
|
+
|
|
187
|
+
# Add multi-lang-build skill
|
|
188
|
+
skills["multi-lang-build"] = {
|
|
189
|
+
"name": "Multi-Lang Build",
|
|
190
|
+
"description": "Automated build tool for Go, Python, and pnpm projects",
|
|
191
|
+
"category": "build",
|
|
192
|
+
"commands": [
|
|
193
|
+
{
|
|
194
|
+
"name": "build-go",
|
|
195
|
+
"command": "multi-lang-build go {source} --output {output}",
|
|
196
|
+
"description": "Build Go project",
|
|
197
|
+
"args": ["source", "output", "target", "mirror"]
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"name": "build-python",
|
|
201
|
+
"command": "multi-lang-build python {source} --output {output}",
|
|
202
|
+
"description": "Build Python project",
|
|
203
|
+
"args": ["source", "output", "mirror"]
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"name": "build-pnpm",
|
|
207
|
+
"command": "multi-lang-build pnpm {source} --output {output}",
|
|
208
|
+
"description": "Build pnpm project",
|
|
209
|
+
"args": ["source", "output", "mirror"]
|
|
210
|
+
}
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
with open(skills_file, "w") as f:
|
|
215
|
+
json.dump(skills, f, indent=2)
|
|
216
|
+
|
|
217
|
+
print(f"✅ Registered with Trae (config: {skills_file})")
|
|
218
|
+
return True
|
|
219
|
+
|
|
220
|
+
except Exception as e:
|
|
221
|
+
print(f"❌ Failed to register with Trae: {e}")
|
|
222
|
+
return False
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def register_codebuddy() -> bool:
|
|
226
|
+
"""Register as CodeBuddy skill.
|
|
227
|
+
|
|
228
|
+
CodeBuddy typically uses ~/.codebuddy/ for configuration.
|
|
229
|
+
"""
|
|
230
|
+
try:
|
|
231
|
+
# Check if codebuddy CLI is available
|
|
232
|
+
result = subprocess.run(
|
|
233
|
+
["which", "codebuddy"],
|
|
234
|
+
capture_output=True,
|
|
235
|
+
text=True,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if result.returncode != 0:
|
|
239
|
+
print("❌ CodeBuddy CLI not found. Please install it first.")
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
# Create CodeBuddy config directory
|
|
243
|
+
config_dir = Path.home() / ".codebuddy"
|
|
244
|
+
config_dir.mkdir(exist_ok=True)
|
|
245
|
+
|
|
246
|
+
# Create or update skills.yaml (CodeBuddy may use YAML)
|
|
247
|
+
skills_file = config_dir / "skills.yaml"
|
|
248
|
+
|
|
249
|
+
skill_config = """# Multi-Lang Build Skill
|
|
250
|
+
skills:
|
|
251
|
+
multi-lang-build:
|
|
252
|
+
name: "Multi-Lang Build"
|
|
253
|
+
description: "Multi-language automated build tool with mirror acceleration"
|
|
254
|
+
version: "0.2.0"
|
|
255
|
+
|
|
256
|
+
commands:
|
|
257
|
+
build-go:
|
|
258
|
+
description: "Build Go project"
|
|
259
|
+
command: "multi-lang-build go {source} --output {output}"
|
|
260
|
+
args:
|
|
261
|
+
- name: source
|
|
262
|
+
description: "Source directory"
|
|
263
|
+
required: true
|
|
264
|
+
- name: output
|
|
265
|
+
description: "Output path"
|
|
266
|
+
required: true
|
|
267
|
+
- name: target
|
|
268
|
+
description: "Build target (file or directory)"
|
|
269
|
+
required: false
|
|
270
|
+
- name: mirror
|
|
271
|
+
description: "Enable mirror acceleration"
|
|
272
|
+
type: flag
|
|
273
|
+
|
|
274
|
+
build-python:
|
|
275
|
+
description: "Build Python project"
|
|
276
|
+
command: "multi-lang-build python {source} --output {output}"
|
|
277
|
+
args:
|
|
278
|
+
- name: source
|
|
279
|
+
description: "Source directory"
|
|
280
|
+
required: true
|
|
281
|
+
- name: output
|
|
282
|
+
description: "Output directory"
|
|
283
|
+
required: true
|
|
284
|
+
- name: mirror
|
|
285
|
+
description: "Enable mirror acceleration"
|
|
286
|
+
type: flag
|
|
287
|
+
|
|
288
|
+
build-pnpm:
|
|
289
|
+
description: "Build pnpm project"
|
|
290
|
+
command: "multi-lang-build pnpm {source} --output {output}"
|
|
291
|
+
args:
|
|
292
|
+
- name: source
|
|
293
|
+
description: "Source directory"
|
|
294
|
+
required: true
|
|
295
|
+
- name: output
|
|
296
|
+
description: "Output directory"
|
|
297
|
+
required: true
|
|
298
|
+
- name: mirror
|
|
299
|
+
description: "Enable mirror acceleration"
|
|
300
|
+
type: flag
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
# Append or create
|
|
304
|
+
if skills_file.exists():
|
|
305
|
+
content = skills_file.read_text()
|
|
306
|
+
if "multi-lang-build" not in content:
|
|
307
|
+
with open(skills_file, "a") as f:
|
|
308
|
+
f.write("\n" + skill_config)
|
|
309
|
+
print(f"✅ Registered with CodeBuddy (updated {skills_file})")
|
|
310
|
+
else:
|
|
311
|
+
print(f"ℹ️ Already registered with CodeBuddy ({skills_file})")
|
|
312
|
+
else:
|
|
313
|
+
skills_file.write_text(skill_config)
|
|
314
|
+
print(f"✅ Registered with CodeBuddy (created {skills_file})")
|
|
315
|
+
|
|
316
|
+
return True
|
|
317
|
+
|
|
318
|
+
except Exception as e:
|
|
319
|
+
print(f"❌ Failed to register with CodeBuddy: {e}")
|
|
320
|
+
return False
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def register_skill(
|
|
324
|
+
ide: Literal["claude", "opencode", "trae", "codebuddy", "all"] = "claude"
|
|
325
|
+
) -> bool:
|
|
326
|
+
"""Register multi-lang-build as a skill for the specified IDE.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
ide: The IDE to register with. Options: "claude", "opencode", "trae", "codebuddy", "all"
|
|
330
|
+
Default is "claude".
|
|
331
|
+
|
|
332
|
+
Returns:
|
|
333
|
+
True if registration succeeded, False otherwise.
|
|
334
|
+
"""
|
|
335
|
+
print(f"📝 Registering multi-lang-build for {ide}...\n")
|
|
336
|
+
|
|
337
|
+
if ide == "all":
|
|
338
|
+
results = [
|
|
339
|
+
("Claude Code", register_claude_code()),
|
|
340
|
+
("OpenCode", register_opencode()),
|
|
341
|
+
("Trae", register_trae()),
|
|
342
|
+
("CodeBuddy", register_codebuddy()),
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
print("\n" + "=" * 50)
|
|
346
|
+
print("Registration Summary:")
|
|
347
|
+
for name, success in results:
|
|
348
|
+
status = "✅" if success else "❌"
|
|
349
|
+
print(f" {status} {name}")
|
|
350
|
+
|
|
351
|
+
return all(success for _, success in results)
|
|
352
|
+
|
|
353
|
+
elif ide == "claude":
|
|
354
|
+
return register_claude_code()
|
|
355
|
+
elif ide == "opencode":
|
|
356
|
+
return register_opencode()
|
|
357
|
+
elif ide == "trae":
|
|
358
|
+
return register_trae()
|
|
359
|
+
elif ide == "codebuddy":
|
|
360
|
+
return register_codebuddy()
|
|
361
|
+
else:
|
|
362
|
+
print(f"❌ Unknown IDE: {ide}")
|
|
363
|
+
print("Supported IDEs: claude, opencode, trae, codebuddy, all")
|
|
364
|
+
return False
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
if __name__ == "__main__":
|
|
368
|
+
import argparse
|
|
369
|
+
|
|
370
|
+
parser = argparse.ArgumentParser(
|
|
371
|
+
description="Register multi-lang-build as an IDE skill"
|
|
372
|
+
)
|
|
373
|
+
parser.add_argument(
|
|
374
|
+
"ide",
|
|
375
|
+
nargs="?",
|
|
376
|
+
default="claude",
|
|
377
|
+
choices=["claude", "opencode", "trae", "codebuddy", "all"],
|
|
378
|
+
help="IDE to register with (default: claude)",
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
args = parser.parse_args()
|
|
382
|
+
success = register_skill(args.ide)
|
|
383
|
+
sys.exit(0 if success else 1)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Type definitions for auto-build project."""
|
|
2
|
+
|
|
3
|
+
from typing import TypeAlias, TypedDict, NotRequired, Literal
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BuildConfig(TypedDict, total=False):
|
|
8
|
+
"""Build configuration for compiler."""
|
|
9
|
+
source_dir: Path
|
|
10
|
+
output_dir: Path
|
|
11
|
+
environment: dict[str, str]
|
|
12
|
+
mirror_enabled: bool
|
|
13
|
+
mirror_region: Literal["china", "global"]
|
|
14
|
+
extra_args: list[str]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BuildResult(TypedDict):
|
|
18
|
+
"""Result of a build operation."""
|
|
19
|
+
success: bool
|
|
20
|
+
return_code: int
|
|
21
|
+
stdout: str
|
|
22
|
+
stderr: str
|
|
23
|
+
output_path: Path | None
|
|
24
|
+
duration_seconds: float
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MirrorConfig(TypedDict, total=False):
|
|
28
|
+
"""Mirror configuration for package managers."""
|
|
29
|
+
name: str
|
|
30
|
+
url: str
|
|
31
|
+
environment_prefix: str
|
|
32
|
+
environment_variables: dict[str, str]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
LanguageType: TypeAlias = Literal["pnpm", "npm", "yarn", "go", "python", "pip", "poetry"]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CompilerInfo(TypedDict):
|
|
39
|
+
"""Information about a compiler."""
|
|
40
|
+
name: str
|
|
41
|
+
version: str
|
|
42
|
+
supported_mirrors: list[str]
|
|
43
|
+
default_mirror: str
|