huaweicloud-devkit 1.1.3-next.0 → 1.1.3-next.1
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 +20 -3
- package/README.zh-CN.md +20 -3
- 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-obs/references/bucket-create.md +1 -0
- package/plugins/huaweicloud-core/skills/huawei-obs/references/static-website.md +2 -0
- package/plugins/huaweicloud-core/src/auth/reconcile.mjs +20 -5
- package/plugins/huaweicloud-core/src/tools.mjs +25 -1
- package/plugins/huaweicloud-core/src/update-check.mjs +3 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://github.com/huaweicloud/huaweicloud-devkit/discussions)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/huaweicloud/huaweicloud-devkit/actions/workflows/ci.yml)
|
|
6
|
-
[](https://www.npmjs.com/package/huaweicloud-devkit)
|
|
7
7
|
|
|
8
8
|
**[中文](README.zh-CN.md) | English**
|
|
9
9
|
|
|
@@ -246,7 +246,7 @@ Any agent that supports MCP can use the standard config:
|
|
|
246
246
|
|
|
247
247
|
No installation required — `npx` handles everything.
|
|
248
248
|
|
|
249
|
-
>
|
|
249
|
+
> For manual MCP registrations like this, do not put credentials in the config. `HW_ACCESS_KEY`/`HW_SECRET_KEY` are reserved for **platform/CI-injected** accounts (e.g. a DevSpace-managed default account) — configure your own account via `npx huaweicloud-devkit auth init` (the single entry point), and switch accounts at runtime with the `huaweicloud_auth_init` / `huaweicloud_auth_switch` MCP tools. See `plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md` for the full credential-resolution priority.
|
|
250
250
|
|
|
251
251
|
#### Connecting over Remote (HTTP)
|
|
252
252
|
|
|
@@ -284,7 +284,24 @@ npx --yes huaweicloud-devkit install-hcloud
|
|
|
284
284
|
npx --yes huaweicloud-devkit auth init
|
|
285
285
|
```
|
|
286
286
|
|
|
287
|
-
Synchronizes AK/SK to KooCLI, OBS, and sandbox APIs in one step.
|
|
287
|
+
Synchronizes AK/SK to KooCLI, OBS, and sandbox APIs in one step — this is the **single entry point**. Never hard-code AK/SK into agent or shell config.
|
|
288
|
+
|
|
289
|
+
**Account switching at runtime** (within an agent session): use the MCP tools `huaweicloud_auth_init` (in-memory, highest priority) or `huaweicloud_auth_switch` (actions: `temporary` / `persist` / `clear`). In sandbox/DevSpace environments where a default account is injected via `HW_ACCESS_KEY`/`HW_SECRET_KEY`, a plain `auth init` will not override it — use `huaweicloud_auth_switch action=persist` to make the session account win.
|
|
290
|
+
|
|
291
|
+
**Credential resolution priority** (highest first):
|
|
292
|
+
|
|
293
|
+
| # | Source | Set by |
|
|
294
|
+
| --- | ------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
295
|
+
| 1 | Runtime (session) credentials | `huaweicloud_auth_init` / `huaweicloud_auth_switch action=temporary` |
|
|
296
|
+
| 2 | S1 global file with `configuredBySession: true` | `huaweicloud_auth_switch action=persist` |
|
|
297
|
+
| 3 | Environment variables (`HW_ACCESS_KEY`/`HW_SECRET_KEY`) | platform/DevSpace-injected default account |
|
|
298
|
+
| 4 | CodeArts / CodeArts Work | `.codeartsdoer/mcp/mcp_settings.json` / `.codeartswork/mcp/mcp_settings.json` |
|
|
299
|
+
| 5 | S1 global file (no session flag) | `auth init` |
|
|
300
|
+
| 6 | KooCLI profile | `~/.hcloud/config.json` (KooCLI commands only) |
|
|
301
|
+
|
|
302
|
+
> **Security**: never put your own AK/SK into the MCP config `env` field — they'd be stored in plaintext and could leak if the config file is committed to git. `env` is for platform/CI injection only.
|
|
303
|
+
|
|
304
|
+
Full details: `plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md`.
|
|
288
305
|
|
|
289
306
|
### Install All Agents
|
|
290
307
|
|
package/README.zh-CN.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://github.com/huaweicloud/huaweicloud-devkit/discussions)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
[](https://github.com/huaweicloud/huaweicloud-devkit/actions/workflows/ci.yml)
|
|
6
|
-
[](https://www.npmjs.com/package/huaweicloud-devkit)
|
|
7
7
|
|
|
8
8
|
**中文 | [English](README.md)**
|
|
9
9
|
|
|
@@ -246,7 +246,7 @@ npx --yes huaweicloud-devkit uninstall --target atomcode
|
|
|
246
246
|
|
|
247
247
|
无需预安装 — `npx` 自动处理一切。
|
|
248
248
|
|
|
249
|
-
>
|
|
249
|
+
> 像上面这种手动 MCP 注册方式,请勿在配置里写凭据。`HW_ACCESS_KEY`/`HW_SECRET_KEY` 是保留给**平台/CI 注入**的账号用的(例如 DevSpace 托管的默认账号)——自己的账号统一通过 `npx huaweicloud-devkit auth init` 配置(唯一入口),会话内切换账号用 `huaweicloud_auth_init` / `huaweicloud_auth_switch` MCP 工具。完整凭据解析优先级见 `plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md`。
|
|
250
250
|
|
|
251
251
|
#### 通过 Remote(HTTP)连接
|
|
252
252
|
|
|
@@ -284,7 +284,24 @@ npx --yes huaweicloud-devkit install-hcloud
|
|
|
284
284
|
npx --yes huaweicloud-devkit auth init
|
|
285
285
|
```
|
|
286
286
|
|
|
287
|
-
一步同步 AK/SK 到 KooCLI、OBS
|
|
287
|
+
一步同步 AK/SK 到 KooCLI、OBS 和沙箱接口——这是**唯一入口**,切勿把 AK/SK 手写进 Agent 或 shell 配置。
|
|
288
|
+
|
|
289
|
+
**会话内切换账号**:使用 MCP 工具 `huaweicloud_auth_init`(内存态,优先级最高)或 `huaweicloud_auth_switch`(`temporary` / `persist` / `clear`)。在沙箱/DevSpace 环境中若默认账号经 `HW_ACCESS_KEY`/`HW_SECRET_KEY` 注入,单纯 `auth init` 无法覆盖——需 `huaweicloud_auth_switch action=persist` 让会话账号生效。
|
|
290
|
+
|
|
291
|
+
**凭据解析优先级**(从高到低):
|
|
292
|
+
|
|
293
|
+
| # | 来源 | 由谁设置 |
|
|
294
|
+
| --- | --------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
295
|
+
| 1 | 运行时(会话)凭据 | `huaweicloud_auth_init` / `huaweicloud_auth_switch action=temporary` |
|
|
296
|
+
| 2 | 带 `configuredBySession: true` 的 S1 全局文件 | `huaweicloud_auth_switch action=persist` |
|
|
297
|
+
| 3 | 环境变量(`HW_ACCESS_KEY`/`HW_SECRET_KEY`) | 平台/DevSpace 注入的默认账号 |
|
|
298
|
+
| 4 | CodeArts / CodeArts Work | `.codeartsdoer/mcp/mcp_settings.json` / `.codeartswork/mcp/mcp_settings.json` |
|
|
299
|
+
| 5 | S1 全局文件(无会话标记) | `auth init` |
|
|
300
|
+
| 6 | KooCLI profile | `~/.hcloud/config.json`(仅 KooCLI 命令) |
|
|
301
|
+
|
|
302
|
+
> **安全**:切勿把自己账号的 AK/SK 写入 MCP 配置的 `env` 字段——会以明文存储,配置文件提交 git 时即泄密;`env` 仅用于平台/CI 注入。
|
|
303
|
+
|
|
304
|
+
完整说明:`plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md`。
|
|
288
305
|
|
|
289
306
|
### 安装所有 Agent
|
|
290
307
|
|
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.3-next.
|
|
4
|
+
"version": "1.1.3-next.1",
|
|
5
5
|
"kooCliVersion": "7.2.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",
|
|
@@ -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.3-next.
|
|
20
|
+
"version": "1.1.3-next.1",
|
|
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.3-next.
|
|
23
|
+
"version": "1.1.3-next.1",
|
|
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.3-next.
|
|
20
|
+
"version": "1.1.3-next.1",
|
|
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-next.
|
|
3
|
+
"version": "1.1.3-next.1",
|
|
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-next.
|
|
3
|
+
"version": "1.1.3-next.1",
|
|
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.3-next.
|
|
5
|
+
"version": "1.1.3-next.1",
|
|
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.",
|
|
@@ -47,3 +47,4 @@ hcloud OBS stat obs://<bucket>
|
|
|
47
47
|
- Region is immutable after creation
|
|
48
48
|
- ACL does NOT cascade to objects — set both bucket-level and object-level access
|
|
49
49
|
- OBS uses separate credentials (`~/.obsutilconfig`, configure via `hcloud OBS config -i`)
|
|
50
|
+
- **Return code is unreliable for `mb`**: it can exit non-zero (e.g. 6) while the bucket is actually created (output still carries a request id). Confirm with `stat obs://<bucket>` / `OBS ls` instead of the exit code; re-running `mb` on the same name is idempotent.
|
|
@@ -54,3 +54,5 @@ curl http://my-static-site.obs-website.cn-north-4.myhuaweicloud.com
|
|
|
54
54
|
- **Always use `-f`**: Without `-f`, obsutil prompts "Please input (y/n)" on large uploads — Agent hangs (TIMEOUT).
|
|
55
55
|
- **Use `-flat` for root files**: Without `-flat`, `dist/` becomes `bucket/dist/` prefix. Static sites need files at bucket root.
|
|
56
56
|
- **Objects don't inherit bucket ACL**: Setting bucket to public-read does NOT make individual objects public. You must also set object-level ACL with `chattri obs://<bucket>/ -r -f -acl=public-read` or use `-acl=public-read` during upload.
|
|
57
|
+
- **`mb` may return a non-zero exit code even on success**: `hcloud OBS mb` occasionally exits with code 6 (or other non-zero) while the bucket is actually created — the output still contains a request id and subsequent `cp`/`chattri` succeed. Judge success by the response text (request id) and confirm with `hcloud OBS ls` / `stat obs://<bucket>`, NOT the exit code alone. `mb` is idempotent, so re-issuing the same bucket name is harmless.
|
|
58
|
+
- **Website endpoint is eventually consistent (~1 min)**: after `PUT /?website` returns 200, the website endpoint (`http://<bucket>.obs-website.<region>.myhuaweicloud.com`) may return 404 `NoSuchWebsiteConfiguration` for up to ~1 minute. This is propagation delay, NOT a configuration failure. Verify immediately via the object URL (`https://<bucket>.obs.<region>.myhuaweicloud.com/index.html`, works before the website endpoint), then poll the website endpoint with a short backoff until it returns 200 before reporting success.
|
|
@@ -45,15 +45,27 @@ export function readKooCliProfiles() {
|
|
|
45
45
|
const current = String(raw.current || 'default');
|
|
46
46
|
const profiles = Array.isArray(raw.profiles) ? raw.profiles : [];
|
|
47
47
|
const mtimeMs = statSync(configPath).mtimeMs;
|
|
48
|
+
// KooCLI 7.x stores AK/SK encrypted (authEncrypt=true): the on-disk values
|
|
49
|
+
// are ciphertext, so a fingerprint computed from them can never match the
|
|
50
|
+
// plaintext S1/S3 stores. Blind the comparable fields instead of treating
|
|
51
|
+
// ciphertext as a real credential and misreporting a S2 drift (#533).
|
|
52
|
+
// KooCLI serializes the flag as the string "true", not a boolean.
|
|
53
|
+
const encrypted = raw.authEncrypt === true || raw.authEncrypt === 'true';
|
|
48
54
|
return {
|
|
49
55
|
current,
|
|
50
56
|
mtimeMs,
|
|
51
57
|
configPath,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
authEncrypt: encrypted,
|
|
59
|
+
profiles: profiles.map((p) =>
|
|
60
|
+
encrypted
|
|
61
|
+
? { name: String(p.name || ''), fingerprint: '', accessKeyId: '', encrypted: true }
|
|
62
|
+
: {
|
|
63
|
+
name: String(p.name || ''),
|
|
64
|
+
fingerprint: fingerprint(p.accessKeyId, p.secretAccessKey),
|
|
65
|
+
accessKeyId: p.accessKeyId || '',
|
|
66
|
+
encrypted: false,
|
|
67
|
+
},
|
|
68
|
+
),
|
|
57
69
|
};
|
|
58
70
|
} catch {
|
|
59
71
|
return { error: 'KooCLI config parse failed' };
|
|
@@ -138,6 +150,9 @@ export function scanState() {
|
|
|
138
150
|
runtimeFingerprint,
|
|
139
151
|
},
|
|
140
152
|
kooCliCurrent: kooCli.error ? null : kooCli.current,
|
|
153
|
+
// S2 is encrypted storage (authEncrypt) → its fingerprint is unavailable,
|
|
154
|
+
// so the S2-current drift check is intentionally skipped (#533).
|
|
155
|
+
s2Encrypted: Boolean(!kooCli.error && kooCli.authEncrypt),
|
|
141
156
|
inconsistencies,
|
|
142
157
|
hasRuntime,
|
|
143
158
|
runtimeFingerprint,
|
|
@@ -1012,7 +1012,31 @@ function refreshUserHashAfterAuthChange({ regenerate = true } = {}) {
|
|
|
1012
1012
|
}
|
|
1013
1013
|
}
|
|
1014
1014
|
|
|
1015
|
-
|
|
1015
|
+
// Reject invalid numeric args up front instead of silently coercing them to
|
|
1016
|
+
// NaN (which downstream defaults would absorb as "no timeout set") — see #530.
|
|
1017
|
+
const NUMERIC_ARG_KEYS = ['timeoutMs', 'maxRetries', 'timeout_ms'];
|
|
1018
|
+
|
|
1019
|
+
function normalizeNumericArgs(args) {
|
|
1020
|
+
const out = { ...args };
|
|
1021
|
+
for (const key of NUMERIC_ARG_KEYS) {
|
|
1022
|
+
const value = out[key];
|
|
1023
|
+
if (value === undefined || value === null) continue;
|
|
1024
|
+
const num = Number(value);
|
|
1025
|
+
// timeouts must be positive; maxRetries may be 0 (means "no retries").
|
|
1026
|
+
const isRetries = key === 'maxRetries';
|
|
1027
|
+
const valid = Number.isFinite(num) && (isRetries ? Number.isSafeInteger(num) && num >= 0 : num > 0);
|
|
1028
|
+
if (!valid) {
|
|
1029
|
+
throw new Error(
|
|
1030
|
+
`Invalid parameter "${key}": expected a ${isRetries ? 'non-negative integer' : 'positive number'}, received ${JSON.stringify(value)}.`,
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
out[key] = num;
|
|
1034
|
+
}
|
|
1035
|
+
return out;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
export async function callTool(name, rawArgs = {}) {
|
|
1039
|
+
const args = normalizeNumericArgs(rawArgs);
|
|
1016
1040
|
const toolValue = toolInvokeValue(name, args);
|
|
1017
1041
|
trackToolInvoke(name, toolValue);
|
|
1018
1042
|
|
|
@@ -323,7 +323,9 @@ export async function upgradePackage({ target = 'all', version = 'latest' } = {}
|
|
|
323
323
|
return { success: false, error: 'version 参数仅支持 latest。目标版本由插件自动判定。' };
|
|
324
324
|
}
|
|
325
325
|
const { doQuery = queryDistTags, spawnFn = defaultSpawn } = options;
|
|
326
|
-
|
|
326
|
+
// Tests inject currentVersion explicitly - the repo package.json version changes
|
|
327
|
+
// between prerelease and stable lines, which must not flip the upgrade-tag logic.
|
|
328
|
+
const previousVersion = options.currentVersion || readInstalledVersion();
|
|
327
329
|
let distTags;
|
|
328
330
|
try {
|
|
329
331
|
distTags = await doQuery();
|