huaweicloud-devkit 1.1.12 → 1.1.13-next.2
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 +1 -1
- package/README.zh-CN.md +1 -1
- package/package.json +2 -2
- 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 +58 -7
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/fullstack-postgrest.md +178 -17
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/resource-pool.md +77 -0
- package/plugins/huaweicloud-core/src/mcp-protocol.mjs +8 -1
- package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +48 -0
- package/plugins/huaweicloud-core/src/sandbox/sandbox-pool.mjs +104 -0
- package/plugins/huaweicloud-core/src/setup-cli.mjs +12 -5
- package/plugins/huaweicloud-core/src/telemetry/agent-detect.mjs +20 -15
- package/plugins/huaweicloud-core/src/telemetry/agent-registry.mjs +4 -0
- package/plugins/huaweicloud-core/src/telemetry/telemetry.mjs +105 -31
- package/plugins/huaweicloud-core/src/tools.mjs +131 -56
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/huaweicloud/huaweicloud-devkit/actions/workflows/ci.yml)
|
|
6
6
|
[](https://www.npmjs.com/package/huaweicloud-devkit)
|
|
7
|
-
[](https://github.com/huaweicloud/huaweicloud-devkit)
|
|
8
8
|
|
|
9
9
|
**[中文](README.zh-CN.md) | English**
|
|
10
10
|
|
package/README.zh-CN.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/huaweicloud/huaweicloud-devkit/actions/workflows/ci.yml)
|
|
6
6
|
[](https://www.npmjs.com/package/huaweicloud-devkit)
|
|
7
|
-
[](https://github.com/huaweicloud/huaweicloud-devkit)
|
|
8
8
|
|
|
9
9
|
**中文 | [English](README.md)**
|
|
10
10
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
3
|
"mcpName": "io.github.huaweicloud/huaweicloud-devkit",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.13-next.2",
|
|
5
5
|
"kooCliVersion": "7.3.12",
|
|
6
6
|
"description": "Agent toolkit that helps coding agents use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities safely and accurately.",
|
|
7
7
|
"type": "module",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"postinstall": "node ./bin/dsh-postinstall.cjs"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"undici": "^8.
|
|
46
|
+
"undici": "^8.12.3"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@eslint/js": "^10.0.1",
|
|
@@ -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.
|
|
20
|
+
"version": "1.1.13-next.2",
|
|
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.
|
|
23
|
+
"version": "1.1.13-next.2",
|
|
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.
|
|
20
|
+
"version": "1.1.13-next.2",
|
|
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.
|
|
3
|
+
"version": "1.1.13-next.2",
|
|
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.
|
|
3
|
+
"version": "1.1.13-next.2",
|
|
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.
|
|
5
|
+
"version": "1.1.13-next.2",
|
|
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.",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: huawei-sandbox
|
|
3
|
-
description: 'Use when creating, connecting, or managing Huawei Cloud Sandbox instances and workspace terminals, or when a task needs a temporary runtime to deploy, run, or preview a web application. Covers sandbox lifecycle (check-user, sign-agreement, connect, release), session-based terminal execution, and credential injection. Triggers on: sandbox, workspace, terminal, web app deployment, deploy web app, preview app, deploy github, github repo, deploy repo, website, static site, web application, hwlink, devstation, hdkitservice, remote exec. NOT for: ECS instances (use huawei-ecs), CCE clusters (use huawei-cce).'
|
|
3
|
+
description: 'Use when creating, connecting, or managing Huawei Cloud Sandbox instances and workspace terminals, or when a task needs a temporary runtime to deploy, run, or preview a web application, backend service, or full-stack workbench. Covers sandbox lifecycle (check-user, sign-agreement, connect, release), session-based terminal execution, and credential injection. Triggers on: sandbox, workspace, terminal, web app deployment, deploy web app, preview app, deploy github, github repo, deploy repo, website, static site, web application, backend service, 工作台, workbench, full-stack, 全栈, CRUD 应用, database-backed REST API, PostgREST, postgres, hwlink, devstation, hdkitservice, remote exec. NOT for: ECS instances (use huawei-ecs), CCE clusters (use huawei-cce).'
|
|
4
4
|
version: 1
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -27,10 +27,56 @@ Hard rules:
|
|
|
27
27
|
- Include the OBS domain reminder and the ECS EIP pairing reminder in the options as presented.
|
|
28
28
|
- After the choice: sandbox → continue with this skill; OBS → `huawei-obs`; ECS → `huawei-ecs` / `huawei-iac`; CCE → `huawei-cce`.
|
|
29
29
|
|
|
30
|
+
## Stack-Selection Gate (MANDATORY — do not skip)
|
|
31
|
+
|
|
32
|
+
When the request involves a **workbench / 工作台 / 全栈 / full-stack project** — front-end plus back-end, CRUD with persistence, or a database-backed app — you MUST treat it as a **full-stack workbench deployment**: the back end defaults to **PostgreSQL + PostgREST** even when the developer never mentions 数据库/postgres/CRUD. Do NOT silently fall through to the SPA/nginx-only path.
|
|
33
|
+
|
|
34
|
+
Use the `question` tool to confirm the stack whenever the backend is ambiguous, presenting the PostgREST default first:
|
|
35
|
+
|
|
36
|
+
1. **PostgreSQL + PostgREST 全栈 (recommended)** — schema + read-only `api_user` role, nginx `/api/` reverse proxy; the REST layer needs zero application code
|
|
37
|
+
2. **应用自带后端** — the project ships its own server (Express/Next API/Nuxt server routes); deploy it inside the sandbox per its framework
|
|
38
|
+
3. **纯静态/SPA** — no persistence; nginx-only
|
|
39
|
+
|
|
40
|
+
Hard rules:
|
|
41
|
+
|
|
42
|
+
- **NEVER infer or default the stack to SPA** when persistence is implied: 工作台/workbench/全栈/full-stack/CRUD/数据库/持久化 ⇒ full-stack (PostgREST default) unless the developer explicitly picks otherwise.
|
|
43
|
+
- **Pre-code checkpoint (MANDATORY)**: before uploading or writing ANY application code, verify the backend choice matches this gate. If an SPA-only deployment already started and persistence turns out to be implied, STOP, tell the developer, and redirect to the full-stack path — do not paper over it with a bolted-on static backend.
|
|
44
|
+
- After the choice: PostgREST → follow [Full-Stack: REST API over PostgreSQL](#full-stack-rest-api-over-postgresql-postgrest) **FIRST** (backend before any frontend code), then continue with the web deployment steps; 自带后端 / 纯静态 → continue with [Web Application Deployment](#web-application-deployment).
|
|
45
|
+
|
|
30
46
|
## Overview
|
|
31
47
|
|
|
32
48
|
Domain expertise for Huawei Cloud Sandbox (DevStation) instances and workspace terminal execution. Covers sandbox lifecycle via hdkitservice API and remote terminal command execution via hwlink protocol.
|
|
33
49
|
|
|
50
|
+
## 两池沙箱(pool_type)
|
|
51
|
+
|
|
52
|
+
> 口径基调:一切以实测为准,口头支持不作数(下表生命周期为实测/平台侧现状,平台调参后本节随之更新)。
|
|
53
|
+
|
|
54
|
+
`huaweicloud_sandbox_connect` 用 `pool_type` 选择资源池(服务端权威映射模板;**没有 persist_mode 参数**——上游参数面仅 template_id/flavor_id):
|
|
55
|
+
|
|
56
|
+
| pool_type | 语义 | 生命周期(已实测) | 适用 |
|
|
57
|
+
| ------------------- | ------------------ | ---------------------------------------------------------- | --------------------------- |
|
|
58
|
+
| `ephemeral`(默认) | 非持久沙箱 | 闲置 30 分钟自动关机 + 闲置 1 小时自动删除(平台定时任务) | 临时运行/预览,勿存重要数据 |
|
|
59
|
+
| `persistent` | 持久沙箱(EVS 盘) | 数据跨关机保留;闲置回收保留期上限 7 天 | 需要跨会话保留数据 |
|
|
60
|
+
|
|
61
|
+
Selection rules(agent 按意图自动选池,开发者可覆盖;意图不明确时呈现两类供选择):
|
|
62
|
+
|
|
63
|
+
| 意图 / 场景 | pool_type | 理由 |
|
|
64
|
+
| ------------------------- | ---------- | ----------------------------------- |
|
|
65
|
+
| 预览 / 试用 / demo | ephemeral | 用完即弃,无需保留状态 |
|
|
66
|
+
| 一次性任务(跑完即弃) | ephemeral | 结果带出沙箱;实例随闲置回收 |
|
|
67
|
+
| 敏感内容(即焚) | ephemeral | 闲置 1 小时自动删除,数据随实例消亡 |
|
|
68
|
+
| 开发工作台 / workbench | persistent | 会话跨天;状态需跨关机保留 |
|
|
69
|
+
| 带数据库项目(DB-backed) | persistent | 数据落在挂载的 EVS 盘(32G) |
|
|
70
|
+
| 跨日评审 / 展示 | persistent | 评审者后续日期回访;实例保留 |
|
|
71
|
+
|
|
72
|
+
- **配额**:每用户每类型 1 台(1+1 可并存);同池 connect 自动复用已有实例
|
|
73
|
+
- **429 双错误码**:`HDKIT_QUOTA_EXCEEDED`(账号配额满,重试无效→引导释放/复用);`HDKIT_CAPACITY_INSUFFICIENT`(池容量不足→建议错峰重试)。响应带 `Retry-After`
|
|
74
|
+
- **TTL 播报**:connect 与执行类工具返回值带池模式/生命周期提示——**ephemeral 池部署的公网地址会随沙箱闲置关机失效**,向开发者交付 URL 时必须附带该提示
|
|
75
|
+
- **烧核播报口径**:沙箱运行消耗核时,播报用「平台赠送 + 活动赚取」口径(非直接计费);账号核时耗尽(`HD.97520422`)时工具返回值给出友好引导
|
|
76
|
+
- **删除纪律**:不向开发者暴露生命周期删除 API(回收走平台闲置策略 G1);开发者主动删除时必须二次确认(确认要删除?数据不可恢复);绝不做延后代删
|
|
77
|
+
- 显式 `template_id` 优先于 `pool_type`(自定义模板场景)
|
|
78
|
+
- 完整口径、容量规划与 G 清单:[references/resource-pool.md](references/resource-pool.md)
|
|
79
|
+
|
|
34
80
|
## Activation
|
|
35
81
|
|
|
36
82
|
- **Proactive offering**: when the developer's task needs a temporary runtime (e.g. "deploy this web app", "run this app and preview it"), offer the sandbox proactively — the developer never has to say "use sandbox". Prompt: "This task can be satisfied by a sandbox — use it?"
|
|
@@ -58,10 +104,10 @@ Domain expertise for Huawei Cloud Sandbox (DevStation) instances and workspace t
|
|
|
58
104
|
|
|
59
105
|
### Sandbox Lifecycle
|
|
60
106
|
|
|
61
|
-
| Tool | Purpose
|
|
62
|
-
| --------------------------------- |
|
|
63
|
-
| `huaweicloud_sandbox_connect` | Connect to sandbox (one user
|
|
64
|
-
| `huaweicloud_sandbox_credentials` | Inject temporary AK/SK into a running sandbox
|
|
107
|
+
| Tool | Purpose |
|
|
108
|
+
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
109
|
+
| `huaweicloud_sandbox_connect` | Connect to sandbox (one instance per user per pool; `pool_type` selects ephemeral/persistent, default ephemeral) |
|
|
110
|
+
| `huaweicloud_sandbox_credentials` | Inject temporary AK/SK into a running sandbox |
|
|
65
111
|
|
|
66
112
|
### Tunnel Persistence (public URL lifetime)
|
|
67
113
|
|
|
@@ -117,6 +163,10 @@ Domain expertise for Huawei Cloud Sandbox (DevStation) instances and workspace t
|
|
|
117
163
|
|
|
118
164
|
**Step 0 — Target-Selection Gate (MANDATORY)**: before any sandbox lifecycle tool, confirm the target. If the developer asked to deploy/host/publish a site without naming a target, STOP and run the [Target-Selection Gate](#target-selection-gate-mandatory--do-not-skip) first; do NOT call `huaweicloud_sandbox_connect` until it is resolved. Proceed with this workflow only if the target is already confirmed as sandbox (or a temporary runtime).
|
|
119
165
|
|
|
166
|
+
**Step 0.3 — Resource pool selection**: once the target is sandbox, pick the pool type per the [两池沙箱(pool_type)](#两池沙箱pool_type) selection rules (auto by intent, developer may override; 1 instance per type, same type reuses). Check the task survives the chosen type's lifecycle window (ephemeral: idle 30min shutdown + 1h delete; persistent: 7-day idle reclaim cap) before connecting.
|
|
167
|
+
|
|
168
|
+
**Step 0.5 — Stack-Selection Gate (MANDATORY)**: before uploading or writing any application code, confirm the backend stack via the [Stack-Selection Gate](#stack-selection-gate-mandatory--do-not-skip). 工作台/workbench/全栈/full-stack/CRUD/持久化 ⇒ full-stack (PostgreSQL + PostgREST default) — do NOT start an SPA-only deployment for a workbench request.
|
|
169
|
+
|
|
120
170
|
Setup is a **plugin-side preflight** — the developer should be asked a question only once, when the agreement actually needs signing:
|
|
121
171
|
|
|
122
172
|
1. **Check user** (transparent): `huaweicloud_sandbox_check_user` — returns `realnameVerified`/`agreementSigned` (200) when all good, OR throws a 403 error with one of these codes:
|
|
@@ -462,13 +512,13 @@ When deploying a **full-stack workbench project** (前后端工作台) or asking
|
|
|
462
512
|
3. **Nginx single-origin** — `/` serves the frontend, `/api/` reverse-proxies to PostgREST (no CORS, same origin). The frontend dir needs `chmod o+x` on the whole path chain or nginx returns 403.
|
|
463
513
|
4. **Expose + keep alive (automatic)** — `huaweicloud_sandbox_expose_tunnel` with the nginx port; it AUTO-enrolls the tunnel into the keepalive watchdog (merged into existing coverage). Prefer `expiry_hours: 720` for long-lived workbench deployments.
|
|
464
514
|
|
|
465
|
-
Complete measured procedure (
|
|
515
|
+
Complete measured procedure (full command chain) plus the 2026-10 field notes (Aliyun mirror URLs, cross-mirror resume corruption, `upload_file` 640 → PGRST002, exec-channel escaping → upload files and run `psql -f` / `curl -d @file`): see `references/fullstack-postgrest.md`. For the sandbox restart recovery checklist (what survives on `/workspace` vs what is lost on the 系统盘, plus the write-GRANT rollback trap): see the `Sandbox Restart Recovery Checklist` section in the same file.
|
|
466
516
|
|
|
467
517
|
## Web Application Deployment
|
|
468
518
|
|
|
469
519
|
When deploying a web application to the sandbox, build the app inside the sandbox before exposing it. Source code is uploaded, dependencies installed, and the framework built in the sandbox environment.
|
|
470
520
|
|
|
471
|
-
**Backend
|
|
521
|
+
**Backend selection (Stack-Selection Gate)**: the backend choice was already confirmed by the [Stack-Selection Gate](#stack-selection-gate-mandatory--do-not-skip) before any code was uploaded. If the project includes a PostgreSQL + PostgREST backend (or the developer asked for one), set up the backend FIRST by following [Full-Stack: REST API over PostgreSQL](#full-stack-rest-api-over-postgresql-postgrest) — install PostgreSQL/PostgREST, create the schema, and point the frontend's nginx `/api/` location at PostgREST — then continue with the steps below. Every tunnel exposed afterwards is auto-enrolled into the keepalive watchdog.
|
|
472
522
|
|
|
473
523
|
**沙箱无 systemd(实测 #935 报告3 问题3)**:沙箱为无 systemd 的容器环境,`systemctl` 全部失效(`System has not been booted with systemd`)—— 不要用 `systemctl start/reload/restart nginx`。Nginx 配置变更直接使用 `nginx -t` 验证 + `nginx -s reload` 热加载,或直接执行 nginx 二进制(`sudo nginx` 启动 / `nginx -s stop` 停止)。`huaweicloud_sandbox_deploy_nginx` 工具返回的 nextStep 文案与该语义一致(配置写入后自动回验存在性与 `nginx -t`,通过后即生效,无需 systemctl)。
|
|
474
524
|
|
|
@@ -1031,6 +1081,7 @@ Returns `complete: true/false`, `score`, and `nextStep` to fix missing items.
|
|
|
1031
1081
|
|
|
1032
1082
|
- [Framework Commands](references/framework-commands.md) — command mapping for all supported frameworks
|
|
1033
1083
|
- [Nginx Templates](references/nginx-templates.md) — nginx configuration templates and fallback
|
|
1084
|
+
- [Resource Pool](references/resource-pool.md) — 资源池定稿口径:两沙箱类型、申请/限流参数(持久 2U4G×300 + 4U8G×200、非持久 2U4G×1000、overlayer 5GB/实例、EVS 300TB)、配额 1/类型 与 429+Retry-After 语义
|
|
1034
1085
|
|
|
1035
1086
|
## Critical Warnings
|
|
1036
1087
|
|
|
@@ -25,10 +25,12 @@ least 14.0"). PGDG is the source for PG 16 — but HCE is NOT el8-lib-compatible
|
|
|
25
25
|
```bash
|
|
26
26
|
# PGDG repo RPM fails on HCE ("nothing provides /etc/redhat-release") — write the repo file by hand.
|
|
27
27
|
# The el8 path is rhel-8-aarch64 WITH A HYPHEN: rhel8-aarch64 (no hyphen) 404s.
|
|
28
|
+
# Use the Aliyun mirror: download.postgresql.org / repo.almalinux.org measure ~8KB/s from
|
|
29
|
+
# sandbox CN egress (a 6.8MB server RPM times out inside 240s); the mirror returns in seconds.
|
|
28
30
|
cat > /etc/yum.repos.d/pgdg16.repo << 'PGDG_EOF'
|
|
29
31
|
[pgdg16]
|
|
30
|
-
name=PostgreSQL 16 for RHEL8 aarch64
|
|
31
|
-
baseurl=https://
|
|
32
|
+
name=PostgreSQL 16 for RHEL8 aarch64 (Aliyun mirror)
|
|
33
|
+
baseurl=https://mirrors.aliyun.com/postgresql/repos/yum/16/redhat/rhel-8-aarch64/
|
|
32
34
|
enabled=1
|
|
33
35
|
gpgcheck=0
|
|
34
36
|
PGDG_EOF
|
|
@@ -39,10 +41,13 @@ differently (they want `libldap-2.5.so.0`). Install the el8 RPMs with
|
|
|
39
41
|
`--nodeps` and shim the sonames:
|
|
40
42
|
|
|
41
43
|
```bash
|
|
42
|
-
|
|
43
|
-
# Download with resume (--max-time + -C -)
|
|
44
|
-
#
|
|
45
|
-
#
|
|
44
|
+
# Aliyun mirror (measured 2026-10: seconds per RPM vs ~8KB/s timeouts on the official source).
|
|
45
|
+
# Download with resume (--max-time + -C -) WITHIN THE SAME MIRROR only: a partial file
|
|
46
|
+
# resumed from a DIFFERENT mirror fails rpm verification ("Payload SHA256 digest: BAD") —
|
|
47
|
+
# when switching sources, rm the partial file and re-download in full (see field notes).
|
|
48
|
+
# A corrupt RPM also ABORTS the whole transaction, silently skipping the other RPMs in the
|
|
49
|
+
# same rpm -ivh call. Install one RPM per call.
|
|
50
|
+
BASE="https://mirrors.aliyun.com/postgresql/repos/yum/16/redhat/rhel-8-aarch64"
|
|
46
51
|
curl -fsSL --http1.1 --max-time 240 -C - "$BASE/postgresql16-libs-16.15-1PGDG.rhel8.10.aarch64.rpm" -o /tmp/pg16-libs.rpm
|
|
47
52
|
rpm -ivh --nodeps /tmp/pg16-libs.rpm
|
|
48
53
|
curl -fsSL --http1.1 --max-time 240 -C - "$BASE/postgresql16-16.15-1PGDG.rhel8.10.aarch64.rpm" -o /tmp/pg16.rpm
|
|
@@ -56,9 +61,10 @@ Soname shims (measured 2026-10):
|
|
|
56
61
|
```bash
|
|
57
62
|
# ICU: versioned symbols (u_strToLower_60) make symlinks IMPOSSIBLE — a
|
|
58
63
|
# libicu.so.60 -> .69 symlink loads but crashes with "undefined symbol".
|
|
59
|
-
# Install the REAL el8 libicu60 (different sonames, coexists with HCE's icu69)
|
|
64
|
+
# Install the REAL el8 libicu60 (different sonames, coexists with HCE's icu69);
|
|
65
|
+
# AlmaLinux official repo is also ~8KB/s from the sandbox — use the Aliyun mirror:
|
|
60
66
|
curl -fsSL --http1.1 --max-time 240 -C - \
|
|
61
|
-
"https://
|
|
67
|
+
"https://mirrors.aliyun.com/almalinux/8/BaseOS/aarch64/os/Packages/libicu-60.3-2.el8_1.aarch64.rpm" -o /tmp/libicu60.rpm
|
|
62
68
|
rpm -ivh --nodeps --force /tmp/libicu60.rpm # --force: license file conflicts with icu69
|
|
63
69
|
|
|
64
70
|
# LDAP: postgres only uses it for LDAP auth (not needed here) — symlinks suffice.
|
|
@@ -72,12 +78,16 @@ ln -sf /usr/lib64/libreadline.so.8 /usr/lib64/libreadline.so.7
|
|
|
72
78
|
ldconfig # registers /usr/pgsql-16/lib (libpq.so.5)
|
|
73
79
|
```
|
|
74
80
|
|
|
75
|
-
Init and start (PG refuses root; no systemd on HCE)
|
|
81
|
+
Init and start (PG refuses root; no systemd on HCE). **The data directory
|
|
82
|
+
MUST live on the data disk** (`/workspace`), not `/var/lib/pgsql` —
|
|
83
|
+
`/var/lib/pgsql` is on the 系统盘 (system disk) and a sandbox reboot rolls it
|
|
84
|
+
back to the image state, destroying all databases. `/workspace` is the data
|
|
85
|
+
disk and survives reboots (#999):
|
|
76
86
|
|
|
77
87
|
```bash
|
|
78
|
-
mkdir -p /
|
|
79
|
-
su - postgres -c "/usr/pgsql-16/bin/initdb -D /
|
|
80
|
-
su - postgres -c "/usr/pgsql-16/bin/pg_ctl -D /
|
|
88
|
+
mkdir -p /workspace/pgsql/16/data && chown postgres:postgres /workspace/pgsql/16/data
|
|
89
|
+
su - postgres -c "/usr/pgsql-16/bin/initdb -D /workspace/pgsql/16/data"
|
|
90
|
+
su - postgres -c "/usr/pgsql-16/bin/pg_ctl -D /workspace/pgsql/16/data -l /workspace/pgsql/16/logfile start"
|
|
81
91
|
```
|
|
82
92
|
|
|
83
93
|
## Step 2: PostgREST (static build) + schema
|
|
@@ -87,8 +97,30 @@ static). **Dynamic Ubuntu builds do NOT work** — HCE glibc 2.34 is older than
|
|
|
87
97
|
Ubuntu 22.04's 2.35 and the binaries fail on load.
|
|
88
98
|
|
|
89
99
|
```bash
|
|
90
|
-
#
|
|
91
|
-
|
|
100
|
+
# Asset name has NO patch version: it is postgrest-v16.5-linux-static-aarch64.tar.xz
|
|
101
|
+
# (v16.4 likewise) — writing "v16.5.0" 404s and is easily misdiagnosed as a broken proxy.
|
|
102
|
+
# Verify the real asset name via the GitHub API before downloading:
|
|
103
|
+
curl -fsSL https://api.github.com/repos/PostgREST/postgrest/releases \
|
|
104
|
+
| grep -o '"name": *"postgrest-v16[^"]*aarch64[^"]*"'
|
|
105
|
+
# GitHub direct is slow from the sandbox; prefix proxies measure ~500KB/s (2026-10):
|
|
106
|
+
# https://ghfast.top/https://github.com/... or https://gh-proxy.com/https://github.com/...
|
|
107
|
+
# ⚠️ Those proxies are THIRD-PARTY: never extract their bytes unverified (supply-chain
|
|
108
|
+
# risk). Pull the official asset sha256 digest from the GitHub releases API, download
|
|
109
|
+
# through the proxy, and verify with sha256sum BEFORE extracting — this also catches
|
|
110
|
+
# partial downloads (a truncated tar.xz fails the check instead of a cryptic tar error).
|
|
111
|
+
PGRST_SHA256="$(curl -fsSL https://api.github.com/repos/PostgREST/postgrest/releases/tags/v16.5 \
|
|
112
|
+
| grep -A30 '"name": *"postgrest-v16.5-linux-static-aarch64.tar.xz"' \
|
|
113
|
+
| grep -o '"digest": *"sha256:[a-f0-9]*"' | head -1 \
|
|
114
|
+
| sed 's/.*sha256://; s/"$//')"
|
|
115
|
+
# ⚠️ The sed strips both the `sha256:` prefix and the closing quote.
|
|
116
|
+
# Using `cut` by delimiter instead would leave a trailing double-quote on the
|
|
117
|
+
# hash, making `sha256sum -c -` fail with "no properly formatted checksum
|
|
118
|
+
# lines found" even when the download is correct.
|
|
119
|
+
test -n "$PGRST_SHA256" # empty digest = API lookup failed; do NOT proceed unverified
|
|
120
|
+
curl -fsSL --http1.1 --max-time 240 -C - -o /tmp/pgrst.tar.xz \
|
|
121
|
+
"https://ghfast.top/https://github.com/PostgREST/postgrest/releases/download/v16.5/postgrest-v16.5-linux-static-aarch64.tar.xz"
|
|
122
|
+
echo "$PGRST_SHA256 /tmp/pgrst.tar.xz" | sha256sum -c - # must print ": OK" before tar
|
|
123
|
+
mkdir -p /opt/postgrest && tar -xJf /tmp/pgrst.tar.xz -C /opt/postgrest
|
|
92
124
|
|
|
93
125
|
cat > /opt/postgrest/pgrst.conf << 'PGRST_EOF'
|
|
94
126
|
db-uri = "postgres://api_user:<db-password>@localhost:5432/postgres"
|
|
@@ -97,8 +129,11 @@ db-anon-role = "api_user"
|
|
|
97
129
|
server-host = "127.0.0.1"
|
|
98
130
|
server-port = 3000
|
|
99
131
|
PGRST_EOF
|
|
132
|
+
# ⚠️ Via the MCP exec channel, do NOT build pgrst.conf / SQL inline (escaping breaks
|
|
133
|
+
# them — see field notes below): write the file locally and huaweicloud_sandbox_upload_file it.
|
|
100
134
|
|
|
101
|
-
# Schema + read-only API role (the anon role gates all writes)
|
|
135
|
+
# Schema + read-only API role (the anon role gates all writes).
|
|
136
|
+
# Same escaping trap: prefer a local schema.sql → upload_file → psql -f (field notes).
|
|
102
137
|
su - postgres -c "/usr/pgsql-16/bin/psql -c \"CREATE SCHEMA api; CREATE TABLE api.todos (id serial primary key, done boolean not null default false, task text not null); CREATE ROLE api_user LOGIN PASSWORD '<db-password>'; GRANT USAGE ON SCHEMA api TO api_user; GRANT SELECT ON ALL TABLES IN SCHEMA api TO api_user;\""
|
|
103
138
|
|
|
104
139
|
setsid nohup /opt/postgrest/postgrest /opt/postgrest/pgrst.conf > /tmp/pgrst.log 2>&1 < /dev/null &
|
|
@@ -145,5 +180,131 @@ devbridge host -p <port> -e 720
|
|
|
145
180
|
```
|
|
146
181
|
|
|
147
182
|
Verify end-to-end through the public URL: `GET /` (page, 200), `GET /api/todos`
|
|
148
|
-
(data, 200), `POST /api/todos` (401 — the anon role has SELECT
|
|
149
|
-
|
|
183
|
+
(data, 200), `POST /api/todos` (**401 by default** — the anon role has SELECT
|
|
184
|
+
only). To enable writes on one table, `GRANT INSERT ON api.todos TO api_user`
|
|
185
|
+
(never a broad grant to anon); after that targeted grant the same POST returns
|
|
186
|
+
**201**.
|
|
187
|
+
|
|
188
|
+
## Field notes (2026-10 retest): 5 measured traps
|
|
189
|
+
|
|
190
|
+
Re-measured 2026-10-23 on HCE 2.0 (aarch64, no systemd) with PG 16.15 +
|
|
191
|
+
PostgREST 16.5; all five traps reproduced and solved, end-to-end verified
|
|
192
|
+
(page 200 / API 200 / POST 401 anon-default, 201 after `GRANT INSERT` on
|
|
193
|
+
`api.todos`).
|
|
194
|
+
|
|
195
|
+
### 1. RPM sources: use the Aliyun mirror
|
|
196
|
+
|
|
197
|
+
`download.postgresql.org` and `repo.almalinux.org` measure **~8KB/s** from the
|
|
198
|
+
sandbox CN egress (the 6.8MB server RPM times out mid-transfer at 240s). The
|
|
199
|
+
Aliyun mirror completes in seconds:
|
|
200
|
+
|
|
201
|
+
- PG 16: `https://mirrors.aliyun.com/postgresql/repos/yum/16/redhat/rhel-8-aarch64/`
|
|
202
|
+
- libicu60: `https://mirrors.aliyun.com/almalinux/8/BaseOS/aarch64/os/Packages/`
|
|
203
|
+
- PostgREST: `ghfast.top` / `gh-proxy.com` prefix proxies (~500KB/s) — but see
|
|
204
|
+
trap 3 first: the asset name must be exact, and the proxy is third-party:
|
|
205
|
+
fetch the official GitHub asset digest and `sha256sum -c` the tarball before
|
|
206
|
+
extracting (see the Step 2 download block).
|
|
207
|
+
|
|
208
|
+
### 2. Cross-mirror resume corrupts RPMs
|
|
209
|
+
|
|
210
|
+
Resuming a partial download with `-C -` **from a different mirror** produces a
|
|
211
|
+
file that fails rpm verification (`Payload SHA256 digest: BAD`). When switching
|
|
212
|
+
sources, `rm` the partial file and re-download it in full — never resume across
|
|
213
|
+
mirrors.
|
|
214
|
+
|
|
215
|
+
### 3. PostgREST 404 is usually the asset name, not the proxy
|
|
216
|
+
|
|
217
|
+
The release asset is `postgrest-v16.5-linux-static-aarch64.tar.xz` — the version
|
|
218
|
+
has **no patch number** (v16.4 likewise); guessing `v16.5.0` returns 404 and
|
|
219
|
+
gets misdiagnosed as "proxy broken". Check the real name first:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
curl -fsSL https://api.github.com/repos/PostgREST/postgrest/releases \
|
|
223
|
+
| grep -o '"name": *"postgrest-v16[^"]*aarch64[^"]*"'
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 4. `upload_file` lands as 640 → silent schema failure → PGRST002
|
|
227
|
+
|
|
228
|
+
Files uploaded by root via `huaweicloud_sandbox_upload_file` arrive as
|
|
229
|
+
`rw-r-----` (640). `su - postgres -c "psql -f /tmp/schema.sql"` then fails with
|
|
230
|
+
`Permission denied`, the schema/role are **silently not created**, and
|
|
231
|
+
PostgREST starts but keeps logging
|
|
232
|
+
`PGRST002: Could not query the database for the schema cache`.
|
|
233
|
+
|
|
234
|
+
Fix: `chmod o+r` the uploaded file before `psql -f`. When troubleshooting
|
|
235
|
+
PGRST002, first confirm the schema/role actually exist (`\dn`, `\du`) — the
|
|
236
|
+
`psql -f` error may have scrolled out of the output tail you looked at.
|
|
237
|
+
|
|
238
|
+
### 5. MCP exec channel mangles nested quotes — upload files instead
|
|
239
|
+
|
|
240
|
+
Nested quotes / inline JSON (pgrst.conf, `psql -c` SQL, `curl -d '{...}'`) get
|
|
241
|
+
corrupted by the exec channel's multi-layer escaping (symptoms: POST 400, SQL
|
|
242
|
+
written wrong). The heredoc/inline `printf` snippets above are for a direct
|
|
243
|
+
shell; over MCP, always use the file-upload pattern:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# locally: write schema.sql / pgrst.conf / payload.json, then upload_file them, then on the sandbox:
|
|
247
|
+
chmod o+r /tmp/schema.sql && su - postgres -c "/usr/pgsql-16/bin/psql -f /tmp/schema.sql"
|
|
248
|
+
curl -s -X POST -H "Content-Type: application/json" -d @/tmp/payload.json http://127.0.0.1:3000/todos
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Sandbox Restart Recovery Checklist (2026-10)
|
|
252
|
+
|
|
253
|
+
A sandbox reboot rolls the **系统盘 (system disk)** back to the image state —
|
|
254
|
+
everything installed under `/`, `/usr`, `/etc`, `$HOME` is lost. Only
|
|
255
|
+
`/workspace` (the data disk) survives. Below is the measured recovery
|
|
256
|
+
checklist, assuming PG data was initialized on `/workspace/pgsql/16/data` per
|
|
257
|
+
Step 1 above.
|
|
258
|
+
|
|
259
|
+
### Lost on reboot (系统盘 — must rebuild)
|
|
260
|
+
|
|
261
|
+
| Component | Location | Recovery action |
|
|
262
|
+
| ---------------------- | ------------------------- | -------------------------------------------------------------------------------- |
|
|
263
|
+
| PostgreSQL 16 RPMs | `/usr/pgsql-16/` | Re-run the Step 1 `rpm -ivh --nodeps` block |
|
|
264
|
+
| Soname shims | `/usr/lib64/lib*.so.*` | Re-run the Step 1 symlink + `ldconfig` block |
|
|
265
|
+
| `postgres` user | `/etc/passwd` entry | `useradd -r -m postgres` then `chown postgres:postgres /workspace/pgsql/16/data` |
|
|
266
|
+
| PostgREST binary | `/opt/postgrest/` | Re-download + sha256-verify + extract (Step 2) |
|
|
267
|
+
| pgrst.conf | `/opt/postgrest/` | Re-upload via `huaweicloud_sandbox_upload_file` |
|
|
268
|
+
| nginx config | `/etc/nginx/conf.d/` | Re-create via `huaweicloud_sandbox_deploy_nginx` |
|
|
269
|
+
| DevBridge 0.2.x binary | `~/.huawei/bin/` (系统盘) | Re-install to `/workspace/.local/bin` (see #999) |
|
|
270
|
+
| DevBridge tunnel | in-memory | Re-run `huaweicloud_sandbox_expose_tunnel` |
|
|
271
|
+
| `/tmp` credentials | `/tmp/hw_creds.sh` etc. | Re-run `huaweicloud_sandbox_credentials` |
|
|
272
|
+
|
|
273
|
+
### Survives reboot (/workspace — no rebuild needed)
|
|
274
|
+
|
|
275
|
+
| Component | Location | Notes |
|
|
276
|
+
| ---------------------- | -------------------------- | -------------------------------------------- |
|
|
277
|
+
| Frontend pages | `/workspace/<repo>/` | Uploaded project persists |
|
|
278
|
+
| PG data directory | `/workspace/pgsql/16/data` | Schema, roles, tables, seed data ALL survive |
|
|
279
|
+
| DevBridge 0.2.x binary | `/workspace/.local/bin/` | If installed per #999 guidance |
|
|
280
|
+
|
|
281
|
+
Because PG data lives on `/workspace`, a restart does **NOT** require rebuilding
|
|
282
|
+
the schema (`schema.sql`) or re-seeding data — `initdb` is also unnecessary.
|
|
283
|
+
Only the PG server RPMs and the `postgres` user need rebuilding; then
|
|
284
|
+
`pg_ctl -D /workspace/pgsql/16/data start` resumes the surviving cluster
|
|
285
|
+
immediately.
|
|
286
|
+
|
|
287
|
+
### Write-permission GRANT rollback trap (POST 401 → GRANT → 201)
|
|
288
|
+
|
|
289
|
+
The `postgres` system user and PG RPMs live on the 系统盘, so after a reboot
|
|
290
|
+
you must recreate the user and re-install PG before `pg_ctl` can start the
|
|
291
|
+
surviving data directory. Once PG starts against the surviving
|
|
292
|
+
`/workspace/pgsql/16/data`, all roles and grants in the PG catalog are intact
|
|
293
|
+
— no re-grant is needed.
|
|
294
|
+
|
|
295
|
+
**However**, if you rebuild the schema from a `schema.sql` that only contains
|
|
296
|
+
`GRANT SELECT` (the read-only anon default), writes are blocked: `POST
|
|
297
|
+
/api/todos` returns **401**. The write grant (`GRANT INSERT, UPDATE, DELETE`)
|
|
298
|
+
was stored in the PG catalog; re-running a SELECT-only script overwrites it.
|
|
299
|
+
The measured fix (2026-10):
|
|
300
|
+
|
|
301
|
+
```sql
|
|
302
|
+
GRANT INSERT, UPDATE, DELETE ON api.todos TO api_user;
|
|
303
|
+
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA api TO api_user;
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
After this targeted re-grant the same `POST /api/todos` returns **201**
|
|
307
|
+
(measured 2026-10: POST 401 → `GRANT INSERT, UPDATE, DELETE` → POST 201).
|
|
308
|
+
This mirrors the Step 4 anon-role gating: `db-anon-role` is read-only by
|
|
309
|
+
default; targeted write grants must be re-applied after any schema rebuild.
|
|
310
|
+
Never grant broad write access to the anon role.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# 两池沙箱资源池口径(v3,2026-11 定稿)
|
|
2
|
+
|
|
3
|
+
> 权威实现:hdkitservice(pool_type 服务端权威解析 + 池感知复用 + 429 双错误码)+ 本插件 `sandbox-pool.mjs`。
|
|
4
|
+
> 本文件是口径快照,与实现冲突时以最新实测为准(基调:一切以实测为准,口头支持不作数)。
|
|
5
|
+
> 本版合并并取代 #1071 旧口径(非持久 3h 固定 / 持久 14 天保留 / 三信号 / 关机前通知均已作废)。
|
|
6
|
+
|
|
7
|
+
## 机制
|
|
8
|
+
|
|
9
|
+
- **池 = 平台预置模板**:非持久 `9a108ab1bc354bc4979b949b36e3c8c1` / 持久 `05860f507ee94930844907a3a136d1a7` / flavor 3U6G `23ebdfe3b2d34cc4b34a1aaf03d27c54`(服务端 `POOL_TEMPLATE_*` 环境变量维护)
|
|
10
|
+
- 客户端传 `pool_type`(ephemeral/persistent),**服务端权威映射** template_id;显式 `template_id` 优先(自定义模板)
|
|
11
|
+
- **无 persist_mode 请求参数**(需求方两次纠正);闲置语义由平台按模板配置,上游参数面仅 name/template_id/flavor_id/source/env/git
|
|
12
|
+
- 实例名前缀即池归属:`hcdke*`(非持久)/ `hcdkp*`(持久);同池才复用。遗留 `hcdk*` 老实例不参与池复用(老模板后续可能无对应资源池,处置待定)
|
|
13
|
+
|
|
14
|
+
## 两类沙箱
|
|
15
|
+
|
|
16
|
+
| 维度 | 非持久化 (ephemeral) | 持久化 (persistent) |
|
|
17
|
+
| -------- | --------------------------------------- | -------------------------------------------- |
|
|
18
|
+
| 定位 | 预览/试用/一次性任务/敏感即焚 | 开发工作台/带数据库项目/跨日评审展示 |
|
|
19
|
+
| 生命周期 | 闲置 30min 自动关机 + 1h 删除(已实测) | 闲置回收保留期上限 7 天(资源组 DB 硬约束) |
|
|
20
|
+
| 存储 | 无持久盘 | 挂 EVS 32G |
|
|
21
|
+
| 配额 | 每用户 1 台(同类复用) | 每用户 1 台(同类复用;可与 1 台非持久并存) |
|
|
22
|
+
|
|
23
|
+
## 生命周期(实测口径)
|
|
24
|
+
|
|
25
|
+
| 项 | 口径 | 状态 |
|
|
26
|
+
| --------------- | ---------------------------------------------- | ------------- |
|
|
27
|
+
| 非持久闲置策略 | 30min 自动关机 + 1h 删除(平台定时任务) | ✅ 已验证生效 |
|
|
28
|
+
| 持久闲置回收 | 保留期上限 7 天(原 14 天口径作废) | 平台侧 |
|
|
29
|
+
| 活性检测 | 当前仅 connect 单信号(三信号为后续诉求 G2) | 现状 |
|
|
30
|
+
| 删除/关机前通知 | 不支持(G6 诉求中)→ 客户端 TTL 播报为补偿方案 | 现状 |
|
|
31
|
+
| 两池实际差异 | 仅 EVS 32GiB 数据盘(非持久池无 disks 字段) | ✅ 已实证 |
|
|
32
|
+
|
|
33
|
+
## 容量规划(原始申请口径)
|
|
34
|
+
|
|
35
|
+
| 资源 | 申请容量 |
|
|
36
|
+
| ----------------- | ----------- |
|
|
37
|
+
| 非持久化 2U4G | 1000 实例 |
|
|
38
|
+
| 持久化 2U4G | 300 实例 |
|
|
39
|
+
| 持久化 4U8G | 200 实例 |
|
|
40
|
+
| overlayer | 5 GB / 实例 |
|
|
41
|
+
| EVS(持久化挂盘) | 300 TB 总量 |
|
|
42
|
+
|
|
43
|
+
> 注意:实际池 flavor 为 **3U6G**(需求方 2026-11-02 指定,尾号 54),上述 2U4G/4U8G 为原始申请口径,容量数字需按 3U6G 重新核算。
|
|
44
|
+
|
|
45
|
+
## 配额与错误码
|
|
46
|
+
|
|
47
|
+
- 每用户每类型 1 台(同类复用,ephemeral + persistent 可并存 1+1);账号并发上限 5
|
|
48
|
+
- 429 双错误码(均带 `Retry-After: 60`):
|
|
49
|
+
- `HDKIT_QUOTA_EXCEEDED`:用户配额满(上游 `HD.98320022`)→ 重试无效,引导释放/复用已有实例
|
|
50
|
+
- `HDKIT_CAPACITY_INSUFFICIENT`:池容量不足(上游 `HD.99003001`/`HD.99008001`/`HD.98330021`)→ 建议错峰重试
|
|
51
|
+
- 烧核:`HD.97520422` = 账号核心时长耗尽(沙箱运行消耗核时;客户端对含该码的错误输出友好播报)
|
|
52
|
+
|
|
53
|
+
## 烧核播报口径
|
|
54
|
+
|
|
55
|
+
沙箱消耗核时(烧核)时向用户播报:核时来源于**平台赠送 + 活动赚取**(非直接计费口径)。
|
|
56
|
+
|
|
57
|
+
## 客户端行为(本插件)
|
|
58
|
+
|
|
59
|
+
- `sandbox_connect` 传 `pool_type`;非法值本地即报错(不发无效请求);未传由服务端默认 ephemeral
|
|
60
|
+
- connect 返回值富化 `pool` 块(TTL 播报,仅服务端回显 pool_type 时);exec/upload/deploy/expose 返回值带 `poolMode`/`persistenceHint`
|
|
61
|
+
- 429 结构化 `remediation`(配额满/容量不足差异化引导步骤)+ `retryAfter`
|
|
62
|
+
- 钉扎(可选,运维场景):`HW_POOL_TEMPLATE_EPHEMERAL`/`HW_POOL_TEMPLATE_PERSISTENT` 环境变量——设置后客户端附带映射 template_id 上送;日常部署无需配置(模板 ID 由服务端权威维护)
|
|
63
|
+
|
|
64
|
+
## 平台侧关键依赖(G 清单,非 devkit 交付)
|
|
65
|
+
|
|
66
|
+
- G1 闲置删除策略配置(资源组,驱动 7 天上限回收)
|
|
67
|
+
- G2 活性检测(当前仅 connect 单信号;三信号为后续诉求)
|
|
68
|
+
- G3 状态查询 API(未落地,继续提)
|
|
69
|
+
- G4 销户开机处置(已完成待测试)
|
|
70
|
+
- G5 销户实例回收(已完成待测试)
|
|
71
|
+
- G6 删除/关机前通知(诉求中)
|
|
72
|
+
|
|
73
|
+
## 已知边界
|
|
74
|
+
|
|
75
|
+
- 池模板当前为**白名单条件实测**(仅对测试账号加白),公开上线后需复测模板 ID 与口径
|
|
76
|
+
- 上游 429 真实响应结构未实测:服务端映射先按已知错误码实现,联调实测后校准
|
|
77
|
+
- 沙箱实例状态机外的过渡态(`cde.1000/1002` 排队中)由服务端等待超时兜底
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { TOOL_DEFINITIONS, callTool } from './tools.mjs';
|
|
2
2
|
import { peekCachedUpdateInfo, applyUpdateHint, readInstalledVersion } from './update-check.mjs';
|
|
3
|
-
import { initTelemetry } from './telemetry/telemetry.mjs';
|
|
3
|
+
import { initTelemetry, flushEvents } from './telemetry/telemetry.mjs';
|
|
4
4
|
import { detectAgent } from './telemetry/agent-detect.mjs';
|
|
5
5
|
|
|
6
|
+
// #1014 P0: 领券类工具同步上报——callTool 完毕后 await flushEvents(),
|
|
7
|
+
// 防止进程提前退出导致领券遥测丢失。
|
|
8
|
+
const P0_SYNC_FLUSH_TOOLS = new Set(['huaweicloud_voucher_claim', 'huaweicloud_competition_voucher_claim']);
|
|
9
|
+
|
|
6
10
|
const pkgVersion = readInstalledVersion() || '0.0.0';
|
|
7
11
|
|
|
8
12
|
// 会话内首个非 check/upgrade 工具调用附加 _updateInfo,只消费一次。
|
|
@@ -78,6 +82,9 @@ export async function dispatch(method, params, opts = {}) {
|
|
|
78
82
|
throw invalidParamsError;
|
|
79
83
|
}
|
|
80
84
|
const result = await callTool(params.name, params.arguments || {});
|
|
85
|
+
if (P0_SYNC_FLUSH_TOOLS.has(params.name)) {
|
|
86
|
+
await flushEvents().catch(() => {});
|
|
87
|
+
}
|
|
81
88
|
const decorated = _decorateResult(sessionId, params.name, result);
|
|
82
89
|
return {
|
|
83
90
|
content: [
|