huaweicloud-devkit 1.1.0-next.3 → 1.1.0-next.5
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/package.json +1 -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/openclaw.plugin.json +1 -1
- package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +47 -35
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/framework-commands.md +0 -1
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/nginx-templates.md +4 -4
- package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +34 -11
- package/plugins/huaweicloud-core/src/tools.mjs +10 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.1.0-next.
|
|
3
|
+
"version": "1.1.0-next.5",
|
|
4
4
|
"description": "Agent toolkit that helps coding agents use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities safely and accurately.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"mcpServers": "./.mcp.json",
|
|
18
18
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
19
19
|
"skills": "./skills/",
|
|
20
|
-
"version": "1.1.0-next.
|
|
20
|
+
"version": "1.1.0-next.5",
|
|
21
21
|
"author": {
|
|
22
22
|
"name": "HuaweiCloud Mate",
|
|
23
23
|
"url": "https://github.com/huaweicloud"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"mcpServers": "./.mcp.json",
|
|
21
21
|
"description": "Agent toolkit that helps coding agents use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities safely and accurately.",
|
|
22
22
|
"skills": "./skills/",
|
|
23
|
-
"version": "1.1.0-next.
|
|
23
|
+
"version": "1.1.0-next.5",
|
|
24
24
|
"author": {
|
|
25
25
|
"name": "HuaweiCloud Mate",
|
|
26
26
|
"url": "https://github.com/huaweicloud"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"mcpServers": "./.mcp.json",
|
|
18
18
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
19
19
|
"skills": "./skills/",
|
|
20
|
-
"version": "1.1.0-next.
|
|
20
|
+
"version": "1.1.0-next.5",
|
|
21
21
|
"author": {
|
|
22
22
|
"name": "HuaweiCloud Mate",
|
|
23
23
|
"url": "https://github.com/huaweicloud"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.1.0-next.
|
|
3
|
+
"version": "1.1.0-next.5",
|
|
4
4
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "HuaweiCloud Mate",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.1.0-next.
|
|
3
|
+
"version": "1.1.0-next.5",
|
|
4
4
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "HuaweiCloud Mate",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
3
|
"id": "huaweicloud-devkit",
|
|
4
4
|
"displayName": "HuaweiCloud DevKit",
|
|
5
|
-
"version": "1.1.0-next.
|
|
5
|
+
"version": "1.1.0-next.5",
|
|
6
6
|
"family": "bundle-plugin",
|
|
7
7
|
"bundleFormat": "codex",
|
|
8
8
|
"description": "Guide coding agents to use Huawei Cloud safely — KooCLI, APIs, SDKs, 28 MCP tools, skills, and safety guardrails.",
|
|
@@ -221,24 +221,22 @@ Before installing project dependencies, verify the sandbox has the required runt
|
|
|
221
221
|
```bash
|
|
222
222
|
# Core tools (expected pre-installed in sandbox image)
|
|
223
223
|
echo "=== Checking core tools ==="
|
|
224
|
-
command -v node
|
|
225
|
-
command -v npm
|
|
226
|
-
command -v nginx
|
|
227
|
-
command -v git
|
|
228
|
-
command -v python3
|
|
229
|
-
command -v curl
|
|
230
|
-
command -v wget
|
|
231
|
-
dpkg -l build-essential >/dev/null 2>&1
|
|
232
|
-
command -v
|
|
233
|
-
command -v netstat && netstat --version 2>&1 | head -1 || echo "MISSING: net-tools"
|
|
234
|
-
command -v make && make --version | head -1 || echo "MISSING: make"
|
|
224
|
+
if command -v node >/dev/null 2>&1; then node --version; else echo "MISSING: node"; fi
|
|
225
|
+
if command -v npm >/dev/null 2>&1; then npm --version; else echo "MISSING: npm"; fi
|
|
226
|
+
if command -v nginx >/dev/null 2>&1; then nginx -v 2>&1; else echo "MISSING: nginx"; fi
|
|
227
|
+
if command -v git >/dev/null 2>&1; then git --version; else echo "MISSING: git"; fi
|
|
228
|
+
if command -v python3 >/dev/null 2>&1; then python3 --version; else echo "MISSING: python3"; fi
|
|
229
|
+
if command -v curl >/dev/null 2>&1; then curl --version | head -1; else echo "MISSING: curl"; fi
|
|
230
|
+
if command -v wget >/dev/null 2>&1; then wget --version | head -1; else echo "MISSING: wget"; fi
|
|
231
|
+
if dpkg -l build-essential >/dev/null 2>&1; then echo "build-essential: found"; else echo "MISSING: build-essential"; fi
|
|
232
|
+
if command -v make >/dev/null 2>&1; then make --version | head -1; else echo "MISSING: make"; fi
|
|
235
233
|
|
|
236
234
|
# Framework-specific tools (install on demand)
|
|
237
235
|
echo "=== Checking framework tools ==="
|
|
238
|
-
command -v pnpm
|
|
239
|
-
command -v yarn
|
|
240
|
-
command -v hugo
|
|
241
|
-
command -v devbridge
|
|
236
|
+
if command -v pnpm >/dev/null 2>&1; then pnpm --version; else echo "MISSING: pnpm"; fi
|
|
237
|
+
if command -v yarn >/dev/null 2>&1; then yarn --version; else echo "MISSING: yarn"; fi
|
|
238
|
+
if command -v hugo >/dev/null 2>&1; then hugo version; else echo "MISSING: hugo"; fi
|
|
239
|
+
if command -v devbridge >/dev/null 2>&1; then devbridge version; else echo "MISSING: devbridge"; fi
|
|
242
240
|
```
|
|
243
241
|
|
|
244
242
|
**Install only missing tools** — parse the pre-flight output and install only tools reported as `MISSING`. Skip tools already present:
|
|
@@ -250,8 +248,6 @@ command -v devbridge && devbridge version || echo "MISSING: devbridge"
|
|
|
250
248
|
| curl | `sudo apt-get update -qq && sudo apt-get install -y -qq curl` |
|
|
251
249
|
| wget | `sudo apt-get update -qq && sudo apt-get install -y -qq wget` |
|
|
252
250
|
| build-essential | `sudo apt-get update -qq && sudo apt-get install -y -qq build-essential` |
|
|
253
|
-
| lsof | `sudo apt-get update -qq && sudo apt-get install -y -qq lsof` |
|
|
254
|
-
| net-tools | `sudo apt-get update -qq && sudo apt-get install -y -qq net-tools` |
|
|
255
251
|
| make | `sudo apt-get update -qq && sudo apt-get install -y -qq make` |
|
|
256
252
|
| pnpm | `npm i -g pnpm` |
|
|
257
253
|
| yarn | `npm i -g yarn` |
|
|
@@ -277,7 +273,7 @@ Wait for install to complete, then:
|
|
|
277
273
|
**Build** — only if build output doesn't already exist:
|
|
278
274
|
|
|
279
275
|
```bash
|
|
280
|
-
cd /workspace/<dirname> && [ -d <outputDir> ] && echo "SKIP: <outputDir> exists" || <buildCmd>
|
|
276
|
+
cd /workspace/<dirname> && [ -d <outputDir> ] && echo "SKIP: <outputDir> exists" || (umask 022 && <buildCmd>)
|
|
281
277
|
```
|
|
282
278
|
|
|
283
279
|
- `cd /workspace/<dirname>/<subAppPath>` for Monorepo sub-apps.
|
|
@@ -303,6 +299,20 @@ Replace `<port>`, `<project>`, `<outputDir>` (and `<nodePort>`/`<publicPort>` fo
|
|
|
303
299
|
|
|
304
300
|
Write the config with `sudo tee`, then reload nginx. If nginx fails, fall back to Python HTTP server (see `references/nginx-templates.md`).
|
|
305
301
|
|
|
302
|
+
**Verify nginx is serving** — curl-check the app before proceeding to DevBridge:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
curl -s -o /dev/null -w "nginx status: %{http_code}\n" http://localhost:<port>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
If the status code is not 2xx/3xx:
|
|
309
|
+
|
|
310
|
+
- **403** — likely file permissions: run `chmod -R o+rX /workspace/<project>/<outputDir>` and re-test
|
|
311
|
+
- **000 (connection refused)** — nginx not listening: check `sudo nginx -t` for config errors
|
|
312
|
+
- **Other** — check nginx error log: `sudo tail -20 /var/log/nginx/error.log`
|
|
313
|
+
|
|
314
|
+
> If `curl` is unavailable, check port listening via `/proc`: `cat /proc/net/tcp | awk '{print $2}' | grep -q "$(printf '%04X' <port>)" && echo "port <port> listening" || echo "port <port> NOT listening"`
|
|
315
|
+
|
|
306
316
|
### Step 6: Start the App
|
|
307
317
|
|
|
308
318
|
- **Static (SPA/SSG/cross-platform)**: nginx is already serving. Skip.
|
|
@@ -325,23 +335,25 @@ Extract the tunnel URL from DevBridge output and return it to the developer. For
|
|
|
325
335
|
|
|
326
336
|
## Critical Warnings
|
|
327
337
|
|
|
328
|
-
| Trap | Why
|
|
329
|
-
| ------------------------------------ |
|
|
330
|
-
| Agreement required first | `sandbox_connect` fails if the agreement isn't signed; the `sandbox_check_user` preflight detects this, so surface it to the developer only when signing is needed
|
|
331
|
-
| Real-name required | `sandbox_connect` fails if `realnameVerified=false`; tell the developer once and stop, don't loop on connect
|
|
332
|
-
| Never expose tunnel details | Do not mention "DevBridge"/"tunnel"/"devbridge" to the developer — say "正在生成访问地址..." and hand over only the URL
|
|
333
|
-
| Login needs `--huaweicloud` | `devbridge auth login --access-key/--secret-key` without `--huaweicloud` falls back to interactive browser login, which fails in the sandbox
|
|
334
|
-
| CLI PATH | The installer only writes `~/.bashrc`; run `export PATH=$PATH:$HOME/.huawei/bin` in the session before using `devbridge`
|
|
335
|
-
| Never install tunnel tooling locally | If the sandbox cannot install it, report a generic error and stop — installing on the developer's machine defeats sandbox deployment
|
|
336
|
-
| Return the deployment URL | Always hand the public URL from the host log to the developer as the final result
|
|
337
|
-
| Session state persists | `exec_with_session` preserves `cd`, env vars, aliases between calls
|
|
338
|
-
| 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).
|
|
339
|
-
| Destructive commands blocked | `rm -rf /`, `mkfs`, `dd if=`, fork bombs are denied by safety policy
|
|
340
|
-
| Workspace ID = dev_stage_id | Use `dev_stage_id` from `sandbox_connect` as `workspace_id` for terminal exec
|
|
341
|
-
| 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
|
|
342
|
-
| Upload project for local code | Use `sandbox_upload_project` to transfer local projects — packages as tar.gz, uploads via HTTP tunnel, extracts on sandbox. Much faster than base64 for multi-file projects
|
|
343
|
-
| Upload file for single files | Use `sandbox_upload_file` for individual files — base64 chunked, reliable for small files (<1MB)
|
|
344
|
-
| Node.js >= 22 required | Sandbox terminal uses built-in WebSocket (globalThis.WebSocket); if Node.js is missing, install it from the Huawei Cloud mirror (see "Node.js in the sandbox")
|
|
338
|
+
| Trap | Why |
|
|
339
|
+
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
340
|
+
| Agreement required first | `sandbox_connect` fails if the agreement isn't signed; the `sandbox_check_user` preflight detects this, so surface it to the developer only when signing is needed |
|
|
341
|
+
| Real-name required | `sandbox_connect` fails if `realnameVerified=false`; tell the developer once and stop, don't loop on connect |
|
|
342
|
+
| Never expose tunnel details | Do not mention "DevBridge"/"tunnel"/"devbridge" to the developer — say "正在生成访问地址..." and hand over only the URL |
|
|
343
|
+
| Login needs `--huaweicloud` | `devbridge auth login --access-key/--secret-key` without `--huaweicloud` falls back to interactive browser login, which fails in the sandbox |
|
|
344
|
+
| CLI PATH | The installer only writes `~/.bashrc`; run `export PATH=$PATH:$HOME/.huawei/bin` in the session before using `devbridge` |
|
|
345
|
+
| Never install tunnel tooling locally | If the sandbox cannot install it, report a generic error and stop — installing on the developer's machine defeats sandbox deployment |
|
|
346
|
+
| Return the deployment URL | Always hand the public URL from the host log to the developer as the final result |
|
|
347
|
+
| Session state persists | `exec_with_session` preserves `cd`, env vars, aliases between calls |
|
|
348
|
+
| 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). |
|
|
349
|
+
| Destructive commands blocked | `rm -rf /`, `mkfs`, `dd if=`, fork bombs are denied by safety policy |
|
|
350
|
+
| Workspace ID = dev_stage_id | Use `dev_stage_id` from `sandbox_connect` as `workspace_id` for terminal exec |
|
|
351
|
+
| 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 |
|
|
352
|
+
| Upload project for local code | Use `sandbox_upload_project` to transfer local projects — packages as tar.gz, uploads via HTTP tunnel, extracts on sandbox. Much faster than base64 for multi-file projects |
|
|
353
|
+
| Upload file for single files | Use `sandbox_upload_file` for individual files — base64 chunked, reliable for small files (<1MB) |
|
|
354
|
+
| Node.js >= 22 required | Sandbox terminal uses built-in WebSocket (globalThis.WebSocket); if Node.js is missing, install it from the Huawei Cloud mirror (see "Node.js in the sandbox") |
|
|
355
|
+
| Sandbox restart kills processes | After sandbox restarts, all user processes (nginx, Node.js, Python servers) are stopped. Re-run startup commands and verify ports are listening before proceeding. |
|
|
356
|
+
| Cross-platform binaries incompatible | The sandbox runs Linux. Native binaries built on Windows/macOS (e.g., Prisma client, `node_modules/.prisma/`, platform-specific native addons) will not execute. Always install and build dependencies inside the sandbox, not locally. |
|
|
345
357
|
|
|
346
358
|
## Node.js in the sandbox
|
|
347
359
|
|
|
@@ -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,7 +38,7 @@ 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 _;
|
|
@@ -65,7 +65,7 @@ sudo nginx -s reload 2>/dev/null || sudo nginx
|
|
|
65
65
|
Use for: Hugo, Hexo, plain static HTML
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
sudo tee /etc/nginx/
|
|
68
|
+
sudo tee /etc/nginx/conf.d/app.conf > /dev/null << 'NGINX_EOF'
|
|
69
69
|
server {
|
|
70
70
|
listen <port>;
|
|
71
71
|
root /workspace/<project>/<outputDir>;
|
|
@@ -155,7 +155,9 @@ export async function execWithSession(workspaceId, command, username, timeoutMs)
|
|
|
155
155
|
|
|
156
156
|
export const UPLOAD_CHUNK_SIZE = 30000;
|
|
157
157
|
|
|
158
|
-
export const UPLOAD_BATCH_SIZE =
|
|
158
|
+
export const UPLOAD_BATCH_SIZE = 2;
|
|
159
|
+
|
|
160
|
+
export const UPLOAD_MAX_RETRIES = 3;
|
|
159
161
|
|
|
160
162
|
export function splitBase64Chunks(base64, chunkSize = UPLOAD_CHUNK_SIZE) {
|
|
161
163
|
const chunks = [];
|
|
@@ -189,11 +191,21 @@ export async function uploadFileWithSession(workspaceId, localPath, remotePath,
|
|
|
189
191
|
const batchNum = Math.floor(batchStart / UPLOAD_BATCH_SIZE) + 1;
|
|
190
192
|
const totalBatches = Math.ceil(chunks.length / UPLOAD_BATCH_SIZE);
|
|
191
193
|
const cmd = `printf '%s' '${combinedChunk}' >> "${tmp}"`;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
);
|
|
194
|
+
|
|
195
|
+
let batchOk = false;
|
|
196
|
+
let lastError;
|
|
197
|
+
for (let retry = 0; retry < UPLOAD_MAX_RETRIES; retry++) {
|
|
198
|
+
const res = await execWithSession(workspaceId, cmd, username, timeoutMs);
|
|
199
|
+
if (res.exitCode === 0) {
|
|
200
|
+
batchOk = true;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
lastError = res.stdout || res.error || res.exitCode;
|
|
204
|
+
console.error(` upload retry ${retry + 1}/${UPLOAD_MAX_RETRIES} for batch ${batchNum}/${totalBatches}`);
|
|
205
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
206
|
+
}
|
|
207
|
+
if (!batchOk) {
|
|
208
|
+
throw new Error(`sandbox upload: failed writing batch ${batchNum}/${totalBatches}: ${lastError}`);
|
|
197
209
|
}
|
|
198
210
|
if (batchNum % 10 === 0 || batchNum === totalBatches) {
|
|
199
211
|
console.error(` upload progress: batch ${batchNum}/${totalBatches}`);
|
|
@@ -556,14 +568,25 @@ export async function uploadProjectWithSession(
|
|
|
556
568
|
uploadLog(`uploadProject: ${localDir} -> ${archiveRemotePath} (archive=${archiveSize} bytes, md5=${expectedMd5})`);
|
|
557
569
|
|
|
558
570
|
let result;
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
571
|
+
let tunnelError;
|
|
572
|
+
for (let attempt = 0; attempt < UPLOAD_MAX_RETRIES; attempt++) {
|
|
573
|
+
try {
|
|
574
|
+
await cleanupFileServer(workspaceId, username).catch(() => {});
|
|
575
|
+
result = await uploadViaHttpTunnel(workspaceId, archivePath, archiveRemotePath, username, timeoutMs, options);
|
|
576
|
+
tunnelError = null;
|
|
577
|
+
break;
|
|
578
|
+
} catch (error) {
|
|
579
|
+
tunnelError = error;
|
|
580
|
+
uploadLog(`uploadProject: attempt ${attempt + 1}/${UPLOAD_MAX_RETRIES} failed: ${error.message}`);
|
|
581
|
+
await new Promise((r) => setTimeout(r, 5000));
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
if (tunnelError) {
|
|
585
|
+
uploadLog(`uploadProject: all ${UPLOAD_MAX_RETRIES} attempts failed: ${tunnelError.message}`);
|
|
563
586
|
uploadLog(`uploadProject: NOT falling back to base64 (removed). Rethrowing with diagnostics.`);
|
|
564
587
|
cleanupLocalArchive(archivePath);
|
|
565
588
|
throw new Error(
|
|
566
|
-
`sandbox upload failed: HTTP tunnel could not transfer the project archive. ` +
|
|
589
|
+
`sandbox upload failed after ${UPLOAD_MAX_RETRIES} attempts: HTTP tunnel could not transfer the project archive. ` +
|
|
567
590
|
`Archive size: ${(archiveSize / 1024).toFixed(1)}KB. ` +
|
|
568
591
|
`Root cause: ${tunnelError.message}. ` +
|
|
569
592
|
`Diagnostic log: ${UPLOAD_LOG_PATH}`,
|
|
@@ -648,21 +648,27 @@ export const TOOL_DEFINITIONS = [
|
|
|
648
648
|
},
|
|
649
649
|
{
|
|
650
650
|
name: 'huaweicloud_voucher_status',
|
|
651
|
-
description: '
|
|
651
|
+
description: 'Query the Huawei Cloud incentive voucher claim status.',
|
|
652
652
|
inputSchema: {
|
|
653
653
|
type: 'object',
|
|
654
654
|
properties: {
|
|
655
|
-
domain_id: {
|
|
655
|
+
domain_id: {
|
|
656
|
+
type: 'string',
|
|
657
|
+
description: 'Optional. Leave empty in production — account is resolved from IAM automatically.',
|
|
658
|
+
},
|
|
656
659
|
},
|
|
657
660
|
},
|
|
658
661
|
},
|
|
659
662
|
{
|
|
660
663
|
name: 'huaweicloud_voucher_claim',
|
|
661
|
-
description: '
|
|
664
|
+
description: 'Claim the Huawei Cloud incentive voucher. Automatically checks if already claimed.',
|
|
662
665
|
inputSchema: {
|
|
663
666
|
type: 'object',
|
|
664
667
|
properties: {
|
|
665
|
-
domain_id: {
|
|
668
|
+
domain_id: {
|
|
669
|
+
type: 'string',
|
|
670
|
+
description: 'Optional. Leave empty in production — account is resolved from IAM automatically.',
|
|
671
|
+
},
|
|
666
672
|
},
|
|
667
673
|
},
|
|
668
674
|
},
|