huaweicloud-devkit 1.1.0-next.2 → 1.1.0-next.21
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 +64 -1
- package/README.zh-CN.md +63 -1
- package/package.json +3 -1
- package/plugins/huaweicloud-core/.claude-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.codex-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.cursor-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.hermes-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/hooks/huaweicloud-safety.py +46 -21
- package/plugins/huaweicloud-core/openclaw.plugin.json +1 -1
- package/plugins/huaweicloud-core/safety/rules/cloud-risk-rules.json +136 -24
- package/plugins/huaweicloud-core/skills/huawei-billing/SKILL.md +15 -14
- package/plugins/huaweicloud-core/skills/huawei-dew/SKILL.md +1 -1
- package/plugins/huaweicloud-core/skills/huawei-ecs/SKILL.md +5 -1
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/hc-activity.md +27 -0
- package/plugins/huaweicloud-core/skills/huawei-iam/SKILL.md +11 -11
- package/plugins/huaweicloud-core/skills/huawei-rds/SKILL.md +6 -5
- package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +596 -93
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/framework-commands.md +0 -1
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/nginx-templates.md +8 -4
- package/plugins/huaweicloud-core/skills/huawei-smn-dms/SKILL.md +19 -12
- package/plugins/huaweicloud-core/skills/huawei-voucher/SKILL.md +52 -0
- package/plugins/huaweicloud-core/skills/huawei-vpc/SKILL.md +26 -26
- package/plugins/huaweicloud-core/skills/huawei-vpc/references/network.md +12 -6
- package/plugins/huaweicloud-core/skills/huawei-waf-aad/SKILL.md +7 -4
- package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +7 -7
- package/plugins/huaweicloud-core/skills/huaweicloud-core/SKILL.md +2 -0
- package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +8 -0
- package/plugins/huaweicloud-core/src/auth/credentials.mjs +30 -1
- package/plugins/huaweicloud-core/src/auth/service.mjs +33 -0
- package/plugins/huaweicloud-core/src/detect-framework.mjs +25 -3
- package/plugins/huaweicloud-core/src/hcloud-cli.mjs +67 -5
- package/plugins/huaweicloud-core/src/mcp-server.mjs +23 -0
- package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +11 -3
- package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +436 -21
- package/plugins/huaweicloud-core/src/search-market.mjs +1 -0
- package/plugins/huaweicloud-core/src/setup-cli.mjs +605 -50
- package/plugins/huaweicloud-core/src/tools.mjs +193 -18
- package/plugins/huaweicloud-core/src/ws-exec/ws-exec-client.js +29 -8
|
@@ -50,7 +50,6 @@ These tools should be available in the sandbox image. Verify with the pre-flight
|
|
|
50
50
|
| curl | 8.x | Tool downloads, health checks |
|
|
51
51
|
| build-essential | - | Native module compilation |
|
|
52
52
|
| pnpm | 10.x | Monorepo / workspace installs |
|
|
53
|
-
| lsof | 4.95.x | Port conflict detection |
|
|
54
53
|
|
|
55
54
|
### Install on Demand
|
|
56
55
|
|
|
@@ -6,7 +6,7 @@ Nginx is the primary serving mechanism for web apps deployed to the sandbox. Pyt
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
sudo apt-get update -qq && sudo apt-get install -y -qq nginx 2>/dev/null || true
|
|
9
|
-
sudo mkdir -p /etc/nginx/
|
|
9
|
+
sudo mkdir -p /etc/nginx/conf.d
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
## Template 1: SPA (with try_files fallback)
|
|
@@ -14,7 +14,7 @@ sudo mkdir -p /etc/nginx/sites-enabled
|
|
|
14
14
|
Use for: Vite, CRA, Vue CLI, Angular, VitePress, Docusaurus, Taro H5, uni-app H5
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
sudo tee /etc/nginx/
|
|
17
|
+
sudo tee /etc/nginx/conf.d/app.conf > /dev/null << 'NGINX_EOF'
|
|
18
18
|
server {
|
|
19
19
|
listen <port>;
|
|
20
20
|
root /workspace/<project>/<outputDir>;
|
|
@@ -38,10 +38,11 @@ sudo nginx -s reload 2>/dev/null || sudo nginx
|
|
|
38
38
|
Use for: Next.js, Nuxt
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
sudo tee /etc/nginx/
|
|
41
|
+
sudo tee /etc/nginx/conf.d/app.conf > /dev/null << 'NGINX_EOF'
|
|
42
42
|
server {
|
|
43
43
|
listen <publicPort>;
|
|
44
44
|
server_name _;
|
|
45
|
+
large_client_header_buffers 4 32k;
|
|
45
46
|
|
|
46
47
|
location / {
|
|
47
48
|
proxy_pass http://127.0.0.1:<nodePort>;
|
|
@@ -54,6 +55,9 @@ server {
|
|
|
54
55
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
55
56
|
proxy_cache_bypass $http_upgrade;
|
|
56
57
|
proxy_read_timeout 60s;
|
|
58
|
+
proxy_buffer_size 128k;
|
|
59
|
+
proxy_buffers 4 256k;
|
|
60
|
+
proxy_busy_buffers_size 256k;
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
NGINX_EOF
|
|
@@ -65,7 +69,7 @@ sudo nginx -s reload 2>/dev/null || sudo nginx
|
|
|
65
69
|
Use for: Hugo, Hexo, plain static HTML
|
|
66
70
|
|
|
67
71
|
```bash
|
|
68
|
-
sudo tee /etc/nginx/
|
|
72
|
+
sudo tee /etc/nginx/conf.d/app.conf > /dev/null << 'NGINX_EOF'
|
|
69
73
|
server {
|
|
70
74
|
listen <port>;
|
|
71
75
|
root /workspace/<project>/<outputDir>;
|
|
@@ -8,7 +8,7 @@ version: 1
|
|
|
8
8
|
|
|
9
9
|
**STOP - Do not answer from general knowledge.** Follow the procedure below.
|
|
10
10
|
|
|
11
|
-
Always run `hcloud SMN <Operation> --help` or `hcloud
|
|
11
|
+
Always run `hcloud SMN <Operation> --help`, `hcloud Kafka <Operation> --help`, `hcloud RabbitMQ <Operation> --help`, or `hcloud RocketMQ <Operation> --help` before constructing commands.
|
|
12
12
|
|
|
13
13
|
## Overview
|
|
14
14
|
|
|
@@ -38,21 +38,28 @@ Domain expertise for SMN (Simple Message Notification) and DMS (Distributed Mess
|
|
|
38
38
|
|
|
39
39
|
## DMS
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
> **DMS 是产品统一品牌**,涵盖 Kafka、RabbitMQ、RocketMQ 三种引擎。在 KooCLI 中,三种引擎被拆分为独立服务,**不存在 `hcloud DMS` 命令**。
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
|
|
|
43
|
+
### Engine → KooCLI Service Mapping
|
|
44
|
+
|
|
45
|
+
| Engine | KooCLI Service | Description |
|
|
46
|
+
| -------- | ----------------- | -------------------- |
|
|
47
|
+
| Kafka | `hcloud Kafka` | 高吞吐分布式消息队列 |
|
|
48
|
+
| RabbitMQ | `hcloud RabbitMQ` | AMQP 消息代理 |
|
|
49
|
+
| RocketMQ | `hcloud RocketMQ` | 低延迟金融级消息队列 |
|
|
48
50
|
|
|
49
51
|
### Common Workflows
|
|
50
52
|
|
|
51
|
-
| Task
|
|
52
|
-
|
|
|
53
|
-
| List instances
|
|
54
|
-
|
|
|
55
|
-
| List
|
|
53
|
+
| Task | Service | Operation |
|
|
54
|
+
| ------------------------ | ---------- | ------------------------------------------------------------------ |
|
|
55
|
+
| List Kafka instances | `Kafka` | `ListInstances --cli-region=<r> --project_id=<p>` |
|
|
56
|
+
| List RabbitMQ instances | `RabbitMQ` | `ListInstancesDetails --cli-region=<r> --project_id=<p>` |
|
|
57
|
+
| List RocketMQ instances | `RocketMQ` | `ListInstances --cli-region=<r> --project_id=<p>` |
|
|
58
|
+
| Create Kafka instance | `Kafka` | `CreatePostPaidKafkaInstance --cli-region=<r> --project_id=<p>` |
|
|
59
|
+
| Create RabbitMQ instance | `RabbitMQ` | `CreatePostPaidInstanceByEngine --cli-region=<r> --project_id=<p>` |
|
|
60
|
+
| Create RocketMQ instance | `RocketMQ` | `CreateInstanceByEngine --cli-region=<r> --project_id=<p>` |
|
|
61
|
+
| List Kafka topics | `Kafka` | `ListInstanceTopics --cli-region=<r> --project_id=<p>` |
|
|
62
|
+
| List RocketMQ topics | `RocketMQ` | `ListRocketInstanceTopics --cli-region=<r> --project_id=<p>` |
|
|
56
63
|
|
|
57
64
|
Discover exact parameters with `--help` before executing any command.
|
|
58
65
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: huawei-voucher
|
|
3
|
+
description: '查询和领取华为云激励代金券(一人一次)。当用户询问插件能力、首次使用,或提到"领券/代金券/优惠券/激励金/领取"等话题时,先查询领取状态:未领取(claimed=false)则主动提示可领取,已领取(claimed=true)则不打扰。Triggers: voucher, coupon, incentive, 领券, 代金券, 优惠券, 激励金, 领取. NOT for: 账单/费用查询(用 huawei-billing)。'
|
|
4
|
+
version: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 华为云激励代金券
|
|
8
|
+
|
|
9
|
+
## 主动提示准则(核心)
|
|
10
|
+
|
|
11
|
+
此能力仅在用户尚未领取时才有价值,需避免已领取用户被反复打扰:
|
|
12
|
+
|
|
13
|
+
1. 当用户**询问插件能力 / 首次使用 / 提到福利领取类话题**时,先调用 `huaweicloud_voucher_status` 查询领取状态。
|
|
14
|
+
2. 若 `claimed=false` → 主动告知"可领取华为云代金券(一人一次)",并询问是否现在领取。
|
|
15
|
+
3. 若 `claimed=true` → 静默处理,不再提及代金券,不打扰用户。
|
|
16
|
+
|
|
17
|
+
## 流程
|
|
18
|
+
|
|
19
|
+
### 1. 查询状态
|
|
20
|
+
|
|
21
|
+
调用 `huaweicloud_voucher_status`(生产环境无需 `domain_id`,测试环境需传 `domain_id`)。
|
|
22
|
+
|
|
23
|
+
返回 `{ claimed, message }`:
|
|
24
|
+
|
|
25
|
+
- `claimed=true` + `message="已领取"` → 已领取,告知结果即可,不再引导
|
|
26
|
+
- `claimed=false` + `message="未领取"` → 未领取,可引导领取
|
|
27
|
+
|
|
28
|
+
### 2. 领取代金券
|
|
29
|
+
|
|
30
|
+
调用 `huaweicloud_voucher_claim`(生产环境无需 `domain_id`)。
|
|
31
|
+
|
|
32
|
+
返回 `{ claimed, voucherId, amount, message }`。
|
|
33
|
+
|
|
34
|
+
### 3. 结果解读(错误码 UX)
|
|
35
|
+
|
|
36
|
+
| 返回 message 关键特征 | 含义 | 对用户表述 |
|
|
37
|
+
| -------------------------------------------- | --------------------------- | -------------------- |
|
|
38
|
+
| `领取成功` | 发券成功 | 告知券已到账 |
|
|
39
|
+
| `已领取过` / `已领取` | 该账号已领过 | 告知已领取,不打扰 |
|
|
40
|
+
| `本月代金券总额度已用完,所有账号均无法领取` | 全局额度用尽(HD.60630042) | 告知下月再试 |
|
|
41
|
+
| `请先完成实名认证` | 账号未实名(HD.60630022) | 引导去控制台实名认证 |
|
|
42
|
+
| `发券失败: <原文>` | 其他错误 | 原样转达,不展开 |
|
|
43
|
+
|
|
44
|
+
## 环境注意
|
|
45
|
+
|
|
46
|
+
- 生产环境:`voucher_status` / `voucher_claim` 无需传 `domain_id`,后端从 IAM 自动解析账号。
|
|
47
|
+
- 测试环境:需传 `domain_id`(华为云账号 ID);未传时返回 `测试环境需提供 domain_id`,此时可用 `hcloud IAM KeystoneListAuthDomains` 查询账号 ID 后补传。
|
|
48
|
+
|
|
49
|
+
## 注意事项
|
|
50
|
+
|
|
51
|
+
- 每个账号(domain_id)仅可领取一次,重复调用返回已领取。
|
|
52
|
+
- 领取结果以激励服务返回为准,不要凭本地认知猜测。
|
|
@@ -18,19 +18,19 @@ Domain expertise for Huawei Cloud Virtual Private Cloud (VPC). Covers VPC/subnet
|
|
|
18
18
|
|
|
19
19
|
## Critical Warnings
|
|
20
20
|
|
|
21
|
-
| Trap | Why
|
|
22
|
-
| ------------------------------------- |
|
|
23
|
-
| VPC CIDR cannot change | Once set, VPC CIDR block is immutable
|
|
24
|
-
| Security group stateful | SG rules are stateful. Return traffic auto-allowed
|
|
25
|
-
| Network ACL stateless | ACL rules must allow both inbound AND outbound
|
|
26
|
-
| EIP bills when idle | Unbound EIP still charges. Release when unused
|
|
27
|
-
| Subnet AZ binding | Subnet tied to single AZ. Cross-AZ needs multiple subnets
|
|
28
|
-
| EIP PER type needs `--bandwidth.name` | PER bandwidth requires explicit name; `--help` marks it optional but it's required
|
|
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
|
-
| **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. Common DNS
|
|
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`
|
|
21
|
+
| Trap | Why |
|
|
22
|
+
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
23
|
+
| VPC CIDR cannot change | Once set, VPC CIDR block is immutable |
|
|
24
|
+
| Security group stateful | SG rules are stateful. Return traffic auto-allowed |
|
|
25
|
+
| Network ACL stateless | ACL rules must allow both inbound AND outbound |
|
|
26
|
+
| EIP bills when idle | Unbound EIP still charges. Release when unused |
|
|
27
|
+
| Subnet AZ binding | Subnet tied to single AZ. Cross-AZ needs multiple subnets |
|
|
28
|
+
| EIP PER type needs `--bandwidth.name` | PER bandwidth requires explicit name; `--help` marks it optional but it's required |
|
|
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
|
+
| **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. Common DNS (primary / secondary): cn-north-4 (100.125.1.250 / 100.125.129.250), cn-north-1 (100.125.1.250 / 100.125.21.250), cn-east-3 (100.125.1.250 / 100.125.64.250), cn-south-1 (100.125.1.250 / 100.125.136.29), ap-southeast-3 (100.125.1.250 / 100.125.128.250). Authoritative per region: `hcloud DNS ListNameServers --type=private --region=<r>` |
|
|
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` |
|
|
34
34
|
|
|
35
35
|
## Common Workflows
|
|
36
36
|
|
|
@@ -43,25 +43,25 @@ Domain expertise for Huawei Cloud Virtual Private Cloud (VPC). Covers VPC/subnet
|
|
|
43
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 |
|
|
44
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 |
|
|
45
45
|
| Bind EIP to ECS | hcloud EIP AssociatePublicips --publicip_id=<id> --publicip.associate_instance_id=<port-id> --publicip.associate_instance_type=PORT | Get port ID from `hcloud ECS ListServersDetails --server_id=<id>` → `OS-EXT-IPS:port_id` |
|
|
46
|
-
| Unbind EIP | hcloud EIP
|
|
46
|
+
| Unbind EIP | hcloud EIP DisassociatePublicips --publicip_id=<id> | references/eip.md |
|
|
47
47
|
| Delete EIP | hcloud EIP DeletePublicip --publicip_id=<id> | references/eip.md |
|
|
48
48
|
| List EIPs | hcloud EIP ListPublicips | |
|
|
49
49
|
| NAT gateway | hcloud NAT CreateNatGateway --nat.name=<name> --nat.spec=<spec> --router_id=<vpc-id> --internal_network_id=<subnet-id> | Run `hcloud NAT CreateNatGateway --help` for available spec values |
|
|
50
50
|
|
|
51
51
|
## Troubleshooting
|
|
52
52
|
|
|
53
|
-
| Error | Root Cause -> Fix
|
|
54
|
-
| -------------------------------------------------- |
|
|
55
|
-
| Cannot reach instance | SG missing rule or no EIP -> Add SG rule / Bind EIP
|
|
56
|
-
| Subnet CIDR conflict | Overlapping with existing subnets -> Choose non-overlapping CIDR
|
|
57
|
-
| NAT gateway no internet | Route table missing default route -> Add 0.0.0.0/0 via NAT
|
|
58
|
-
| EIP quota exceeded | Check actual quota: `hcloud EIP ListPublicips --cli-region=<r>` to see current usage. Default varies by account (typically 5-10)
|
|
59
|
-
| EIP.7905 | Run `hcloud EIP ListPublicips --cli-region=<r>` first to check current usage
|
|
60
|
-
| VPC.0301: Bandwidth name invalid | PER type requires `--bandwidth.name`, even though `--help` marks it optional
|
|
61
|
-
| EIP has no public IP after binding | May need AddIngressEipV2 for ELB-type resources (see huawei-apig)
|
|
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
|
|
63
|
-
| VPC.0209: Subnet still used | Subnet has dependent resources (ECS/RDS) — delete instances first, then subnet
|
|
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
|
|
53
|
+
| Error | Root Cause -> Fix |
|
|
54
|
+
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
55
|
+
| Cannot reach instance | SG missing rule or no EIP -> Add SG rule / Bind EIP |
|
|
56
|
+
| Subnet CIDR conflict | Overlapping with existing subnets -> Choose non-overlapping CIDR |
|
|
57
|
+
| NAT gateway no internet | Route table missing default route -> Add 0.0.0.0/0 via NAT |
|
|
58
|
+
| EIP quota exceeded | Check actual quota: `hcloud EIP ListPublicips --cli-region=<r>` to see current usage. Default varies by account (typically 5-10) |
|
|
59
|
+
| EIP.7905 | Run `hcloud EIP ListPublicips --cli-region=<r>` first to check current usage |
|
|
60
|
+
| VPC.0301: Bandwidth name invalid | PER type requires `--bandwidth.name`, even though `--help` marks it optional |
|
|
61
|
+
| EIP has no public IP after binding | May need AddIngressEipV2 for ELB-type resources (see huawei-apig) |
|
|
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 DNS ListNameServers --type=private --region=<r>` |
|
|
63
|
+
| VPC.0209: Subnet still used | Subnet has dependent resources (ECS/RDS) — delete instances first, then subnet |
|
|
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 |
|
|
65
65
|
|
|
66
66
|
## Security Considerations
|
|
67
67
|
|
|
@@ -6,11 +6,17 @@ Subnets without DNS configuration will fail cloud-init. Use these DNS addresses:
|
|
|
6
6
|
|
|
7
7
|
| Region | Primary DNS | Secondary DNS |
|
|
8
8
|
| -------------- | ------------- | --------------- |
|
|
9
|
-
| cn-north-1 | 100.125.1.250 | 100.125.
|
|
9
|
+
| cn-north-1 | 100.125.1.250 | 100.125.21.250 |
|
|
10
10
|
| cn-north-4 | 100.125.1.250 | 100.125.129.250 |
|
|
11
|
-
| cn-east-3 | 100.125.1.250 | 100.125.
|
|
12
|
-
| cn-south-1 | 100.125.1.250 | 100.125.
|
|
13
|
-
| ap-southeast-3 | 100.125.1.250 | 100.125.
|
|
11
|
+
| cn-east-3 | 100.125.1.250 | 100.125.64.250 |
|
|
12
|
+
| cn-south-1 | 100.125.1.250 | 100.125.136.29 |
|
|
13
|
+
| ap-southeast-3 | 100.125.1.250 | 100.125.128.250 |
|
|
14
|
+
|
|
15
|
+
Get the authoritative values for any region at runtime (preferred over this table):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
hcloud DNS ListNameServers --type=private --region=<region>
|
|
19
|
+
```
|
|
14
20
|
|
|
15
21
|
**Subnet create with DNS**:
|
|
16
22
|
|
|
@@ -21,8 +27,8 @@ hcloud VPC CreateSubnet \
|
|
|
21
27
|
--subnet.cidr=10.50.1.0/24 \
|
|
22
28
|
--subnet.gateway_ip=10.50.1.1 \
|
|
23
29
|
--subnet.availability_zone=<az> \
|
|
24
|
-
--subnet.dnsList.1
|
|
25
|
-
--subnet.dnsList.2
|
|
30
|
+
--subnet.dnsList.1=<dns1> \
|
|
31
|
+
--subnet.dnsList.2=<dns2>
|
|
26
32
|
```
|
|
27
33
|
|
|
28
34
|
## Nested Prefix Summary
|
|
@@ -29,8 +29,8 @@ Domain expertise for WAF and Anti-DDoS. Covers WAF policy/rules, AAD protection,
|
|
|
29
29
|
|
|
30
30
|
| Task | Operation |
|
|
31
31
|
| ------------------- | --------------------------------------------------------------- |
|
|
32
|
-
| List WAF instances | `
|
|
33
|
-
| List policies | `
|
|
32
|
+
| List WAF instances | `ListCompositeHosts --cli-region=<r> --project_id=<p>` |
|
|
33
|
+
| List policies | `ListPolicy --cli-region=<r> --project_id=<p>` |
|
|
34
34
|
| Create custom rule | `BatchCreateCustomRule --cli-region=<r> --project_id=<p>` |
|
|
35
35
|
| Create IP blacklist | `BatchCreateWhiteblackipRule --cli-region=<r> --project_id=<p>` |
|
|
36
36
|
| Create CC rule | `BatchCreateCcRule --cli-region=<r> --project_id=<p>` |
|
|
@@ -39,8 +39,11 @@ Domain expertise for WAF and Anti-DDoS. Covers WAF policy/rules, AAD protection,
|
|
|
39
39
|
### AAD
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
|
|
43
|
-
hcloud AAD
|
|
42
|
+
# List AAD instances (requires --cli-region=cn-north-4 or ap-southeast-1)
|
|
43
|
+
hcloud AAD ListInstance --cli-region=<r> --project_id=<p>
|
|
44
|
+
|
|
45
|
+
# List DDoS attack events
|
|
46
|
+
hcloud AAD ListDDoSAttackEvent --cli-region=<r> --project_id=<p>
|
|
44
47
|
```
|
|
45
48
|
|
|
46
49
|
## Troubleshooting
|
|
@@ -125,13 +125,13 @@ hcloud <Service> <Op> --cli-debug=true
|
|
|
125
125
|
|
|
126
126
|
Credentials are resolved in this order (highest priority first):
|
|
127
127
|
|
|
128
|
-
| Priority | Source
|
|
129
|
-
| -------- |
|
|
130
|
-
| 1 | Runtime credentials
|
|
131
|
-
| 2 | Environment variables
|
|
132
|
-
| 3 | CodeArts
|
|
133
|
-
| 4 | Global config file
|
|
134
|
-
| 5 | KooCLI profile
|
|
128
|
+
| Priority | Source | Mechanism | Persistence |
|
|
129
|
+
| -------- | ------------------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------- |
|
|
130
|
+
| 1 | Runtime credentials | `huaweicloud_auth_init` tool | Memory (cleared on MCP restart) |
|
|
131
|
+
| 2 | Environment variables | `HW_ACCESS_KEY` / `HW_SECRET_KEY` | MCP process lifetime |
|
|
132
|
+
| 3 | CodeArts / CodeArts Work | `.codeartsdoer/mcp/mcp_settings.json` (project → user) or `.codeartswork/mcp/mcp_settings.json` (user) | File |
|
|
133
|
+
| 4 | Global config file | `~/.config/huaweicloud/credentials.json` | Permanent |
|
|
134
|
+
| 5 | KooCLI profile | `~/.hcloud/config.json` (KooCLI only) | Permanent |
|
|
135
135
|
|
|
136
136
|
When switching accounts within the same Agent session, use `huaweicloud_auth_init` to set runtime credentials. This overrides all other sources for the current MCP process.
|
|
137
137
|
|
|
@@ -43,6 +43,7 @@ Do not rely on training data for facts. Huawei Cloud services, pricing, quotas,
|
|
|
43
43
|
| troubleshoot | Troubleshooting Routing | error, bug, failed, AccessDenied, quota | Handoff to huaweicloud-troubleshooting |
|
|
44
44
|
| api-sdk | API/SDK Routing | API call, SDK, REST, integration, code example | Handoff to huaweicloud-api-and-sdk |
|
|
45
45
|
| report-issue | Issue Reporting | wrong service, you picked wrong, incorrect | Read references/report-issue.md |
|
|
46
|
+
| voucher | Voucher Routing | 领券, 代金券, 优惠券, 激励金, 领取, voucher, coupon, incentive | Handoff to huawei-voucher |
|
|
46
47
|
|
|
47
48
|
## Service Map
|
|
48
49
|
|
|
@@ -70,6 +71,7 @@ Do not rely on training data for facts. Huawei Cloud services, pricing, quotas,
|
|
|
70
71
|
| CI/CD pipeline | CloudDeploy | huawei-deployment |
|
|
71
72
|
| Temporary runtime / web app preview | Sandbox (DevStation) | huawei-sandbox |
|
|
72
73
|
| Getting started | Account setup | huaweicloud-cli-and-auth |
|
|
74
|
+
| Incentive voucher | Voucher | huawei-voucher |
|
|
73
75
|
|
|
74
76
|
**Web app scenario layering**: for "deploy a web app", prefer `huawei-sandbox` for free/quick try (hello world, prototype, demo, temporary preview — temporary runtime + public URL, ~8h validity, zero billed resources); route to `huawei-functiongraph` / `huawei-ecs` (or `huawei-cce`) for production / long-term / custom-domain / high-availability hosting.
|
|
75
77
|
|
|
@@ -9,6 +9,7 @@ export const SUPPORTED_AGENT_TARGETS = [
|
|
|
9
9
|
'codex',
|
|
10
10
|
'codex-desktop',
|
|
11
11
|
'codearts',
|
|
12
|
+
'codearts-work',
|
|
12
13
|
'workbuddy',
|
|
13
14
|
'dsh',
|
|
14
15
|
'officeace',
|
|
@@ -78,6 +79,12 @@ function codeartsRegistered() {
|
|
|
78
79
|
});
|
|
79
80
|
}
|
|
80
81
|
|
|
82
|
+
function codeartsWorkRegistered() {
|
|
83
|
+
const path = join(baseHome(), '.codeartswork', 'mcp', 'mcp_settings.json');
|
|
84
|
+
const cfg = readJsonSafe(path);
|
|
85
|
+
return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
|
|
86
|
+
}
|
|
87
|
+
|
|
81
88
|
function workbuddyRegistered() {
|
|
82
89
|
const cfg = readJsonSafe(join(baseHome(), '.workbuddy', 'mcp.json'));
|
|
83
90
|
return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
|
|
@@ -208,6 +215,7 @@ export function getAgentRegistrationStatuses(target = 'all') {
|
|
|
208
215
|
if (agent === 'codex-desktop') configured = codexDesktopRegistered();
|
|
209
216
|
if (agent === 'codex') configured = codexCliRegistered();
|
|
210
217
|
if (agent === 'codearts') configured = codeartsRegistered();
|
|
218
|
+
if (agent === 'codearts-work') configured = codeartsWorkRegistered();
|
|
211
219
|
if (agent === 'workbuddy') configured = workbuddyRegistered();
|
|
212
220
|
if (agent === 'dsh') configured = dshRegistered();
|
|
213
221
|
if (agent === 'officeace') configured = officeaceRegistered();
|
|
@@ -123,7 +123,11 @@ export function getParentCwd() {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function isCodeArtsContext() {
|
|
126
|
-
return
|
|
126
|
+
return (
|
|
127
|
+
existsSync(join(process.cwd(), '.codeartsdoer')) ||
|
|
128
|
+
existsSync(join(homedir(), '.codeartsdoer')) ||
|
|
129
|
+
existsSync(join(homedir(), '.codeartswork'))
|
|
130
|
+
);
|
|
127
131
|
}
|
|
128
132
|
|
|
129
133
|
function readCodeArtsCredentials() {
|
|
@@ -154,6 +158,31 @@ function readCodeArtsCredentials() {
|
|
|
154
158
|
}
|
|
155
159
|
}
|
|
156
160
|
|
|
161
|
+
// CodeArts Work — user-level only
|
|
162
|
+
{
|
|
163
|
+
const path = join(homedir(), '.codeartswork', 'mcp', 'mcp_settings.json');
|
|
164
|
+
try {
|
|
165
|
+
if (existsSync(path)) {
|
|
166
|
+
const config = JSON.parse(readFileSync(path, 'utf8'));
|
|
167
|
+
const server = config?.mcpServers?.['huaweicloud-devkit'];
|
|
168
|
+
if (server?.env) {
|
|
169
|
+
const ak = server.env.HW_ACCESS_KEY;
|
|
170
|
+
const sk = server.env.HW_SECRET_KEY;
|
|
171
|
+
if (ak && sk) {
|
|
172
|
+
return {
|
|
173
|
+
ak,
|
|
174
|
+
sk,
|
|
175
|
+
securityToken: server.env.HW_SECURITY_TOKEN || '',
|
|
176
|
+
region: server.env.HW_REGION || server.env.HUAWEICLOUD_REGION || '',
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
} catch {
|
|
182
|
+
// mcp_settings.json missing or invalid — skip
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
157
186
|
return null;
|
|
158
187
|
}
|
|
159
188
|
|
|
@@ -54,9 +54,42 @@ export function syncAuth(target = 'all') {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
let hcloud = { ok: false, message: 'KooCLI not installed' };
|
|
58
|
+
if (hcloudInstalled()) {
|
|
59
|
+
const bin = process.env.HCLOUD_BIN || 'hcloud';
|
|
60
|
+
const r = spawnSync(
|
|
61
|
+
bin,
|
|
62
|
+
[
|
|
63
|
+
'configure',
|
|
64
|
+
'set',
|
|
65
|
+
`--cli-access-key=${credentials.ak}`,
|
|
66
|
+
`--cli-secret-key=${credentials.sk}`,
|
|
67
|
+
`--cli-region=${credentials.region || ''}`,
|
|
68
|
+
],
|
|
69
|
+
{
|
|
70
|
+
shell: false,
|
|
71
|
+
windowsHide: true,
|
|
72
|
+
stdio: 'pipe',
|
|
73
|
+
timeout: 30000,
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
if (r.status === 0) {
|
|
77
|
+
hcloud = { ok: true, message: 'KooCLI config synced' };
|
|
78
|
+
} else {
|
|
79
|
+
hcloud = {
|
|
80
|
+
ok: false,
|
|
81
|
+
message: 'KooCLI config sync failed',
|
|
82
|
+
error: String(r.stderr || '')
|
|
83
|
+
.trim()
|
|
84
|
+
.slice(0, 240),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
57
89
|
return {
|
|
58
90
|
ok: true,
|
|
59
91
|
obs: { configured: true, path: obs.path, endpoint: obs.endpoint },
|
|
92
|
+
hcloud,
|
|
60
93
|
credentialsConfigured: true,
|
|
61
94
|
agents: getAgentRegistrationStatuses(target).agents,
|
|
62
95
|
note: 'OBS credentials were synced from the global credential vault. Agent MCP registration is managed by "npx huaweicloud-devkit install --target <agent>".',
|
|
@@ -157,10 +157,13 @@ function readPkg(projectPath) {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
function detectPackageManager(projectPath) {
|
|
160
|
+
function detectPackageManager(projectPath, pkg) {
|
|
161
161
|
if (existsSync(join(projectPath, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
162
162
|
if (existsSync(join(projectPath, 'yarn.lock'))) return 'yarn';
|
|
163
163
|
if (existsSync(join(projectPath, 'package-lock.json'))) return 'npm';
|
|
164
|
+
if (existsSync(join(projectPath, 'bun.lockb'))) return 'bun';
|
|
165
|
+
const declared = (pkg?.packageManager || '').split('@')[0];
|
|
166
|
+
if (declared && ['pnpm', 'yarn', 'npm', 'bun'].includes(declared)) return declared;
|
|
164
167
|
return 'npm';
|
|
165
168
|
}
|
|
166
169
|
|
|
@@ -234,10 +237,24 @@ function frameworkResult(fw, pm, projectPath) {
|
|
|
234
237
|
return patchCommands({ ...fw, packageManager: pm, rootDir: projectPath }, pm);
|
|
235
238
|
}
|
|
236
239
|
|
|
240
|
+
function readVitepressOutDir(projectPath) {
|
|
241
|
+
const configFiles = ['config.mts', 'config.ts', 'config.mjs', 'config.js'];
|
|
242
|
+
for (const cf of configFiles) {
|
|
243
|
+
const configPath = join(projectPath, '.vitepress', cf);
|
|
244
|
+
if (!existsSync(configPath)) continue;
|
|
245
|
+
try {
|
|
246
|
+
const content = readFileSync(configPath, 'utf8');
|
|
247
|
+
const match = content.match(/outDir\s*:\s*['"]([^'"]+)['"]/);
|
|
248
|
+
if (match) return match[1];
|
|
249
|
+
} catch {}
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
237
254
|
export function detectFramework(projectPath) {
|
|
238
255
|
const pkg = readPkg(projectPath);
|
|
239
256
|
const deps = collectDeps(pkg);
|
|
240
|
-
const pm = detectPackageManager(projectPath);
|
|
257
|
+
const pm = detectPackageManager(projectPath, pkg);
|
|
241
258
|
|
|
242
259
|
if (
|
|
243
260
|
existsSync(join(projectPath, 'pnpm-workspace.yaml')) ||
|
|
@@ -287,7 +304,12 @@ export function detectFramework(projectPath) {
|
|
|
287
304
|
}
|
|
288
305
|
|
|
289
306
|
if (existsSync(join(projectPath, '.vitepress'))) {
|
|
290
|
-
|
|
307
|
+
const outDir = readVitepressOutDir(projectPath);
|
|
308
|
+
return frameworkResult(
|
|
309
|
+
outDir ? { ...FRAMEWORKS.vitepress, outputDir: outDir } : FRAMEWORKS.vitepress,
|
|
310
|
+
pm,
|
|
311
|
+
projectPath,
|
|
312
|
+
);
|
|
291
313
|
}
|
|
292
314
|
|
|
293
315
|
if (
|