huaweicloud-devkit 1.0.0 → 1.0.2-dev.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.
- package/README.md +52 -93
- package/README.zh-CN.md +115 -0
- package/package.json +2 -1
- package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +44 -0
- package/plugins/huaweicloud-core/skills/huawei-apig/SKILL.md +22 -2
- package/plugins/huaweicloud-core/skills/huawei-cloud-eye/SKILL.md +17 -0
- package/plugins/huaweicloud-core/skills/huawei-ecs/SKILL.md +50 -0
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/create-instance.md +20 -2
- package/plugins/huaweicloud-core/skills/huawei-obs/SKILL.md +13 -3
- package/plugins/huaweicloud-core/skills/huawei-rds/SKILL.md +48 -5
- package/plugins/huaweicloud-core/skills/huawei-vpc/SKILL.md +5 -2
- package/plugins/huaweicloud-core/src/setup-cli.mjs +172 -27
- package/plugins/huaweicloud-core/src/tools.mjs +5 -0
package/README.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
# HuaweiCloud DevKit
|
|
2
2
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|
[](https://github.com/huaweicloud/HuaweiCloud-Devkit/actions/workflows/ci.yml)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
**[中文](README.zh-CN.md) | English**
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Help AI coding agents use Huawei Cloud safely and accurately — a single integration that gives agents cloud knowledge, CLI tooling, and safety guardrails.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Supports OpenCode, Codex, CodeArts Agent, and WorkBuddy.
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
11
13
|
|
|
12
14
|
### OpenCode
|
|
13
15
|
|
|
@@ -15,13 +17,13 @@ HuaweiCloud DevKit 为 AI 编码助手提供操作华为云所需的知识、工
|
|
|
15
17
|
npx --yes huaweicloud-devkit install
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
Installs the DevKit into OpenCode automatically. **Restart the session** after installation.
|
|
19
21
|
|
|
20
22
|
```bash
|
|
21
|
-
npx --yes huaweicloud-devkit doctor
|
|
22
|
-
npx --yes huaweicloud-devkit status
|
|
23
|
-
npx --yes huaweicloud-devkit update
|
|
24
|
-
npx --yes huaweicloud-devkit uninstall #
|
|
23
|
+
npx --yes huaweicloud-devkit doctor # self-check
|
|
24
|
+
npx --yes huaweicloud-devkit status # show status
|
|
25
|
+
npx --yes huaweicloud-devkit update # update
|
|
26
|
+
npx --yes huaweicloud-devkit uninstall # uninstall
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
### Codex
|
|
@@ -30,127 +32,84 @@ npx --yes huaweicloud-devkit uninstall # 卸载
|
|
|
30
32
|
npx --yes huaweicloud-devkit install --target codex
|
|
31
33
|
```
|
|
32
34
|
|
|
33
|
-
>
|
|
34
|
-
|
|
35
|
-
### CodeArts Agent(码道)
|
|
35
|
+
> The Codex CLI must be installed first.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
### CodeArts Agent
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
npx --yes huaweicloud-devkit install --target codearts
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
**Restart the session** after installation.
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
npx --yes huaweicloud-devkit install-hcloud #
|
|
47
|
-
npx --yes huaweicloud-devkit doctor #
|
|
48
|
-
npx --yes huaweicloud-devkit status --target codearts
|
|
49
|
-
npx --yes huaweicloud-devkit uninstall --target codearts
|
|
46
|
+
npx --yes huaweicloud-devkit install-hcloud # install KooCLI
|
|
47
|
+
npx --yes huaweicloud-devkit doctor # self-check
|
|
48
|
+
npx --yes huaweicloud-devkit status --target codearts
|
|
49
|
+
npx --yes huaweicloud-devkit uninstall --target codearts
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
>
|
|
52
|
+
> **Sandbox mode**: CodeArts defaults to sandbox mode which blocks KooCLI. `install-hcloud` detects this and shows how to resolve it — install KooCLI outside the sandbox terminal, or disable sandbox mode in CodeArts settings (Settings → Permissions → Bash mode).
|
|
53
53
|
>
|
|
54
|
-
>
|
|
54
|
+
> **Authentication**: Run `hcloud configure init` to configure AK/SK and region.
|
|
55
|
+
|
|
56
|
+
### WorkBuddy
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx --yes huaweicloud-devkit install --target workbuddy
|
|
60
|
+
```
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
**Restart the session** after installation.
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
### Other Agents
|
|
65
|
+
|
|
66
|
+
For agents that support the Model Context Protocol (MCP):
|
|
59
67
|
|
|
60
68
|
```json
|
|
61
69
|
{
|
|
62
70
|
"mcp": {
|
|
63
71
|
"huaweicloud-devkit": {
|
|
64
72
|
"type": "local",
|
|
65
|
-
"command": ["node", "
|
|
73
|
+
"command": ["node", "<path>/plugins/huaweicloud-core/src/mcp-server.mjs"],
|
|
66
74
|
"enabled": true
|
|
67
75
|
}
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
```
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
Then install:
|
|
73
81
|
|
|
74
82
|
```bash
|
|
75
83
|
npx --yes huaweicloud-devkit install
|
|
76
84
|
```
|
|
77
85
|
|
|
78
|
-
>
|
|
79
|
-
|
|
80
|
-
## 包含内容
|
|
81
|
-
|
|
82
|
-
### 插件
|
|
83
|
-
|
|
84
|
-
`huaweicloud-core` 插件将 MCP 服务器配置、27 个 Agent 技能和安全策略打包为一次性安装。
|
|
85
|
-
|
|
86
|
-
| 插件 | 说明 |
|
|
87
|
-
|------|------|
|
|
88
|
-
| [huaweicloud-core](plugins/huaweicloud-core/) | 核心插件,含技能、MCP 服务器、安全策略。**从这里开始。** |
|
|
89
|
-
|
|
90
|
-
### 技能
|
|
91
|
-
|
|
92
|
-
Agent 技能是经过整理的指令和参考材料包,帮助 Agent 完成特定的华为云任务。技能按需加载——Agent 只发现和检索与当前任务相关的内容。
|
|
93
|
-
|
|
94
|
-
包含 6 个元技能(路由、发现、CLI/认证、API/SDK、安全、排错)和 20 个服务技能(覆盖 ECS、OBS、VPC、IAM、RDS、GaussDB、FunctionGraph、APIG、CCE、SMN/DMS、ModelArts、Cloud Eye、CTS、DEW、Billing、CBR、WAF/AAD、DDS/DCS、Deployment、Getting Started)。
|
|
95
|
-
|
|
96
|
-
浏览 [`skills/`](plugins/huaweicloud-core/skills/) 目录查看所有可用技能。
|
|
97
|
-
|
|
98
|
-
### Rules 文件
|
|
99
|
-
|
|
100
|
-
推荐的项目级配置文件,告诉 Agent 如何高效使用华为云——例如优先使用 MCP 服务器、发现可用技能、遵循最小权限 IAM 原则。
|
|
101
|
-
|
|
102
|
-
详见 [`rules/huawei-agent-rules.md`](rules/huawei-agent-rules.md)。
|
|
103
|
-
|
|
104
|
-
### MCP 服务器
|
|
105
|
-
|
|
106
|
-
本地 MCP 服务器(`plugins/huaweicloud-core/src/mcp-server.mjs`)通过 Model Context Protocol 为 Agent 提供安全的 KooCLI 访问。
|
|
107
|
-
|
|
108
|
-
- **安全优先执行** — 所有 `hcloud` 命令执行前自动分类(读/写/密钥),写操作需用户明确批准。
|
|
109
|
-
- **输出脱敏** — 凭证形态的值(AK/SK、Token、密码)自动替换为 `***REDACTED***`。
|
|
110
|
-
- **16 个结构化工具** — 技能搜索、CLI 检查、只读命令、区域发现、错误解释、Hook 风险检查等。
|
|
111
|
-
- **零运行时依赖** — 纯 Node.js(>= 20),无需 npm install。
|
|
112
|
-
|
|
113
|
-
详见 [MCP 工具表](#mcp-工具)。
|
|
86
|
+
> **Prerequisites:** [KooCLI](https://support.huaweicloud.com/qs-hcli/hcli_02_003.html) (`hcloud`) installed and authenticated. Node.js >= 20 required.
|
|
114
87
|
|
|
115
|
-
##
|
|
88
|
+
## What It Does
|
|
116
89
|
|
|
117
|
-
|
|
90
|
+
- **Guided cloud operations** — agents get step-by-step guidance for 20+ Huawei Cloud services (ECS, OBS, VPC, RDS, GaussDB, FunctionGraph, APIG, CCE, and more)
|
|
91
|
+
- **Safety-first execution** — all write operations require explicit user approval; credentials and secrets are automatically redacted from output
|
|
92
|
+
- **Pre-execution risk checks** — public exposure, credential leaks, and destructive operations are caught before they run
|
|
93
|
+
- **Regional awareness** — auto-discovers available regions and checks service availability before creating resources
|
|
118
94
|
|
|
119
|
-
|
|
120
|
-
|------|------|------|
|
|
121
|
-
| 技能层 | `SKILL.md` 流程文档 | 教会 Agent 正确的行为规则和安全用法 |
|
|
122
|
-
| 钩子层 | `huaweicloud-safety.py` | PreToolUse Hook 阻断高风险工具调用 |
|
|
123
|
-
| MCP 层 | `safety-policy.mjs` | Node.js 安全策略包装器,在所有 Agent 环境中强制执行 |
|
|
95
|
+
## Supported Services
|
|
124
96
|
|
|
125
|
-
|
|
97
|
+
ECS, OBS, VPC, IAM, RDS, GaussDB, FunctionGraph, APIG, CCE, SMN/DMS, ModelArts, Cloud Eye, CTS, DEW, Billing, CBR, WAF/AAD, DDS/DCS, Deployment, and Getting Started guides.
|
|
126
98
|
|
|
127
|
-
##
|
|
99
|
+
## Documentation
|
|
128
100
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
| 知识发现 | `huaweicloud_get_regional_availability` | 检查目标区域的服务可用性 |
|
|
135
|
-
| CLI | `huaweicloud_check_cli` | 检查 KooCLI `hcloud` 是否已安装 |
|
|
136
|
-
| CLI | `huaweicloud_plan_cli_command` | 分类计划命令(读/写/密钥)但不执行 |
|
|
137
|
-
| CLI | `huaweicloud_list_operations` | 列出服务的可用 KooCLI 操作 |
|
|
138
|
-
| CLI | `huaweicloud_run_readonly_command` | 执行只读命令并脱敏输出 |
|
|
139
|
-
| CLI | `huaweicloud_run_approved_command` | 经用户明确批准后执行写命令 |
|
|
140
|
-
| 安全 | `huaweicloud_show_profile_redacted` | 安全查看 KooCLI 配置(凭证脱敏) |
|
|
141
|
-
| 安全 | `huaweicloud_hook_check_command` | 执行前检查 Shell/KooCLI 命令风险 |
|
|
142
|
-
| 安全 | `huaweicloud_hook_check_artifacts` | 检查生成的代码、IaC、IAM/OBS 策略和配置文件风险 |
|
|
143
|
-
| 安全 | `huaweicloud_hook_check_deploy_plan` | 检查沙箱、预览环境和云资源部署计划风险 |
|
|
144
|
-
| 路由 | `huaweicloud_service_catalog` | 返回推荐的能力来源排序 |
|
|
145
|
-
| 排错 | `huaweicloud_explain_error` | 解释错误码并建议诊断步骤 |
|
|
101
|
+
- [Architecture](docs/architecture.md)
|
|
102
|
+
- [Safety Model](docs/safety-model.md)
|
|
103
|
+
- [Hook Rule Model](docs/hook-rule-model.md)
|
|
104
|
+
- [Changelog](docs/CHANGELOG.md)
|
|
105
|
+
- [KooCLI official docs](https://support.huaweicloud.com/qs-hcli/hcli_02_003.html)
|
|
146
106
|
|
|
147
|
-
##
|
|
107
|
+
## Contributors
|
|
148
108
|
|
|
149
|
-
|
|
150
|
-
-
|
|
151
|
-
|
|
152
|
-
- [KooCLI 官方文档](https://support.huaweicloud.com/qs-hcli/hcli_02_003.html)
|
|
109
|
+
<a href="https://github.com/huaweicloud/huaweicloud-devkit/graphs/contributors">
|
|
110
|
+
<img src="https://contrib.rocks/image?repo=huaweicloud/huaweicloud-devkit" />
|
|
111
|
+
</a>
|
|
153
112
|
|
|
154
|
-
##
|
|
113
|
+
## License
|
|
155
114
|
|
|
156
|
-
|
|
115
|
+
This project is licensed under the Apache-2.0 License. See [LICENSE](LICENSE).
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# HuaweiCloud DevKit
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://github.com/huaweicloud/HuaweiCloud-Devkit/actions/workflows/ci.yml)
|
|
5
|
+
|
|
6
|
+
**中文 | [English](README.md)**
|
|
7
|
+
|
|
8
|
+
帮助 AI 编码助手安全、准确地使用华为云——一站式集成云知识、CLI 工具和安全护栏。
|
|
9
|
+
|
|
10
|
+
支持 OpenCode、Codex、码道(CodeArts Agent)、WorkBuddy。
|
|
11
|
+
|
|
12
|
+
## 快速开始
|
|
13
|
+
|
|
14
|
+
### OpenCode
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx --yes huaweicloud-devkit install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
自动安装 DevKit。安装后**重启会话**。
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx --yes huaweicloud-devkit doctor # 自检
|
|
24
|
+
npx --yes huaweicloud-devkit status # 查看状态
|
|
25
|
+
npx --yes huaweicloud-devkit update # 更新
|
|
26
|
+
npx --yes huaweicloud-devkit uninstall # 卸载
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Codex
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx --yes huaweicloud-devkit install --target codex
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> 需要先安装 Codex CLI。
|
|
36
|
+
|
|
37
|
+
### CodeArts Agent(码道)
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx --yes huaweicloud-devkit install --target codearts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
安装后**重启会话**。
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx --yes huaweicloud-devkit install-hcloud # 安装 KooCLI
|
|
47
|
+
npx --yes huaweicloud-devkit doctor # 自检
|
|
48
|
+
npx --yes huaweicloud-devkit status --target codearts
|
|
49
|
+
npx --yes huaweicloud-devkit uninstall --target codearts
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
> **沙箱模式**:码道默认沙箱模式会阻止 KooCLI 运行。`install-hcloud` 自动检测并给出指引——请在码道外终端安装使用 KooCLI,或在码道设置中关闭沙箱模式(设置 → 权限 → Bash 模式)。
|
|
53
|
+
>
|
|
54
|
+
> **认证**:执行 `hcloud configure init` 配置 AK/SK 与区域。
|
|
55
|
+
|
|
56
|
+
### WorkBuddy
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx --yes huaweicloud-devkit install --target workbuddy
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
安装后**重启会话**。
|
|
63
|
+
|
|
64
|
+
### 其他 Agent
|
|
65
|
+
|
|
66
|
+
支持 MCP 协议的 Agent,手动配置:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcp": {
|
|
71
|
+
"huaweicloud-devkit": {
|
|
72
|
+
"type": "local",
|
|
73
|
+
"command": ["node", "<路径>/plugins/huaweicloud-core/src/mcp-server.mjs"],
|
|
74
|
+
"enabled": true
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
然后安装:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx --yes huaweicloud-devkit install
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
> **前置条件:** 需要安装 [KooCLI](https://support.huaweicloud.com/qs-hcli/hcli_02_003.html)(`hcloud`)并完成认证。Node.js >= 20。
|
|
87
|
+
|
|
88
|
+
## 功能特性
|
|
89
|
+
|
|
90
|
+
- **引导式云操作** — Agent 获得 20+ 华为云服务的分步操作指引(ECS、OBS、VPC、RDS、GaussDB、FunctionGraph、APIG、CCE 等)
|
|
91
|
+
- **安全优先执行** — 所有写操作需用户明确批准;凭证和密钥自动脱敏
|
|
92
|
+
- **执行前风险检查** — 公网暴露、凭证泄露、破坏性操作在执行前即被拦截
|
|
93
|
+
- **区域感知** — 自动发现可用区域,创建资源前检查服务可用性
|
|
94
|
+
|
|
95
|
+
## 支持的服务
|
|
96
|
+
|
|
97
|
+
ECS、OBS、VPC、IAM、RDS、GaussDB、FunctionGraph、APIG、CCE、SMN/DMS、ModelArts、Cloud Eye、CTS、DEW、Billing、CBR、WAF/AAD、DDS/DCS、Deployment,以及入门指南。
|
|
98
|
+
|
|
99
|
+
## 文档
|
|
100
|
+
|
|
101
|
+
- [架构](docs/architecture.md)
|
|
102
|
+
- [安全模型](docs/safety-model.md)
|
|
103
|
+
- [Hook 规则模型](docs/hook-rule-model.md)
|
|
104
|
+
- [变更记录](docs/CHANGELOG.md)
|
|
105
|
+
- [KooCLI 官方文档](https://support.huaweicloud.com/qs-hcli/hcli_02_003.html)
|
|
106
|
+
|
|
107
|
+
## 贡献者
|
|
108
|
+
|
|
109
|
+
<a href="https://github.com/huaweicloud/huaweicloud-devkit/graphs/contributors">
|
|
110
|
+
<img src="https://contrib.rocks/image?repo=huaweicloud/huaweicloud-devkit" />
|
|
111
|
+
</a>
|
|
112
|
+
|
|
113
|
+
## 许可证
|
|
114
|
+
|
|
115
|
+
本项目基于 Apache-2.0 许可证发布。详见 [LICENSE](LICENSE)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.0.0",
|
|
3
|
+
"version": "1.0.2-dev.0",
|
|
4
4
|
"description": "Agent toolkit that helps coding agents use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities safely and accurately.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"agent",
|
|
33
33
|
"codex",
|
|
34
34
|
"opencode",
|
|
35
|
+
"workbuddy",
|
|
35
36
|
"mcp",
|
|
36
37
|
"koocli",
|
|
37
38
|
"hcloud"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "huaweicloud-core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "HuaweiCloud Mate",
|
|
7
|
+
"url": "https://github.com/huaweicloud"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/huaweicloud/HuaweiCloud-Devkit",
|
|
10
|
+
"repository": "https://github.com/huaweicloud/HuaweiCloud-Devkit",
|
|
11
|
+
"license": "Apache-2.0",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"huaweicloud",
|
|
14
|
+
"huawei-cloud",
|
|
15
|
+
"koocli",
|
|
16
|
+
"hcloud",
|
|
17
|
+
"agent",
|
|
18
|
+
"mcp",
|
|
19
|
+
"api",
|
|
20
|
+
"sdk",
|
|
21
|
+
"skills"
|
|
22
|
+
],
|
|
23
|
+
"skills": "./skills/",
|
|
24
|
+
"mcpServers": "./.mcp.json",
|
|
25
|
+
"hooks": "./hooks/",
|
|
26
|
+
"interface": {
|
|
27
|
+
"displayName": "HuaweiCloud Devkit",
|
|
28
|
+
"shortDescription": "HuaweiCloud Devkit - Huawei Cloud guidance, CLI/API/SDK routing, MCP tools, and safety for coding agents.",
|
|
29
|
+
"longDescription": "HuaweiCloud Devkit helps coding agents choose and use Huawei Cloud Skills, KooCLI, APIs, SDKs, and MCP tools with less context, safer command execution, and more accurate cloud implementation decisions.",
|
|
30
|
+
"developerName": "HuaweiCloud Mate",
|
|
31
|
+
"category": "Cloud",
|
|
32
|
+
"capabilities": [
|
|
33
|
+
"Read",
|
|
34
|
+
"Interactive"
|
|
35
|
+
],
|
|
36
|
+
"websiteURL": "https://github.com/huaweicloud/HuaweiCloud-Devkit",
|
|
37
|
+
"brandColor": "#C7000B",
|
|
38
|
+
"defaultPrompt": [
|
|
39
|
+
"Help me choose the right Huawei Cloud capability.",
|
|
40
|
+
"Check my Huawei Cloud CLI setup safely.",
|
|
41
|
+
"Plan this Huawei Cloud API or SDK task."
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -54,14 +54,34 @@ Key gotchas when creating:
|
|
|
54
54
|
|
|
55
55
|
### Add Public Access (ELB Provider Only)
|
|
56
56
|
|
|
57
|
+
`BASIC` instances have no public IP. Use `PROFESSIONAL` + `elb` provider for public access (`lvs` is internal-only).
|
|
58
|
+
|
|
57
59
|
```bash
|
|
58
60
|
hcloud APIG AddIngressEipV2 \
|
|
59
61
|
--instance_id=<id> \
|
|
60
62
|
--bandwidth_charging_mode=bandwidth \
|
|
61
|
-
--bandwidth_size
|
|
63
|
+
--bandwidth_size=<size>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
To use an existing EIP instead of creating a new one:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
hcloud APIG AddIngressEipV2 \
|
|
70
|
+
--instance_id=<id> \
|
|
71
|
+
--eip_id=<existing-eip-id>
|
|
62
72
|
```
|
|
63
73
|
|
|
64
|
-
> `AddIngressEipV2` only works with `elb` provider. `AddEipV2` requires `lvs` provider. Bandwidth minimum is 5 Mbps.
|
|
74
|
+
> `AddIngressEipV2` only works with `elb` provider. `AddEipV2` (without "Ingress") requires `lvs` provider. Bandwidth minimum is 5 Mbps.
|
|
75
|
+
|
|
76
|
+
**Verification** — After binding, poll the instance to confirm EIP is active:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
hcloud APIG ListInstancesV2 --cli-region=<region> --instance_id=<id> --cli-output=json | jq '.instances[0].eip_address'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Wait for `eip_address` to show a valid IP (may take up to 2 minutes). If `eip_address` is still `null` after 2 minutes, the EIP may not have been assigned.
|
|
83
|
+
|
|
84
|
+
> **Trap**: `sl_domain` from `CreateApiGroupV2` is an **internal-only** domain (e.g., `*.apic.cn-north-4.huaweicloudapis.com`). It may resolve to internal IP only (NXDOMAIN from public internet). **For public access, always use the `eip_address` from the instance**, not the `sl_domain` or trigger `invoke_url`.
|
|
65
85
|
|
|
66
86
|
## API Group
|
|
67
87
|
|
|
@@ -53,6 +53,23 @@ hcloud CES CreateAlarm --help
|
|
|
53
53
|
# --condition.comparison_operator, --condition.count
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
### `--condition.comparison_operator` Legal Values
|
|
57
|
+
|
|
58
|
+
For metric alarms use **symbols** (NOT words like `gt`/`lt`):
|
|
59
|
+
|
|
60
|
+
| Value | Meaning |
|
|
61
|
+
|-------|---------|
|
|
62
|
+
| `>` | Greater than |
|
|
63
|
+
| `>=` | Greater than or equal |
|
|
64
|
+
| `<` | Less than |
|
|
65
|
+
| `<=` | Less than or equal |
|
|
66
|
+
| `=` | Equal |
|
|
67
|
+
| `!=` | Not equal |
|
|
68
|
+
|
|
69
|
+
For event alarms: `cycle_decrease`, `cycle_increase`, `cycle_wave`.
|
|
70
|
+
|
|
71
|
+
> **Trap**: Shell may interpret `>` and `<` as redirect operators. Always quote: `--condition.comparison_operator=">="` or use `--cli-jsonInput=<file>`.
|
|
72
|
+
|
|
56
73
|
## Troubleshooting
|
|
57
74
|
|
|
58
75
|
| Error | Fix |
|
|
@@ -57,6 +57,7 @@ Flavor families are **region-dependent**. Always run `hcloud ECS ListFlavors --c
|
|
|
57
57
|
| Security group rule | hcloud VPC CreateSecurityGroupRule --security_group_id=<id> --direction=<direction> --protocol=<protocol> | references/sg.md |
|
|
58
58
|
| Attach disk | hcloud EVS AttachVolume --volume_id=<id> --server_id=<id> | references/evs.md |
|
|
59
59
|
| Delete instance | hcloud ECS DeleteServers --servers.1.id=<id> --delete_publicip=true --delete_volume=true | references/create-instance.md |
|
|
60
|
+
| Reboot instance | hcloud ECS BatchRebootServers --reboot.servers.1.id=<id> --reboot.type=SOFT | NOT `RebootServer` — that operation does not exist |
|
|
60
61
|
|
|
61
62
|
## How to Search for Instances
|
|
62
63
|
|
|
@@ -66,8 +67,57 @@ Flavor families are **region-dependent**. Always run `hcloud ECS ListFlavors --c
|
|
|
66
67
|
2. Filter client-side by name substring, tag, or status
|
|
67
68
|
3. Use `--server_tags` filter if instances are tagged: `hcloud ECS ListServersDetails --server_tags.1.key=Project`
|
|
68
69
|
|
|
70
|
+
> **Return structure**: `ListServersDetails` returns `{"servers": [...]}` (array), NOT `{"server": ...}`. Parse as `.servers[0].status`, NOT `.server.status`.
|
|
71
|
+
|
|
69
72
|
Abort if the result set is larger than `--limit` and ask the user to narrow the search.
|
|
70
73
|
|
|
74
|
+
## Instance Status Polling
|
|
75
|
+
|
|
76
|
+
ECS creation is asynchronous. Status transitions: `BUILD` → `ACTIVE` (or `ERROR`). Wait times vary widely (20s–3min), never use fixed sleep.
|
|
77
|
+
|
|
78
|
+
Poll strategy:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
for i in $(seq 1 30); do
|
|
82
|
+
status=$(hcloud ECS ListServersDetails --cli-region=<region> --server_id=<id> --cli-output=json | jq -r '.servers[0].status')
|
|
83
|
+
if [ "$status" = "ACTIVE" ]; then break; fi
|
|
84
|
+
if [ "$status" = "ERROR" ]; then echo "Creation failed"; exit 1; fi
|
|
85
|
+
sleep 10
|
|
86
|
+
done
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- Poll interval: 10 seconds
|
|
90
|
+
- Maximum wait: 5 minutes (30 iterations)
|
|
91
|
+
- Check for `ERROR` status to detect creation failures early
|
|
92
|
+
|
|
93
|
+
## SSH Connection Verification
|
|
94
|
+
|
|
95
|
+
After ECS is ACTIVE and EIP is bound, verify SSH connectivity:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
hcloud ECS ListServersDetails --cli-region=<region> --server_id=<id>
|
|
99
|
+
# → addresses.<vpc-id>[].OS-EXT-IPS:addr
|
|
100
|
+
|
|
101
|
+
ssh -o StrictHostKeyChecking=accept-new -i <path-to-private-key> root@<eip-address>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
> **SSH verification checklist**: EIP bound → security group has port 22 ingress → keypair private key saved locally → known_hosts handled with `StrictHostKeyChecking=accept-new` (or delete stale entries with `ssh-keygen -R <ip>`).
|
|
105
|
+
|
|
106
|
+
### Running Commands Inside the Instance
|
|
107
|
+
|
|
108
|
+
Use SSH for any in-instance operations (install software, check logs, start services):
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
ssh -o StrictHostKeyChecking=accept-new -i <key> root@<eip> 'command'
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Example — re-run failed cloud-init setup manually:
|
|
115
|
+
```bash
|
|
116
|
+
ssh -o StrictHostKeyChecking=accept-new -i <key> root@<eip> 'dnf install -y nginx && systemctl enable --now nginx'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
> If SCP blocks SSH, use cloud-init `--server.user_data` for full deployment instead. See `references/create-instance.md` §Bootstrap.
|
|
120
|
+
|
|
71
121
|
## Deleting Instances
|
|
72
122
|
|
|
73
123
|
- Show the user the exact command and get explicit approval before running
|
|
@@ -61,6 +61,11 @@ hcloud ECS CreateServers ... --server.user_data=$user_data
|
|
|
61
61
|
> **Security**: Never embed secrets (passwords, AK/SK, tokens) in user_data. It is stored unencrypted and readable from within the instance via IMDS. Fetch secrets at boot from DEW/CSMS instead.
|
|
62
62
|
>
|
|
63
63
|
> **Debugging**: If the script didn't run, check `/var/log/cloud-init-output.log` on the instance.
|
|
64
|
+
>
|
|
65
|
+
> **Recovery after failure**: user_data only executes on **first boot**. Restarting the instance will NOT re-run user_data scripts. If cloud-init fails (e.g., DNS missing → `yum`/`apt` cannot resolve repos):
|
|
66
|
+
> 1. Fix the root cause (e.g., update subnet DNS via `VPC UpdateSubnet`)
|
|
67
|
+
> 2. Either: SSH into the instance and run the setup commands manually (see `huawei-ecs` → SSH Connection Verification → Running Commands Inside the Instance)
|
|
68
|
+
> 3. Or: Delete the instance and recreate with corrected user_data (fresh boot)
|
|
64
69
|
|
|
65
70
|
## 7. EIP (two methods)
|
|
66
71
|
|
|
@@ -91,8 +96,21 @@ hcloud EIP AssociatePublicips --publicip_id=<eip-id> --publicip.associate_instan
|
|
|
91
96
|
```
|
|
92
97
|
|
|
93
98
|
## 8. Verify
|
|
94
|
-
|
|
95
|
-
|
|
99
|
+
|
|
100
|
+
ECS creation is asynchronous. Wait times vary widely (20s to 3min). Status transitions: `BUILD` → `ACTIVE` (or `ERROR`). Never use fixed sleep — poll actively:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
for i in $(seq 1 30); do
|
|
104
|
+
status=$(hcloud ECS ListServersDetails --cli-region=<region> --server_id=<instance-id> --cli-output=json | jq -r '.servers[0].status')
|
|
105
|
+
if [ "$status" = "ACTIVE" ]; then break; fi
|
|
106
|
+
if [ "$status" = "ERROR" ]; then echo "Creation failed"; exit 1; fi
|
|
107
|
+
sleep 10
|
|
108
|
+
done
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
- Poll interval: 10 seconds
|
|
112
|
+
- Maximum wait: 5 minutes (30 iterations)
|
|
113
|
+
- After ACTIVE, confirm once more: `hcloud ECS ListServersDetails --cli-region=<region> --server_id=<instance-id>`
|
|
96
114
|
|
|
97
115
|
### Verify HTTP accessibility (if EIP bound)
|
|
98
116
|
|
|
@@ -31,7 +31,7 @@ Domain expertise for Huawei Cloud Object Storage Service (OBS). Covers bucket/ob
|
|
|
31
31
|
|
|
32
32
|
| Trap | Why |
|
|
33
33
|
|------|-----|
|
|
34
|
-
| Bucket name is global | All users share bucket namespace |
|
|
34
|
+
| Bucket name is global | All users share bucket namespace. Always use a unique name: `{prefix}-{timestamp}` (e.g. `mybucket-20260810155048`) |
|
|
35
35
|
| Three-layer permissions | IAM > Bucket Policy > ACL. Most restrictive wins |
|
|
36
36
|
| Versioning is irreversible | Once enabled, cannot be disabled, only suspended |
|
|
37
37
|
| OBS uses AK/SK directly | NOT IAM tokens. Auth errors mean check AK/SK validity |
|
|
@@ -42,7 +42,17 @@ Domain expertise for Huawei Cloud Object Storage Service (OBS). Covers bucket/ob
|
|
|
42
42
|
|
|
43
43
|
## OBS Credential Setup (Required Before First Use)
|
|
44
44
|
|
|
45
|
-
KooCLI OBS uses a separate config file (`~/.obsutilconfig`), NOT `~/.hcloud/config.json`.
|
|
45
|
+
KooCLI OBS uses a separate config file (`~/.obsutilconfig`), NOT `~/.hcloud/config.json`. All OBS commands fail with credential errors until this is configured.
|
|
46
|
+
|
|
47
|
+
**In-session bootstrap (recommended)**: Call `huaweicloud_setup_obs_config` — it syncs AK/SK from the active hcloud profile automatically. No manual key entry needed. Run this once per session before any OBS command.
|
|
48
|
+
|
|
49
|
+
**CLI fallback** (if MCP tools unavailable):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
hcloud OBS config -e=<endpoint> -i=<AK> -k=<SK> -t=token
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
> `huaweicloud_setup_obs_config` should be called at the start of every OBS task — never assume credentials are pre-configured from a previous session.
|
|
46
56
|
|
|
47
57
|
## Common Workflows
|
|
48
58
|
|
|
@@ -82,7 +92,7 @@ Build → Create bucket → Upload → Set bucket ACL → Set object ACL → Con
|
|
|
82
92
|
| Error | Root Cause -> Fix |
|
|
83
93
|
|-------|------------------|
|
|
84
94
|
| AccessDenied on bucket | IAM/bucket policy/ACL conflict -> Check all three layers |
|
|
85
|
-
| BucketAlreadyExists | Name taken globally ->
|
|
95
|
+
| BucketAlreadyExists | Name taken globally -> Generate unique name with timestamp suffix: `{prefix}-{yyyymmddHHMMSS}` |
|
|
86
96
|
| NoSuchKey | Object doesn't exist or wrong region -> Verify key and region |
|
|
87
97
|
| InvalidAccessKeyId | OBS uses AK/SK directly -> Verify AK/SK validity, OBS endpoint, OBS permissions |
|
|
88
98
|
| EntityTooLarge | Single PUT limit 5GB -> Use multipart upload |
|
|
@@ -29,7 +29,7 @@ hcloud RDS <Operation> --cli-region=<region> [--key=value ...]
|
|
|
29
29
|
| Operation | PascalCase: `ListInstances`, `CreateManualBackup` |
|
|
30
30
|
| Params | `--key=value` format. JSON params: `--key='{"k":"v"}'` |
|
|
31
31
|
| Array params | 1-based: `--instance_ids.1=xxx` |
|
|
32
|
-
| Password param | Conflicts with KooCLI system param;
|
|
32
|
+
| Password param | Conflicts with KooCLI system param; use `--cli-jsonInput` (see Critical Warnings) |
|
|
33
33
|
|
|
34
34
|
## Critical Warnings
|
|
35
35
|
|
|
@@ -38,9 +38,12 @@ hcloud RDS <Operation> --cli-region=<region> [--key=value ...]
|
|
|
38
38
|
| Engine version immutable | Cannot change MySQL to PostgreSQL in-place |
|
|
39
39
|
| Automated backups use OBS | Backup storage incurs separate charges. Set retention period explicitly |
|
|
40
40
|
| Storage auto-scaling off by default | Enable before storage runs out or instance goes read-only |
|
|
41
|
-
| `--password` conflicts with KooCLI |
|
|
41
|
+
| `--password` conflicts with KooCLI | Use `--cli-jsonInput=<file>` with JSON file (see `--cli-jsonInput` section below). The `printf "b\n"` workaround is broken in KooCLI 7.2.12+ |
|
|
42
42
|
| Volume type must match flavor | General→CLOUDSSD; Dedicated→CLOUDSSD\|ESSD; ARM→ULTRAHIGH |
|
|
43
43
|
| Flavor not in region | Always `ListFlavors` first. Spec codes vary by region |
|
|
44
|
+
| `database_name` is case-sensitive | Use `MySQL` / `PostgreSQL` / `SQLServer` / `MariaDB` — NOT lower-case `mysql` |
|
|
45
|
+
| Instance creation takes 3–8 min | Status: BUILD→MODIFYING→ACTIVE. Poll every 15s: `hcloud RDS ListInstances --cli-region=<r> --instance_id=<id> \| jq '.instances[0].status'` |
|
|
46
|
+
| Body `--region` is required | CreateInstance body requires `--region=<r>` (same as `--cli-region`) or `DBS.280243` |
|
|
44
47
|
| Restore creates new instance | No in-place restore. Verify target flavor before restoring |
|
|
45
48
|
|
|
46
49
|
## Instance Management
|
|
@@ -56,6 +59,7 @@ hcloud RDS ListEngineFlavors --instance_id=<id> --cli-region=<r>
|
|
|
56
59
|
### Create Instance
|
|
57
60
|
```bash
|
|
58
61
|
hcloud RDS CreateInstance --cli-region=<r> \
|
|
62
|
+
--region=<r> \
|
|
59
63
|
--name=<name> \
|
|
60
64
|
--datastore.type=<engine> \
|
|
61
65
|
--datastore.version=<version> \
|
|
@@ -66,11 +70,36 @@ hcloud RDS CreateInstance --cli-region=<r> \
|
|
|
66
70
|
--subnet_id=<subnet-id> \
|
|
67
71
|
--security_group_id=<sg-id> \
|
|
68
72
|
--availability_zone=<az> \
|
|
69
|
-
--charge_info.charge_mode=<mode>
|
|
70
|
-
--password=<pw>
|
|
73
|
+
--charge_info.charge_mode=<mode>
|
|
71
74
|
```
|
|
72
75
|
|
|
73
|
-
> `--password` conflicts with a KooCLI system param.
|
|
76
|
+
> `--password` conflicts with a KooCLI system param. Use `--cli-jsonInput` (see below). The `printf "b\n"` pipe workaround is broken in KooCLI 7.2.12+.
|
|
77
|
+
|
|
78
|
+
### `--cli-jsonInput` for CreateInstance
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"path": {
|
|
83
|
+
"project_id": "<project-id>"
|
|
84
|
+
},
|
|
85
|
+
"body": {
|
|
86
|
+
"name": "<name>",
|
|
87
|
+
"region": "<region>",
|
|
88
|
+
"datastore": { "type": "<engine>", "version": "<version>" },
|
|
89
|
+
"ha": { "mode": "single", "replication_mode": "semisync" },
|
|
90
|
+
"flavor_ref": "<flavor-id>",
|
|
91
|
+
"volume": { "type": "<vol-type>", "size": <gb> },
|
|
92
|
+
"vpc_id": "<vpc-id>",
|
|
93
|
+
"subnet_id": "<subnet-id>",
|
|
94
|
+
"security_group_id": "<sg-id>",
|
|
95
|
+
"availability_zone": "<az>",
|
|
96
|
+
"password": "<pw>",
|
|
97
|
+
"charge_info": { "charge_mode": "postPaid" }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> Save as `rds-create.json` then: `hcloud RDS CreateInstance --cli-jsonInput=rds-create.json`. For `project_id`, run `hcloud IAM KeystoneListProjects`.
|
|
74
103
|
|
|
75
104
|
| Param | Required | Note |
|
|
76
105
|
|-------|----------|------|
|
|
@@ -139,6 +168,20 @@ psql -h <private_ip> -p 5432 -U root -d postgres
|
|
|
139
168
|
> hcloud does NOT support SQL execution. Use a database client.
|
|
140
169
|
> For public access, bind an EIP (see `huawei-vpc`).
|
|
141
170
|
|
|
171
|
+
### Database Client Acquisition
|
|
172
|
+
|
|
173
|
+
If a database client is not installed on the agent's machine, install one:
|
|
174
|
+
|
|
175
|
+
| Platform | MySQL | PostgreSQL |
|
|
176
|
+
|----------|-------|------------|
|
|
177
|
+
| **Linux** | `apt install mysql-client` / `yum install mysql` | `apt install postgresql-client` |
|
|
178
|
+
| **macOS** | `brew install mysql-client` | `brew install libpq` |
|
|
179
|
+
| **Windows** | Download MySQL Workbench or `winget install Oracle.MySQL` | Download pgAdmin or `winget install PostgreSQL.PostgreSQL` |
|
|
180
|
+
| **Python (any)** | `pip install pymysql` then `python -c "import pymysql; ..."` | `pip install psycopg2` then `python -c "import psycopg2; ..."` |
|
|
181
|
+
| **Docker (any)** | `docker run -it --rm mysql:8 mysql -h <ip> -u root -p` | `docker run -it --rm postgres:16 psql -h <ip> -U root` |
|
|
182
|
+
|
|
183
|
+
> If no client can be installed, use the Huawei Cloud **Data Studio** console: https://console.huaweicloud.com/dms/
|
|
184
|
+
|
|
142
185
|
## Mutating Operations (Require Approval)
|
|
143
186
|
|
|
144
187
|
| Operation | Effect |
|
|
@@ -28,15 +28,17 @@ Domain expertise for Huawei Cloud Virtual Private Cloud (VPC). Covers VPC/subnet
|
|
|
28
28
|
| EIP PER type needs `--bandwidth.name` | PER bandwidth requires explicit name; `--help` marks it optional but it's required |
|
|
29
29
|
| **VPC params need nested prefix** | KooCLI 7.x VPC API uses `--vpc.<param>`, `--subnet.<param>`, `--security_group.<param>`. Example: `--vpc.name=xxx` NOT `--name=xxx` |
|
|
30
30
|
| **Security group needs no vpc_id** | VPC v3 API `CreateSecurityGroup` does NOT accept `vpc_id`. Security groups are region-level, not VPC-bound |
|
|
31
|
-
| Subnet DNS empty → ECS no DNS | DNS params (`--subnet.primary_dns`, `--subnet.secondary_dns`) marked optional but empty default breaks cloud-init domain resolution — `yum`/`apt` installs fail silently. Always set both.
|
|
31
|
+
| Subnet DNS empty → ECS no DNS | DNS params (`--subnet.primary_dns`, `--subnet.secondary_dns`) marked optional but empty default breaks cloud-init domain resolution — `yum`/`apt` installs fail silently. Always set both. Common DNS IPs: cn-north-4 (100.125.1.250 / 100.125.1.251), cn-north-1 (100.125.1.250 / 100.125.129.250), cn-east-3 (100.125.1.250 / 100.125.129.250), ap-southeast-3 (100.125.1.250 / 100.125.128.250) |
|
|
32
32
|
| SCP blocks 0.0.0.0/0 SG rules | If `CreateSecurityGroupRule` with `--remote_ip_prefix=0.0.0.0/0` fails with `SYS.0403`, an org-level SCP policy is denying wide-open rules. Narrow to a specific CIDR range (e.g., your office IP) instead |
|
|
33
|
+
| **VPC tags use `*` separator** | VPC tag format: `--vpc.tags.1=env*test` (asterisk between key and value). NOT `--vpc.tags.1.key=env` (ECS-style). This is different from ECS `--server.metadata.key=value` |
|
|
33
34
|
|
|
34
35
|
## Common Workflows
|
|
35
36
|
|
|
36
37
|
| Task | Command | Steps |
|
|
37
38
|
|------|---------|-------|
|
|
38
39
|
| Create VPC | hcloud VPC CreateVpc --vpc.name=<name> --vpc.cidr=<cidr> | CIDR must not conflict with existing VPCs. Run `hcloud VPC ListVpcs` first |
|
|
39
|
-
| Create subnet | hcloud VPC CreateSubnet --subnet.name=<name> --subnet.vpc_id=<id> --subnet.cidr=<cidr> --subnet.gateway_ip=<gw> --subnet.primary_dns=<dns1> --subnet.secondary_dns=<dns2> --subnet.availability_zone=<az> | Subnet CIDR must be a subset of the VPC CIDR. DNS addresses vary by region — see
|
|
40
|
+
| Create subnet | hcloud VPC CreateSubnet --subnet.name=<name> --subnet.vpc_id=<id> --subnet.cidr=<cidr> --subnet.gateway_ip=<gw> --subnet.primary_dns=<dns1> --subnet.secondary_dns=<dns2> --subnet.availability_zone=<az> | Subnet CIDR must be a subset of the VPC CIDR. DNS addresses vary by region — see Critical Warnings for common values |
|
|
41
|
+
| Update subnet | hcloud VPC UpdateSubnet --subnet_id=<id> --subnet.dnsList.1=<dns1> --subnet.dnsList.2=<dns2> | Fix DNS after creation. Restart ECS after updating DNS for cloud-init to pick up changes |
|
|
40
42
|
| Security group | hcloud VPC CreateSecurityGroup --security_group.name=<name> | references/security-group.md |
|
|
41
43
|
| SG rule | hcloud VPC CreateSecurityGroupRule --security_group_rule.security_group_id=<id> --security_group_rule.direction=<direction> --security_group_rule.protocol=<protocol> --security_group_rule.multiport=<port> --security_group_rule.remote_ip_prefix=<cidr> | references/security-group.md |
|
|
42
44
|
| Create EIP | hcloud EIP CreatePublicip --publicip.type=<type> --bandwidth.size=<size> --bandwidth.share_type=<share-type> --bandwidth.name=<name> | Run `hcloud EIP CreatePublicip --help` to confirm valid type values per region |
|
|
@@ -58,6 +60,7 @@ Domain expertise for Huawei Cloud Virtual Private Cloud (VPC). Covers VPC/subnet
|
|
|
58
60
|
| VPC.0301: Bandwidth name invalid | PER type requires `--bandwidth.name`, even though `--help` marks it optional |
|
|
59
61
|
| EIP has no public IP after binding | May need AddIngressEipV2 for ELB-type resources (see huawei-apig) |
|
|
60
62
|
| ECS cloud-init fails silently (port 80/443 closed) | Subnet likely has no DNS. Check `hcloud VPC ShowSubnet --subnet_id=<id>` → `dnsList` empty? Rebuild subnet with `--subnet.primary_dns=<dns1> --subnet.secondary_dns=<dns2>`. DNS addresses per region: `hcloud VPC CreateSubnet --help` |
|
|
63
|
+
| VPC.0209: Subnet still used | Subnet has dependent resources (ECS/RDS) — delete instances first, then subnet |
|
|
61
64
|
| SYS.0403 / SCP deny | Service Control Policy explicitly denies this operation — contact org admin to adjust SCP, or use an account/region without the restriction. If SSH is blocked, bootstrap via cloud-init user_data instead: see `huawei-ecs` — no SSH needed |
|
|
62
65
|
|
|
63
66
|
## Security Considerations
|
|
@@ -50,6 +50,10 @@ function codeartsProjectSkillsDir() { return join(codeartsProjectDir(), 'skills'
|
|
|
50
50
|
function codeartsProjectMcpSettingsFile() { return join(codeartsProjectDir(), 'mcp', 'mcp_settings.json'); }
|
|
51
51
|
function codeartsPluginsDir() { return join(homedir(), '.codeartsdoer', 'huaweicloud-plugins'); }
|
|
52
52
|
|
|
53
|
+
function workbuddySkillsDir() { return join(homedir(), '.workbuddy', 'skills'); }
|
|
54
|
+
function workbuddyMcpConfigFile() { return join(homedir(), '.workbuddy', 'mcp.json'); }
|
|
55
|
+
function workbuddyPluginsDir() { return join(homedir(), '.workbuddy', 'huaweicloud-plugins'); }
|
|
56
|
+
|
|
53
57
|
// Detect CodeArts sandbox mode (bash_mode in permission config).
|
|
54
58
|
function detectCodeartsSandbox() {
|
|
55
59
|
try {
|
|
@@ -110,8 +114,13 @@ function copyDir(src, dest) {
|
|
|
110
114
|
|
|
111
115
|
function removeIfExists(p) {
|
|
112
116
|
if (existsSync(p)) {
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
try {
|
|
118
|
+
rmSync(p, { recursive: true, force: true });
|
|
119
|
+
return true;
|
|
120
|
+
} catch (e) {
|
|
121
|
+
console.log(` \x1b[33m[WARN]\x1b[0m Could not remove ${p}: ${e.message}`);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
115
124
|
}
|
|
116
125
|
return false;
|
|
117
126
|
}
|
|
@@ -463,6 +472,93 @@ function codeartsStatus() {
|
|
|
463
472
|
}
|
|
464
473
|
}
|
|
465
474
|
|
|
475
|
+
async function installWorkBuddy() {
|
|
476
|
+
const skillsSrc = join(PLUGIN_ROOT, 'skills');
|
|
477
|
+
const srcDir = join(PLUGIN_ROOT, 'src');
|
|
478
|
+
const safetyDir = join(PLUGIN_ROOT, 'safety');
|
|
479
|
+
const pluginDest = workbuddyPluginsDir();
|
|
480
|
+
|
|
481
|
+
copyDir(skillsSrc, workbuddySkillsDir());
|
|
482
|
+
console.log(` Skills -> ${workbuddySkillsDir()}`);
|
|
483
|
+
|
|
484
|
+
copyDir(srcDir, join(pluginDest, 'src'));
|
|
485
|
+
console.log(` MCP Server -> ${join(pluginDest, 'src')}`);
|
|
486
|
+
copyDir(safetyDir, join(pluginDest, 'safety'));
|
|
487
|
+
console.log(` Safety Policy -> ${join(pluginDest, 'safety')}`);
|
|
488
|
+
|
|
489
|
+
// Write MCP config to ~/.workbuddy/mcp.json
|
|
490
|
+
const mcpPath = join(pluginDest, 'src', 'mcp-server.mjs').replace(/\\/g, '/');
|
|
491
|
+
const configPath = workbuddyMcpConfigFile();
|
|
492
|
+
let config = {};
|
|
493
|
+
if (existsSync(configPath)) {
|
|
494
|
+
try { config = JSON.parse(readFileSync(configPath, 'utf8')); } catch {}
|
|
495
|
+
}
|
|
496
|
+
const env = { HUAWEICLOUD_AGENT_TOOLKIT_MODE: 'local' };
|
|
497
|
+
const hcloudBin = findHcloudBin();
|
|
498
|
+
if (hcloudBin) env.HCLOUD_BIN = hcloudBin.replace(/\\/g, '/');
|
|
499
|
+
config.mcpServers = config.mcpServers || {};
|
|
500
|
+
config.mcpServers['huaweicloud-devkit'] = {
|
|
501
|
+
command: 'node',
|
|
502
|
+
args: [mcpPath],
|
|
503
|
+
env,
|
|
504
|
+
};
|
|
505
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
506
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
507
|
+
console.log(` MCP config updated: ${configPath}`);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function uninstallWorkBuddy() {
|
|
511
|
+
const skillsDir = workbuddySkillsDir();
|
|
512
|
+
let removed = 0;
|
|
513
|
+
if (existsSync(skillsDir)) {
|
|
514
|
+
for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
515
|
+
if (entry.name.startsWith('huawei')) {
|
|
516
|
+
removeIfExists(join(skillsDir, entry.name));
|
|
517
|
+
removed++;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (removed > 0) console.log(` Removed ${removed} skills`);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (removeIfExists(workbuddyPluginsDir())) {
|
|
524
|
+
console.log(' Removed MCP server and safety policy');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const configPath = workbuddyMcpConfigFile();
|
|
528
|
+
if (existsSync(configPath)) {
|
|
529
|
+
let config = {};
|
|
530
|
+
try { config = JSON.parse(readFileSync(configPath, 'utf8')); } catch {}
|
|
531
|
+
if (config.mcpServers?.['huaweicloud-devkit']) {
|
|
532
|
+
delete config.mcpServers['huaweicloud-devkit'];
|
|
533
|
+
if (Object.keys(config.mcpServers).length === 0) delete config.mcpServers;
|
|
534
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
535
|
+
console.log(` MCP config cleaned: ${configPath}`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function workbuddyStatus() {
|
|
541
|
+
const pluginDir = workbuddyPluginsDir();
|
|
542
|
+
const skillsDir = workbuddySkillsDir();
|
|
543
|
+
console.log(` MCP Server: ${existsSync(join(pluginDir, 'src', 'mcp-server.mjs')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`);
|
|
544
|
+
console.log(` Safety Policy: ${existsSync(join(pluginDir, 'safety', 'policy.json')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`);
|
|
545
|
+
let skillCount = 0;
|
|
546
|
+
if (existsSync(skillsDir)) {
|
|
547
|
+
skillCount = readdirSync(skillsDir, { withFileTypes: true })
|
|
548
|
+
.filter((d) => d.isDirectory() && d.name.startsWith('huawei')).length;
|
|
549
|
+
}
|
|
550
|
+
console.log(` Skills: ${skillCount > 0 ? `\x1b[32m${skillCount} installed\x1b[0m` : '\x1b[31mNot installed\x1b[0m'}`);
|
|
551
|
+
const configPath = workbuddyMcpConfigFile();
|
|
552
|
+
if (existsSync(configPath)) {
|
|
553
|
+
try {
|
|
554
|
+
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
555
|
+
console.log(` MCP config: ${config.mcpServers?.['huaweicloud-devkit'] ? '\x1b[32mConfigured\x1b[0m' : '\x1b[31mNot configured\x1b[0m'}`);
|
|
556
|
+
} catch {
|
|
557
|
+
console.log(` MCP config: \x1b[31mInvalid\x1b[0m`);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
466
562
|
function opencodeStatus() {
|
|
467
563
|
const pluginDir = opencodePluginsDir();
|
|
468
564
|
const skillsDir = opencodeSkillsDir();
|
|
@@ -492,6 +588,7 @@ function parseTarget() {
|
|
|
492
588
|
if (val === 'codex') return 'codex';
|
|
493
589
|
if (val === 'codex-desktop') return 'codex-desktop';
|
|
494
590
|
if (val === 'codearts') return 'codearts';
|
|
591
|
+
if (val === 'workbuddy') return 'workbuddy';
|
|
495
592
|
if (val === 'all') return 'all';
|
|
496
593
|
return 'opencode';
|
|
497
594
|
}
|
|
@@ -514,6 +611,10 @@ async function cmdInstall() {
|
|
|
514
611
|
console.log('\n[CodeArts]');
|
|
515
612
|
await installCodeArts();
|
|
516
613
|
}
|
|
614
|
+
if (target === 'workbuddy' || target === 'all') {
|
|
615
|
+
console.log('\n[WorkBuddy]');
|
|
616
|
+
await installWorkBuddy();
|
|
617
|
+
}
|
|
517
618
|
if (target === 'codex' || target === 'all') {
|
|
518
619
|
console.log('\n[Codex]');
|
|
519
620
|
if (!hasCodexCLI()) {
|
|
@@ -539,7 +640,9 @@ async function cmdInstall() {
|
|
|
539
640
|
} console.log(`\n\x1b[32mInstallation complete!\x1b[0m`);
|
|
540
641
|
const appName = target === 'codearts' ? 'CodeArts'
|
|
541
642
|
: target === 'codex-desktop' ? 'Codex Desktop'
|
|
542
|
-
: target === 'codex' ? 'Codex'
|
|
643
|
+
: target === 'codex' ? 'Codex'
|
|
644
|
+
: target === 'workbuddy' ? 'WorkBuddy'
|
|
645
|
+
: 'OpenCode';
|
|
543
646
|
const pad = ' '.repeat(24 - appName.length);
|
|
544
647
|
console.log(`\n\x1b[1m\x1b[33m╔══════════════════════════════════════════════════════╗`);
|
|
545
648
|
console.log(`\x1b[1m\x1b[33m║ MCP 工具在重启 ${appName} 会话后才生效${pad}║`);
|
|
@@ -558,7 +661,9 @@ async function cmdInstall() {
|
|
|
558
661
|
console.log(`\nAfter restart + hcloud setup, run: npx huaweicloud-devkit doctor`);
|
|
559
662
|
|
|
560
663
|
// Write install marker for doctor to detect
|
|
561
|
-
const markerDir = target === 'codearts' ? codeartsPluginsDir()
|
|
664
|
+
const markerDir = target === 'codearts' ? codeartsPluginsDir()
|
|
665
|
+
: target === 'workbuddy' ? workbuddyPluginsDir()
|
|
666
|
+
: opencodePluginsDir();
|
|
562
667
|
writeFileSync(join(markerDir, '.installed'), new Date().toISOString());
|
|
563
668
|
if (target === 'opencode' || target === 'all') {
|
|
564
669
|
console.log('Or describe your Huawei Cloud task in OpenCode');
|
|
@@ -569,6 +674,9 @@ async function cmdInstall() {
|
|
|
569
674
|
if (target === 'codex' || target === 'all') {
|
|
570
675
|
console.log('Or mention @huaweicloud-core in Codex');
|
|
571
676
|
}
|
|
677
|
+
if (target === 'workbuddy' || target === 'all') {
|
|
678
|
+
console.log('Or describe your Huawei Cloud task in WorkBuddy');
|
|
679
|
+
}
|
|
572
680
|
}
|
|
573
681
|
|
|
574
682
|
async function cmdUninstall() {
|
|
@@ -584,6 +692,10 @@ async function cmdUninstall() {
|
|
|
584
692
|
console.log('\n[CodeArts]');
|
|
585
693
|
uninstallCodeArts();
|
|
586
694
|
}
|
|
695
|
+
if (target === 'workbuddy' || target === 'all') {
|
|
696
|
+
console.log('\n[WorkBuddy]');
|
|
697
|
+
uninstallWorkBuddy();
|
|
698
|
+
}
|
|
587
699
|
if (target === 'codex' || target === 'all') {
|
|
588
700
|
console.log('\n[Codex]');
|
|
589
701
|
uninstallCodexDesktop();
|
|
@@ -609,6 +721,10 @@ async function cmdStatus() {
|
|
|
609
721
|
console.log('\n[CodeArts]');
|
|
610
722
|
codeartsStatus();
|
|
611
723
|
}
|
|
724
|
+
if (target === 'workbuddy' || target === 'all') {
|
|
725
|
+
console.log('\n[WorkBuddy]');
|
|
726
|
+
workbuddyStatus();
|
|
727
|
+
}
|
|
612
728
|
if (target === 'codex' || target === 'all') {
|
|
613
729
|
console.log('\n[Codex]');
|
|
614
730
|
if (!hasCodexCLI()) {
|
|
@@ -636,13 +752,16 @@ async function cmdDoctor() {
|
|
|
636
752
|
// Node.js
|
|
637
753
|
check('Node.js >= 20', process.versions.node.split('.')[0] >= 20, 'Run: nvm install 20 && nvm use 20');
|
|
638
754
|
|
|
639
|
-
// MCP server — check OpenCode
|
|
755
|
+
// MCP server — check OpenCode, Codex Desktop, CodeArts, and WorkBuddy paths
|
|
640
756
|
const opencodePluginDir = opencodePluginsDir();
|
|
641
757
|
const codexPluginDir = codexDesktopPluginsDir();
|
|
758
|
+
const workbuddyPluginDir = workbuddyPluginsDir();
|
|
642
759
|
const mcpOk = existsSync(join(opencodePluginDir, 'src', 'mcp-server.mjs'))
|
|
643
|
-
|| existsSync(join(codexPluginDir, 'src', 'mcp-server.mjs'))
|
|
760
|
+
|| existsSync(join(codexPluginDir, 'src', 'mcp-server.mjs'))
|
|
761
|
+
|| existsSync(join(workbuddyPluginDir, 'src', 'mcp-server.mjs'));
|
|
644
762
|
const mcpTarget = existsSync(join(opencodePluginDir, 'src', 'mcp-server.mjs')) ? 'OpenCode'
|
|
645
|
-
: existsSync(join(codexPluginDir, 'src', 'mcp-server.mjs')) ? 'Codex Desktop'
|
|
763
|
+
: existsSync(join(codexPluginDir, 'src', 'mcp-server.mjs')) ? 'Codex Desktop'
|
|
764
|
+
: existsSync(join(workbuddyPluginDir, 'src', 'mcp-server.mjs')) ? 'WorkBuddy' : '';
|
|
646
765
|
check('MCP server installed', mcpOk, 'Run: npx huaweicloud-devkit install');
|
|
647
766
|
|
|
648
767
|
if (mcpOk) {
|
|
@@ -650,10 +769,11 @@ async function cmdDoctor() {
|
|
|
650
769
|
}
|
|
651
770
|
|
|
652
771
|
const safetyOk = existsSync(join(opencodePluginDir, 'safety', 'policy.json'))
|
|
653
|
-
|| existsSync(join(codexPluginDir, 'safety', 'policy.json'))
|
|
772
|
+
|| existsSync(join(codexPluginDir, 'safety', 'policy.json'))
|
|
773
|
+
|| existsSync(join(workbuddyPluginDir, 'safety', 'policy.json'));
|
|
654
774
|
check('Safety policy installed', safetyOk, 'Run: npx huaweicloud-devkit install');
|
|
655
775
|
|
|
656
|
-
// MCP config — check OpenCode
|
|
776
|
+
// MCP config — check OpenCode, Codex Desktop, and WorkBuddy
|
|
657
777
|
let mcpConfigured = false;
|
|
658
778
|
let mcpCfgTarget = '';
|
|
659
779
|
const opencodeCfg = opencodeConfigFile();
|
|
@@ -670,6 +790,13 @@ async function cmdDoctor() {
|
|
|
670
790
|
if (cfg.mcp && cfg.mcp['huaweicloud-devkit']) { mcpConfigured = true; mcpCfgTarget = 'Codex Desktop'; }
|
|
671
791
|
} catch {}
|
|
672
792
|
}
|
|
793
|
+
const workbuddyCfg = workbuddyMcpConfigFile();
|
|
794
|
+
if (!mcpConfigured && existsSync(workbuddyCfg)) {
|
|
795
|
+
try {
|
|
796
|
+
const cfg = JSON.parse(readFileSync(workbuddyCfg, 'utf8'));
|
|
797
|
+
if (cfg.mcpServers && cfg.mcpServers['huaweicloud-devkit']) { mcpConfigured = true; mcpCfgTarget = 'WorkBuddy'; }
|
|
798
|
+
} catch {}
|
|
799
|
+
}
|
|
673
800
|
check('MCP configured', mcpConfigured, mcpCfgTarget ? `Found in ${mcpCfgTarget} config` : 'Run: npx huaweicloud-devkit install');
|
|
674
801
|
|
|
675
802
|
// hcloud CLI
|
|
@@ -699,36 +826,51 @@ async function cmdDoctor() {
|
|
|
699
826
|
}
|
|
700
827
|
|
|
701
828
|
// Skills
|
|
702
|
-
const skillsOptions = [opencodeSkillsDir(), codexDesktopSkillsDir(), codeartsSkillsDir()];
|
|
703
|
-
let skillCount = 0, skillsDir = '';
|
|
829
|
+
const skillsOptions = [opencodeSkillsDir(), codexDesktopSkillsDir(), codeartsSkillsDir(), workbuddySkillsDir()];
|
|
830
|
+
let skillCount = 0, skillsDir = '', missingSkills = [];
|
|
704
831
|
for (const dir of skillsOptions) {
|
|
705
832
|
if (!existsSync(dir)) continue;
|
|
706
|
-
const
|
|
707
|
-
.filter((d) => d.isDirectory() && d.name.startsWith('huawei'))
|
|
833
|
+
const entries = readdirSync(dir, { withFileTypes: true })
|
|
834
|
+
.filter((d) => d.isDirectory() && d.name.startsWith('huawei'));
|
|
835
|
+
const count = entries.length;
|
|
708
836
|
if (count > skillCount) { skillCount = count; skillsDir = dir; }
|
|
837
|
+
for (const d of entries) {
|
|
838
|
+
if (!existsSync(join(dir, d.name, 'SKILL.md'))) missingSkills.push(d.name);
|
|
839
|
+
}
|
|
709
840
|
}
|
|
710
841
|
const skillsOk = skillCount >= 6;
|
|
711
|
-
check(`Skills installed (${skillCount})`, skillsOk, 'Run: npx huaweicloud-devkit
|
|
842
|
+
check(`Skills installed (${skillCount})`, skillsOk, 'Run: npx huaweicloud-devkit install');
|
|
843
|
+
if (missingSkills.length > 0) {
|
|
844
|
+
console.log(` \x1b[33m[WARN]\x1b[0m ${missingSkills.length} skill(s) missing SKILL.md: ${missingSkills.join(', ')} — Run: npx huaweicloud-devkit install`);
|
|
845
|
+
warn++;
|
|
846
|
+
}
|
|
712
847
|
|
|
713
848
|
console.log(`\nResults: ${pass} pass, ${warn} warn, ${fail} fail`);
|
|
714
849
|
|
|
715
850
|
if (mcpConfigured && !hcloudOk) {
|
|
716
|
-
console.log('\n\x1b[33mMCP is configured but hcloud is not installed. Install hcloud then restart
|
|
851
|
+
console.log('\n\x1b[33mMCP is configured but hcloud is not installed. Install hcloud then restart your session.\x1b[0m');
|
|
717
852
|
}
|
|
718
853
|
if (fail > 0) {
|
|
719
|
-
console.log('\x1b[33mFix failures above, then restart your
|
|
854
|
+
console.log('\x1b[33mFix failures above, then restart your session.\x1b[0m');
|
|
720
855
|
}
|
|
721
856
|
if (fail === 0 && mcpConfigured) {
|
|
722
|
-
console.log('\n\x1b[32mAll checks passed.\x1b[0m Restart
|
|
857
|
+
console.log('\n\x1b[32mAll checks passed.\x1b[0m Restart your session, then describe your Huawei Cloud task');
|
|
723
858
|
}
|
|
724
859
|
|
|
725
|
-
// Detect "installed but not restarted"
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
860
|
+
// Detect "installed but not restarted" — check all supported agents
|
|
861
|
+
const installedMarkers = [
|
|
862
|
+
{ path: join(opencodePluginsDir(), '.installed'), name: 'OpenCode' },
|
|
863
|
+
{ path: join(workbuddyPluginsDir(), '.installed'), name: 'WorkBuddy' },
|
|
864
|
+
{ path: join(codeartsPluginsDir(), '.installed'), name: 'CodeArts' },
|
|
865
|
+
];
|
|
866
|
+
for (const marker of installedMarkers) {
|
|
867
|
+
if (existsSync(marker.path)) {
|
|
868
|
+
console.log(`\n\x1b[1m\x1b[31m╔══════════════════════════════════════════╗`);
|
|
869
|
+
console.log(`\x1b[1m\x1b[31m║ 请重启 ${marker.name}!MCP 工具尚未激活 ║`);
|
|
870
|
+
console.log(`\x1b[1m\x1b[31m║ 关闭当前会话 → 重新打开即可 ║`);
|
|
871
|
+
console.log(`\x1b[1m\x1b[31m╚══════════════════════════════════════════╝\x1b[0m`);
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
732
874
|
}
|
|
733
875
|
}
|
|
734
876
|
|
|
@@ -737,7 +879,9 @@ async function cmdUpdate() {
|
|
|
737
879
|
const target = parseTarget();
|
|
738
880
|
|
|
739
881
|
if (target === 'opencode' || target === 'all') {
|
|
740
|
-
if (!existsSync(join(opencodePluginsDir(), 'src', 'mcp-server.mjs'))
|
|
882
|
+
if (!existsSync(join(opencodePluginsDir(), 'src', 'mcp-server.mjs'))
|
|
883
|
+
&& !existsSync(join(workbuddyPluginsDir(), 'src', 'mcp-server.mjs'))
|
|
884
|
+
&& !codexStatus()) {
|
|
741
885
|
console.log('\x1b[33mNot installed. Use "install" command first.\x1b[0m');
|
|
742
886
|
return;
|
|
743
887
|
}
|
|
@@ -908,7 +1052,7 @@ async function main() {
|
|
|
908
1052
|
case '-h':
|
|
909
1053
|
default:
|
|
910
1054
|
console.log(BANNER);
|
|
911
|
-
console.log('Usage: npx huaweicloud-devkit <command> [--target <opencode|codex|codearts|all>]\n');
|
|
1055
|
+
console.log('Usage: npx huaweicloud-devkit <command> [--target <opencode|codex|codearts|workbuddy|all>]\n');
|
|
912
1056
|
console.log('Commands:');
|
|
913
1057
|
console.log(' install Install skills, MCP server, safety policy');
|
|
914
1058
|
console.log(' uninstall Remove installed files');
|
|
@@ -919,11 +1063,12 @@ async function main() {
|
|
|
919
1063
|
console.log(' install-hcloud Show KooCLI install commands for your OS');
|
|
920
1064
|
console.log(' help Show this help');
|
|
921
1065
|
console.log('\nOptions:');
|
|
922
|
-
console.log(' --target Target agent: opencode (default), codex, codearts, all');
|
|
1066
|
+
console.log(' --target Target agent: opencode (default), codex, codearts, workbuddy, all');
|
|
923
1067
|
console.log('\nExamples:');
|
|
924
1068
|
console.log(' npx huaweicloud-devkit install');
|
|
925
1069
|
console.log(' npx huaweicloud-devkit install --target codex');
|
|
926
1070
|
console.log(' npx huaweicloud-devkit install --target codearts');
|
|
1071
|
+
console.log(' npx huaweicloud-devkit install --target workbuddy');
|
|
927
1072
|
console.log(' npx huaweicloud-devkit install --target all');
|
|
928
1073
|
break;
|
|
929
1074
|
}
|
|
@@ -17,10 +17,15 @@ function codeartsSkillsDir() {
|
|
|
17
17
|
const home = homedir();
|
|
18
18
|
return join(home, '.codeartsdoer', 'skills');
|
|
19
19
|
}
|
|
20
|
+
function workbuddySkillsDir() {
|
|
21
|
+
const home = homedir();
|
|
22
|
+
return join(home, '.workbuddy', 'skills');
|
|
23
|
+
}
|
|
20
24
|
function resolveSkillsRoot() {
|
|
21
25
|
if (existsSync(SKILLS_ROOT_DEV)) return SKILLS_ROOT_DEV;
|
|
22
26
|
if (existsSync(codeartsSkillsDir())) return codeartsSkillsDir();
|
|
23
27
|
if (existsSync(opencodeSkillsDir())) return opencodeSkillsDir();
|
|
28
|
+
if (existsSync(workbuddySkillsDir())) return workbuddySkillsDir();
|
|
24
29
|
return SKILLS_ROOT_DEV;
|
|
25
30
|
}
|
|
26
31
|
const SKILLS_ROOT = resolveSkillsRoot();
|