huaweicloud-devkit 1.1.0-next.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +27 -1
  2. package/README.zh-CN.md +26 -1
  3. package/package.json +3 -1
  4. package/plugins/huaweicloud-core/.claude-plugin/plugin.json +1 -1
  5. package/plugins/huaweicloud-core/.codex-plugin/plugin.json +1 -1
  6. package/plugins/huaweicloud-core/.cursor-plugin/plugin.json +1 -1
  7. package/plugins/huaweicloud-core/.hermes-plugin/plugin.json +1 -1
  8. package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +1 -1
  9. package/plugins/huaweicloud-core/hooks/huaweicloud-safety.py +29 -12
  10. package/plugins/huaweicloud-core/openclaw.plugin.json +1 -1
  11. package/plugins/huaweicloud-core/safety/rules/cloud-risk-rules.json +136 -24
  12. package/plugins/huaweicloud-core/skills/huawei-billing/SKILL.md +15 -14
  13. package/plugins/huaweicloud-core/skills/huawei-dew/SKILL.md +1 -1
  14. package/plugins/huaweicloud-core/skills/huawei-ecs/SKILL.md +5 -1
  15. package/plugins/huaweicloud-core/skills/huawei-ecs/references/hc-activity.md +27 -0
  16. package/plugins/huaweicloud-core/skills/huawei-iam/SKILL.md +11 -11
  17. package/plugins/huaweicloud-core/skills/huawei-rds/SKILL.md +6 -5
  18. package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +71 -7
  19. package/plugins/huaweicloud-core/skills/huawei-sandbox/references/nginx-templates.md +4 -0
  20. package/plugins/huaweicloud-core/skills/huawei-smn-dms/SKILL.md +19 -12
  21. package/plugins/huaweicloud-core/skills/huawei-vpc/SKILL.md +26 -26
  22. package/plugins/huaweicloud-core/skills/huawei-vpc/references/network.md +12 -6
  23. package/plugins/huaweicloud-core/skills/huawei-waf-aad/SKILL.md +7 -4
  24. package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +7 -7
  25. package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +14 -0
  26. package/plugins/huaweicloud-core/src/auth/credentials.mjs +30 -1
  27. package/plugins/huaweicloud-core/src/auth/service.mjs +33 -0
  28. package/plugins/huaweicloud-core/src/detect-framework.mjs +25 -3
  29. package/plugins/huaweicloud-core/src/hcloud-cli.mjs +67 -5
  30. package/plugins/huaweicloud-core/src/mcp-server.mjs +23 -0
  31. package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +11 -3
  32. package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +118 -23
  33. package/plugins/huaweicloud-core/src/search-market.mjs +1 -0
  34. package/plugins/huaweicloud-core/src/setup-cli.mjs +491 -64
  35. package/plugins/huaweicloud-core/src/tools.mjs +37 -15
@@ -40,7 +40,7 @@ hcloud RDS <Operation> --cli-region=<region> [--key=value ...]
40
40
  | Automated backups use OBS | Backup storage incurs separate charges. Set retention period explicitly |
41
41
  | Storage auto-scaling off by default | Enable before storage runs out or instance goes read-only |
42
42
  | `--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+ |
43
- | Volume type must match flavor | General→CLOUDSSD; Dedicated→CLOUDSSD\|ESSD; ARM→ULTRAHIGH |
43
+ | Volume type must match flavor | General→CLOUDSSD; Dedicated→CLOUDSSD\|ESSD; ARM→CLOUDSSD |
44
44
  | Flavor not in region | Always `ListFlavors` first. Spec codes vary by region |
45
45
  | `database_name` is case-sensitive | Use `MySQL` / `PostgreSQL` / `SQLServer` / `MariaDB` — NOT lower-case `mysql` |
46
46
  | 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'` |
@@ -55,7 +55,7 @@ hcloud RDS <Operation> --cli-region=<region> [--key=value ...]
55
55
  hcloud RDS ListInstances --cli-region=<r>
56
56
  hcloud RDS ListFlavors --database_name=<engine> --cli-region=<r>
57
57
  hcloud RDS ListDatastores --database_name=<engine> --cli-region=<r>
58
- hcloud RDS ListEngineFlavors --instance_id=<id> --cli-region=<r>
58
+ hcloud RDS ListEngineFlavors --instance_id=<id> --availability_zone_ids=<az> --ha_mode=<mode> --cli-region=<r>
59
59
  ```
60
60
 
61
61
  ### Create Instance
@@ -109,7 +109,7 @@ hcloud RDS CreateInstance --cli-region=<r> \
109
109
  | `--name` | Yes | Instance name |
110
110
  | `--datastore` | Yes | `--datastore.type=<engine> --datastore.version=<version>` |
111
111
  | `--flavor_ref` | Yes | From `ListFlavors` output |
112
- | `--volume` | Yes | Type matching: General→CLOUDSSD, Dedicated→CLOUDSSD\|ESSD, ARM→ULTRAHIGH |
112
+ | `--volume` | Yes | Type matching: General→CLOUDSSD, Dedicated→CLOUDSSD\|ESSD, ARM→CLOUDSSD |
113
113
  | `--vpc_id` | Yes | Must exist in target region |
114
114
  | `--subnet_id` | Yes | Must exist in target region |
115
115
  | `--security_group_id` | Yes | Must have DB port open |
@@ -150,7 +150,8 @@ hcloud RDS CreateRestoreInstance --instance_id=<id> --backup_id=<id> --name=<new
150
150
  ## Read Replicas
151
151
 
152
152
  ```bash
153
- hcloud RDS CreateReadReplica --replica_of_id=<primary-id> --name=<name> --flavor_ref=<id> --volume.type=<vol-type> --volume.size=<size> --cli-region=<r>
153
+ # Create a read replica via CreateInstance with --replica_of_id
154
+ hcloud RDS CreateInstance --replica_of_id=<primary-id> --name=<name> --flavor_ref=<id> --volume.type=<vol-type> --volume.size=<size> --cli-region=<r>
154
155
  ```
155
156
 
156
157
  ## Fault Diagnosis
@@ -159,7 +160,7 @@ hcloud RDS CreateReadReplica --replica_of_id=<primary-id> --name=<name> --flavor
159
160
  hcloud RDS ListErrorLogs --instance_id=<id> --start_date=2024-01-01T00:00:00Z --end_date=2024-01-31T23:59:59Z --cli-region=<r>
160
161
  hcloud RDS ListSlowLogs --instance_id=<id> --start_date=... --end_date=... --cli-region=<r>
161
162
  hcloud RDS ShowReplicationStatus --instance_id=<id> --cli-region=<r>
162
- hcloud RDS ListInstanceDiagnosis --cli-region=<r>
163
+ hcloud RDS ListInstanceDiagnosis --engine=<engine> --cli-region=<r>
163
164
  ```
164
165
 
165
166
  ## Connecting
@@ -95,10 +95,15 @@ Setup is a **plugin-side preflight** — the developer should be asked a questio
95
95
  2. **Real-name verification only** (`HDKIT_NOT_REALNAME`): tell the developer once, "Huawei Cloud requires real-name verification before using the sandbox — please complete it in the Huawei Cloud console (实名认证)." and stop — do not retry `connect` in a loop
96
96
  3. **Sign agreement only** (`HDKIT_NOT_AGREEMENT`): **STOP and do NOT sign on your own.** Ask the developer: "Huawei Cloud sandbox requires signing the latest developer service agreement. May I sign it for you?" Then **wait for the developer to explicitly agree** (e.g. "签署" / "确认" / "sign it"). Only after explicit consent call `huaweicloud_sandbox_sign_agreement` and return its result (`signed`/`signedCount`) to the developer. **Never sign a legal agreement on the developer's behalf without their explicit, unambiguous consent.** Do not expose the underlying sandbox/DevBridge service as a separate entity the developer must understand or sign up for
97
97
  4. **Both missing** (`HDKIT_NOT_REALNAME_AND_AGREEMENT`): present **both** requirements together in one message — the real-name verification steps (console, step 2) **and** the agreement-signing request (step 3, wait for explicit consent) — so the developer can complete both at once
98
- 5. **Connect**: `huaweicloud_sandbox_connect` — returns `session_id`, `dev_stage_id`, `connection_id`, `connection_address`
99
- 6. **Cleanup previous deployments** (after first connect to a sandbox): nginx configs and DevBridge tunnels from previous deployments can cause port conflicts and quota errors. Run cleanup immediately after connect:
98
+ 5. **Connect**: `huaweicloud_sandbox_connect` — returns `session_id`, `dev_stage_id`, `connection_id`, `connection_address`. The `source` parameter identifies the calling agent (valid values: `CLI`, `WEB`, `VSCODE`, `WEBVNC`, `WEBPTY`, `WEBIDE`, `CURSOR`, etc. — case-sensitive, all uppercase). The `git` parameter (with `repo_url`, `repo_name`, `target_path`) is accepted but does NOT auto-clone the repository — always clone manually.
99
+ 6. **Cleanup previous deployments** (after first connect to a sandbox): nginx configs, DevBridge tunnels, and stale web processes from previous deployments can cause port conflicts and quota errors. Run cleanup immediately after connect:
100
100
 
101
101
  ```bash
102
+ # Kill stale Node.js web processes from previous deployments
103
+ pkill -9 -f "next-server" 2>/dev/null || true
104
+ pkill -9 -f "next start" 2>/dev/null || true
105
+ pkill -9 -f "nuxt" 2>/dev/null || true
106
+ sleep 1
102
107
  # Remove stale nginx configs from previous deployments
103
108
  sudo rm -f /etc/nginx/conf.d/*.conf /etc/nginx/conf.d/*.conf.bak 2>/dev/null
104
109
  # Remove stale DevBridge tunnels
@@ -202,7 +207,7 @@ fi
202
207
  export PATH=$PATH:$HOME/.huawei/bin # installer only writes ~/.bashrc; session shells do not re-source it
203
208
  ```
204
209
 
205
- **Login** (non-interactive; credentials injected by `huaweicloud_sandbox_credentials` are available at `/tmp/hw_creds.sh`):
210
+ **Login** (non-interactive; credentials from `huaweicloud_sandbox_credentials` are available via `/tmp/hw_creds.sh`). If `source /tmp/hw_creds.sh` returns empty, the credentials injection has expired (sandbox session reconnection resets them) — re-run `huaweicloud_sandbox_credentials` first:
206
211
 
207
212
  ```bash
208
213
  source /tmp/hw_creds.sh 2>/dev/null
@@ -248,7 +253,7 @@ fi
248
253
 
249
254
  ```bash
250
255
  # Step A: List all tunnels (both active and stale)
251
- devbridge ls --all
256
+ devbridge list -j
252
257
  # Step B: Remove all stale tunnels
253
258
  devbridge delete-all
254
259
  # Step C: Retry tunnel creation
@@ -260,6 +265,7 @@ This eliminates the most common deployment failure — historical tunnels from p
260
265
 
261
266
  - The public URL has the form `https://<id>-<port>.cn-north-4-bridge.myhuaweicloud.com` (from the `Tunnel URL:` line).
262
267
  - **Return this URL to the developer as the deployment result link.** Keep the host process running (do not close the session before handing over the URL).
268
+ - Tunnel `description` (`-d`) accepts only Chinese characters, letters, and digits (0-64). Symbols such as `-`/`_`/spaces are rejected (`Invalid tunnel description`).
263
269
  - Internal docs: https://huaweicloud.github.io/devspace-devbridge/
264
270
 
265
271
  **No local downgrade**: if the tunnel tooling cannot be installed in the sandbox, STOP and report a generic error ("无法生成访问地址") without technical detail. Never install it on the developer's local machine — a local install would defeat the purpose of sandbox deployment.
@@ -349,6 +355,16 @@ if command -v apt-get >/dev/null 2>&1; then echo "PKG_MGR=apt"; elif command -v
349
355
 
350
356
  Use the detected `PKG_MGR` for all package installations below.
351
357
 
358
+ **Architecture awareness**: the sandbox runs Linux aarch64 (ARM64). Native binaries built on x64 (Windows/macOS Intel) will not execute. Always install dependencies and build inside the sandbox. For projects with native addons (Taro `@swc/core`, Prisma, `esbuild`, `node-gyp`), local x64 pre-build + upload of `dist/` output is a viable alternative when sandbox builds fail.
359
+
360
+ **GitCode SSL**: if `git clone` from GitCode fails with SSL certificate errors, use a one-shot override (do NOT set it globally — that would disable cert verification for every repo):
361
+
362
+ ```bash
363
+ git -c http.sslVerify=false clone <repo-url>
364
+ ```
365
+
366
+ Then retry the clone. This bypasses SSL verification only for this single clone.
367
+
352
368
  #### 3b: Install nginx (before project upload)
353
369
 
354
370
  ```bash
@@ -422,6 +438,15 @@ echo "NODE_ENV=${NODE_ENV:-development}"
422
438
 
423
439
  This must run via `exec_with_session` so the exported variables persist for subsequent build commands in the same session.
424
440
 
441
+ **Prisma / ORM compatibility**: Prisma CLI (`prisma generate`, `prisma db push`, `prisma migrate`) only reads `.env` by default, NOT `.env.local` or `.env.development`. If the project uses `.env.local` for `DATABASE_URL`, link it before any Prisma command:
442
+
443
+ ```bash
444
+ # Prisma requires .env (not .env.local) — symlink if needed
445
+ if [ -f .env.local ] && [ ! -f .env ]; then ln -sf .env.local .env 2>/dev/null || cp .env.local .env; fi
446
+ # Then re-source
447
+ set -a && source .env 2>/dev/null; set +a
448
+ ```
449
+
425
450
  #### 4b: Install Dependencies
426
451
 
427
452
  Use `exec_one_shot` for install (no shared state needed). Skip if `node_modules` already exists:
@@ -444,6 +469,18 @@ Node v24+ uses musl-based binaries on some sandbox images, which may break nativ
444
469
  - For rollup 4 projects, consider `npm install rollup@3` as fallback
445
470
  - If webpack/rollup native addon errors persist, add `--ignore-scripts` then manually rebuild: `npm rebuild`
446
471
 
472
+ **Prisma / database initialization**: if `prisma/schema.prisma` exists in the project, initialize the database after install and before build. Prisma Client generation (`prisma generate`) is usually handled by `postinstall`, but `prisma db push` (SQLite) or `prisma migrate deploy` (PostgreSQL/MySQL) must be run manually:
473
+
474
+ ```bash
475
+ cd /workspace/<dirname>
476
+ if [ -f prisma/schema.prisma ]; then
477
+ echo "Prisma schema detected — initializing database..."
478
+ npx prisma db push --skip-generate 2>/dev/null || npx prisma migrate deploy 2>/dev/null || echo "WARN: skip db init"
479
+ fi
480
+ ```
481
+
482
+ > `--skip-generate` avoids redundant generation when `postinstall` already ran `prisma generate`. For SQLite, `DATABASE_URL="file:./dev.db"` must be set in `.env`/`.env.local` before this step.
483
+
447
484
  #### 4c: Build
448
485
 
449
486
  **Timeout strategy by framework type:**
@@ -587,6 +624,17 @@ chmod -R +x "$REAL_ROOT/node_modules/.bin" 2>/dev/null || true
587
624
 
588
625
  This prevents the most common deployment failure: nginx 500 with `stat() ... Permission denied` caused by missing `o+x` on intermediate directories.
589
626
 
627
+ #### 4e: Write Deployment Fingerprint
628
+
629
+ After a successful build, write a deployment fingerprint into the output directory. This enables `deploy_check` to verify the nginx-served content belongs to the current deployment (not a stale process from an earlier session):
630
+
631
+ ```bash
632
+ echo "deployed-$(date +%s)-<dirname>" > /workspace/<dirname>/<outputDir>/.deploy_fingerprint
633
+ chmod o+r /workspace/<dirname>/<outputDir>/.deploy_fingerprint 2>/dev/null || true
634
+ ```
635
+
636
+ > For SSR proxy type, nginx does not serve static files from `.next` — the fingerprint check will gracefully SKIP in `deploy_check`. The fingerprint is still written as a deployment marker for debugging.
637
+
590
638
  ### Step 5: Port Availability Check
591
639
 
592
640
  **Before configuring nginx or starting the app**, verify the target ports are free. Port conflicts from previous deployments cause silent failures:
@@ -654,7 +702,7 @@ Use `huaweicloud_sandbox_deploy_nginx` to write the correct template, fix direct
654
702
  - `port` — listen port from framework detection
655
703
  - `project` — project dir name under `/workspace`
656
704
  - `output_dir` — build output dir relative to `/workspace/<project>`
657
- - `node_port` — Node.js app port (required only when `nginx_type=proxy`)
705
+ - `node_port` — Node.js app port for SSR proxy. Defaults to `<port> + 1` if omitted, and the result includes `nodePort` so you know which port to bind the Node process to.
658
706
  - `public_port` — public listen port for SSR proxy (optional, defaults to `port`)
659
707
 
660
708
  The tool automatically handles:
@@ -682,7 +730,21 @@ If the status code is not 2xx/3xx:
682
730
  ### Step 6: Start the App [REQUIRED]
683
731
 
684
732
  - **Static (SPA/SSG/cross-platform)**: nginx is already serving. Skip.
685
- - **SSR**: run `<serveCmd>` via `exec_with_session` to start the Node process in background.
733
+ - **SSR**: `PORT=<nodePort>` prefix is REQUIRED before `<serveCmd>`. nginx `proxy_pass` targets `<nodePort>`, not `<port>` — the two must differ. `deployNginx` returns `nodePort` in its result (defaults to `<port> + 1` for proxy type).
734
+
735
+ **Runtime environment variables**: SSR apps often need `DATABASE_URL`, `NEXTAUTH_URL`, `NEXTAUTH_SECRET`, etc. at runtime. Before starting, verify env vars from Step 4a are still loaded, and re-source `.env` if the shell session was reset:
736
+
737
+ ```bash
738
+ cd /workspace/<dirname>
739
+ # Re-load env vars (SSR apps need them at runtime, not just build time)
740
+ if [ -f .env ]; then set -a && source .env 2>/dev/null; set +a; echo "Loaded .env"; fi
741
+ if [ -f .env.local ]; then set -a && source .env.local 2>/dev/null; set +a; echo "Loaded .env.local"; fi
742
+ # Verify critical vars
743
+ echo "DATABASE_URL=${DATABASE_URL:-<NOT SET>}"
744
+ echo "NEXTAUTH_URL=${NEXTAUTH_URL:-<NOT SET>}"
745
+ ```
746
+
747
+ Then start with `PORT=<nodePort> <serveCmd>` via `exec_with_session` to run the Node process in background.
686
748
 
687
749
  ### Step 7: Expose via DevBridge [REQUIRED — deployment incomplete without this]
688
750
 
@@ -690,7 +752,7 @@ Follow the standard [Expose the deployed app](#expose-the-deployed-app-public-ur
690
752
 
691
753
  Use `exec_with_session` to background DevBridge. For SSR, DevBridge tunnels the nginx public port (not the Node port directly).
692
754
 
693
- **Pre-flight**: always run `devbridge delete-all` before creating a new tunnel to prevent `10006: quota exceeded` from accumulated stale tunnels. If you still get quota error, list tunnels with `devbridge ls --all`, delete stale ones, and retry.
755
+ **Pre-flight**: always run `devbridge delete-all` before creating a new tunnel to prevent `10006: quota exceeded` from accumulated stale tunnels. If you still get quota error, list tunnels with `devbridge list -j`, delete stale ones, and retry.
694
756
 
695
757
  Extract the tunnel URL from DevBridge output. The public URL has the form `https://<id>-<port>.cn-north-4-bridge.myhuaweicloud.com`. **Return this URL to the developer as the deployment result.**
696
758
 
@@ -771,6 +833,8 @@ Returns `complete: true/false`, `score`, and `nextStep` to fix missing items.
771
833
  | Call deploy_check before success | Always call `huaweicloud_sandbox_deploy_check` before reporting deployment success. A green nginx status does not mean the tunnel is accessible — verify end-to-end with the tool. |
772
834
  | Session state persists | `exec_with_session` preserves `cd`, env vars, aliases between calls |
773
835
  | Long commands prefer one-shot | `exec_one_shot` creates a fresh connection per call — more stable for builds, installs, and scripts >30s. See [Tool Selection Guide](#tool-selection-guide). |
836
+ | SSR nginx/Node ports must differ | nginx `proxy_pass` targets `<nodePort>`, not `<port>`. `deploy_nginx` auto-defaults `nodePort` to `<port>+1` — always start the Node process with `PORT=<nodePort>` to match. Same-port = EADDRINUSE. |
837
+ | HTTP 200 ≠ correct content | A green HTTP check does not guarantee the right project is serving — old processes from a previous session bound to the same port will still return 200. `deploy_check` verifies the deployment fingerprint to catch this. |
774
838
  | Destructive commands blocked | `rm -rf /`, `mkfs`, `dd if=`, fork bombs are denied by safety policy |
775
839
  | Workspace ID = dev_stage_id | Use `dev_stage_id` from `sandbox_connect` as `workspace_id` for terminal exec |
776
840
  | Projects live in `/workspace` | Clone/install project code under `/workspace/<repo-name>` (filesystem-root workspace mount, not `$HOME/workspace`), never in `/tmp` — ephemeral locations lose the project when the sandbox session restarts |
@@ -42,6 +42,7 @@ 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
@@ -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 DMS <Operation> --help` before constructing commands.
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
- ### Service Types
41
+ > **DMS 是产品统一品牌**,涵盖 Kafka、RabbitMQ、RocketMQ 三种引擎。在 KooCLI 中,三种引擎被拆分为独立服务,**不存在 `hcloud DMS` 命令**。
42
42
 
43
- | Type | KooCLI Service |
44
- | -------- | -------------- |
45
- | Kafka | `hcloud DMS` |
46
- | RabbitMQ | `hcloud DMS` |
47
- | RocketMQ | `hcloud DMS` |
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 | Operation |
52
- | --------------------- | -------------------------------------------------- |
53
- | List instances | `ListInstances --cli-region=<r> --project_id=<p>` |
54
- | Create Kafka instance | `CreateInstance --cli-region=<r> --project_id=<p>` |
55
- | List Kafka topics | `ListTopics --cli-region=<r> --project_id=<p>` |
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
 
@@ -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 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
- | 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 DisassociatePublicip --publicip_id=<id> | references/eip.md |
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 VPC CreateSubnet --help` |
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.129.250 |
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.129.250 |
12
- | cn-south-1 | 100.125.1.250 | 100.125.129.250 |
13
- | ap-southeast-3 | 100.125.1.250 | 100.125.129.250 |
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=100.125.1.250 \
25
- --subnet.dnsList.2=100.125.129.250
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 | `ListInstances --cli-region=<r> --project_id=<p>` |
33
- | List policies | `ListPolicies --cli-region=<r> --project_id=<p>` |
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
- hcloud AAD ListInstances --cli-region=<r> --project_id=<p>
43
- hcloud AAD CreateInstance --cli-region=<r> --project_id=<p>
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 | 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 project config | `.codeartsdoer/mcp/mcp_settings.json` (project, then user) | File |
133
- | 4 | Global config file | `~/.config/huaweicloud/credentials.json` | Permanent |
134
- | 5 | KooCLI profile | `~/.hcloud/config.json` (KooCLI only) | Permanent |
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
 
@@ -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']);
@@ -179,6 +186,11 @@ function atomcodeRegistered() {
179
186
  return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
180
187
  }
181
188
 
189
+ function openclawRegistered() {
190
+ const cfg = readJsonSafe(join(baseHome(), '.agents', 'huaweicloud-plugins', '.mcp.json'));
191
+ return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
192
+ }
193
+
182
194
  function hermesHome() {
183
195
  if (process.env.HERMES_HOME) return process.env.HERMES_HOME;
184
196
  // Hermes on Windows stores under LOCALAPPDATA, not ~/.hermes
@@ -208,10 +220,12 @@ export function getAgentRegistrationStatuses(target = 'all') {
208
220
  if (agent === 'codex-desktop') configured = codexDesktopRegistered();
209
221
  if (agent === 'codex') configured = codexCliRegistered();
210
222
  if (agent === 'codearts') configured = codeartsRegistered();
223
+ if (agent === 'codearts-work') configured = codeartsWorkRegistered();
211
224
  if (agent === 'workbuddy') configured = workbuddyRegistered();
212
225
  if (agent === 'dsh') configured = dshRegistered();
213
226
  if (agent === 'officeace') configured = officeaceRegistered();
214
227
  if (agent === 'hermes') configured = hermesRegistered();
228
+ if (agent === 'openclaw') configured = openclawRegistered();
215
229
  if (agent === 'atomcode') configured = atomcodeRegistered();
216
230
  result.agents[agent] = { configured };
217
231
  }
@@ -123,7 +123,11 @@ export function getParentCwd() {
123
123
  }
124
124
 
125
125
  function isCodeArtsContext() {
126
- return existsSync(join(process.cwd(), '.codeartsdoer')) || existsSync(join(homedir(), '.codeartsdoer'));
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>".',