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.
- package/README.md +27 -1
- package/README.zh-CN.md +26 -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 +29 -12
- 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 +71 -7
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/nginx-templates.md +4 -0
- package/plugins/huaweicloud-core/skills/huawei-smn-dms/SKILL.md +19 -12
- 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/src/auth/agent-registration.mjs +14 -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 +118 -23
- package/plugins/huaweicloud-core/src/search-market.mjs +1 -0
- package/plugins/huaweicloud-core/src/setup-cli.mjs +491 -64
- 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→
|
|
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→
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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**:
|
|
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
|
|
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
|
|
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
|
|
|
@@ -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
|
|
|
@@ -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
|
|
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>".',
|