huaweicloud-devkit 1.0.2-next.13 → 1.0.2-next.18
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 +8 -28
- package/README.zh-CN.md +8 -28
- 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/.workbuddy-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/hooks/huaweicloud-safety.py +32 -9
- package/plugins/huaweicloud-core/openclaw.plugin.json +19 -0
- package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +16 -0
- package/plugins/huaweicloud-core/skills/huaweicloud-core/SKILL.md +1 -0
- package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +10 -7
- package/plugins/huaweicloud-core/src/auth/credentials.mjs +65 -0
- package/plugins/huaweicloud-core/src/mcp-server.mjs +17 -4
- package/plugins/huaweicloud-core/src/sandbox/hwlink-api.mjs +2 -2
- package/plugins/huaweicloud-core/src/setup-cli.mjs +9 -2
- package/plugins/huaweicloud-core/src/tools.mjs +32 -3
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
Help AI coding agents use Huawei Cloud safely and accurately — a single integration that gives agents cloud knowledge, CLI tooling, and safety guardrails.
|
|
10
10
|
|
|
11
|
-
Supports OpenCode,
|
|
11
|
+
Supports OpenCode, CodeArts Agent, WorkBuddy, DeepSeek Harness (DSH), and OfficeAce.
|
|
12
12
|
|
|
13
13
|
## Prerequisites
|
|
14
14
|
|
|
@@ -33,23 +33,6 @@ npx --yes huaweicloud-devkit update --target opencode
|
|
|
33
33
|
npx --yes huaweicloud-devkit uninstall --target opencode
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
### Codex
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npx --yes huaweicloud-devkit install --target codex
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
> The Codex CLI must be installed first.
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npx --yes huaweicloud-devkit doctor --target codex
|
|
46
|
-
npx --yes huaweicloud-devkit status --target codex
|
|
47
|
-
npx --yes huaweicloud-devkit update --target codex
|
|
48
|
-
npx --yes huaweicloud-devkit uninstall --target codex
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
> **Codex Desktop** (Windows): use `--target codex-desktop` with the same commands.
|
|
52
|
-
|
|
53
36
|
### CodeArts Agent
|
|
54
37
|
|
|
55
38
|
```bash
|
|
@@ -65,7 +48,7 @@ npx --yes huaweicloud-devkit update --target codearts
|
|
|
65
48
|
npx --yes huaweicloud-devkit uninstall --target codearts
|
|
66
49
|
```
|
|
67
50
|
|
|
68
|
-
> **Sandbox mode**: CodeArts defaults to sandbox mode which blocks KooCLI. `install-hcloud` detects this and shows how to resolve it — install KooCLI outside the sandbox terminal, or disable sandbox mode in CodeArts settings (Settings →
|
|
51
|
+
> **Sandbox mode**: CodeArts defaults to sandbox mode which blocks KooCLI. `install-hcloud` detects this and shows how to resolve it — install KooCLI outside the sandbox terminal, or disable sandbox mode in CodeArts settings (Settings → Chats → Agents Terminal Command Running Mode → Auto Running).
|
|
69
52
|
|
|
70
53
|
### WorkBuddy
|
|
71
54
|
|
|
@@ -116,26 +99,22 @@ npx --yes huaweicloud-devkit uninstall --target officeace
|
|
|
116
99
|
|
|
117
100
|
### Other Agents
|
|
118
101
|
|
|
119
|
-
|
|
102
|
+
Any agent that supports MCP can use the standard config:
|
|
120
103
|
|
|
121
104
|
```json
|
|
122
105
|
{
|
|
123
106
|
"mcpServers": {
|
|
124
107
|
"huaweicloud-devkit": {
|
|
125
|
-
"command": "
|
|
126
|
-
"args": ["
|
|
108
|
+
"command": "npx",
|
|
109
|
+
"args": ["-y", "-p", "huaweicloud-devkit@next", "huaweicloud-devkit-mcp"]
|
|
127
110
|
}
|
|
128
111
|
}
|
|
129
112
|
}
|
|
130
113
|
```
|
|
131
114
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
npx --yes huaweicloud-devkit install
|
|
136
|
-
```
|
|
115
|
+
No installation required — `npx` handles everything.
|
|
137
116
|
|
|
138
|
-
>
|
|
117
|
+
> Set `HW_ACCESS_KEY`/`HW_SECRET_KEY` in the MCP config `env` field for project-level credentials.
|
|
139
118
|
|
|
140
119
|
### Install KooCLI
|
|
141
120
|
|
|
@@ -171,6 +150,7 @@ npx --yes huaweicloud-devkit update --target all
|
|
|
171
150
|
- **Safety-first execution** — all write operations require explicit user approval; credentials and secrets are automatically redacted from output
|
|
172
151
|
- **Pre-execution risk checks** — public exposure, credential leaks, and destructive operations are caught before they run
|
|
173
152
|
- **Regional awareness** — auto-discovers available regions and checks service availability before creating resources
|
|
153
|
+
- **Sandbox (DevStation)** — temporary cloud runtime for web app deployment with instant public URL preview
|
|
174
154
|
|
|
175
155
|
## Supported Services
|
|
176
156
|
|
package/README.zh-CN.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
帮助 AI 编码助手安全、准确地使用华为云——一站式集成云知识、CLI 工具和安全护栏。
|
|
10
10
|
|
|
11
|
-
支持 OpenCode
|
|
11
|
+
支持 OpenCode、码道(CodeArts Agent)、WorkBuddy、DeepSeek Harness(DSH)、OfficeAce。
|
|
12
12
|
|
|
13
13
|
## 前置条件
|
|
14
14
|
|
|
@@ -33,23 +33,6 @@ npx --yes huaweicloud-devkit update --target opencode
|
|
|
33
33
|
npx --yes huaweicloud-devkit uninstall --target opencode
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
### Codex
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
npx --yes huaweicloud-devkit install --target codex
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
> 需要先安装 Codex CLI。
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npx --yes huaweicloud-devkit doctor --target codex
|
|
46
|
-
npx --yes huaweicloud-devkit status --target codex
|
|
47
|
-
npx --yes huaweicloud-devkit update --target codex
|
|
48
|
-
npx --yes huaweicloud-devkit uninstall --target codex
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
> **Codex Desktop**(Windows):将 `--target codex` 换成 `--target codex-desktop`,命令相同。
|
|
52
|
-
|
|
53
36
|
### CodeArts Agent(码道)
|
|
54
37
|
|
|
55
38
|
```bash
|
|
@@ -65,7 +48,7 @@ npx --yes huaweicloud-devkit update --target codearts
|
|
|
65
48
|
npx --yes huaweicloud-devkit uninstall --target codearts
|
|
66
49
|
```
|
|
67
50
|
|
|
68
|
-
> **沙箱模式**:码道默认沙箱模式会阻止 KooCLI 运行。`install-hcloud` 自动检测并给出指引——请在码道外终端安装使用 KooCLI,或在码道设置中关闭沙箱模式(设置 →
|
|
51
|
+
> **沙箱模式**:码道默认沙箱模式会阻止 KooCLI 运行。`install-hcloud` 自动检测并给出指引——请在码道外终端安装使用 KooCLI,或在码道设置中关闭沙箱模式(设置 → 对话流 → 智能体 终端命令运行模式 → 自动运行)。
|
|
69
52
|
|
|
70
53
|
### WorkBuddy
|
|
71
54
|
|
|
@@ -116,26 +99,22 @@ npx --yes huaweicloud-devkit uninstall --target officeace
|
|
|
116
99
|
|
|
117
100
|
### 其他 Agent
|
|
118
101
|
|
|
119
|
-
|
|
102
|
+
任何支持 MCP 协议的 Agent,直接使用标准 MCP 配置:
|
|
120
103
|
|
|
121
104
|
```json
|
|
122
105
|
{
|
|
123
106
|
"mcpServers": {
|
|
124
107
|
"huaweicloud-devkit": {
|
|
125
|
-
"command": "
|
|
126
|
-
"args": ["
|
|
108
|
+
"command": "npx",
|
|
109
|
+
"args": ["-y", "-p", "huaweicloud-devkit@next", "huaweicloud-devkit-mcp"]
|
|
127
110
|
}
|
|
128
111
|
}
|
|
129
112
|
}
|
|
130
113
|
```
|
|
131
114
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
```bash
|
|
135
|
-
npx --yes huaweicloud-devkit install
|
|
136
|
-
```
|
|
115
|
+
无需预安装 — `npx` 自动处理一切。
|
|
137
116
|
|
|
138
|
-
>
|
|
117
|
+
> 项目级 AK/SK 可通过 MCP 配置的 `env` 字段设置 `HW_ACCESS_KEY`/`HW_SECRET_KEY`。
|
|
139
118
|
|
|
140
119
|
### 安装 KooCLI
|
|
141
120
|
|
|
@@ -171,6 +150,7 @@ npx --yes huaweicloud-devkit update --target all
|
|
|
171
150
|
- **安全优先执行** — 所有写操作需用户明确批准;凭证和密钥自动脱敏
|
|
172
151
|
- **执行前风险检查** — 公网暴露、凭证泄露、破坏性操作在执行前即被拦截
|
|
173
152
|
- **区域感知** — 自动发现可用区域,创建资源前检查服务可用性
|
|
153
|
+
- **沙箱(DevStation)** — 临时云端运行环境,部署 Web 应用并即刻获得公网预览地址
|
|
174
154
|
|
|
175
155
|
## 支持的服务
|
|
176
156
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.0.2-next.
|
|
3
|
+
"version": "1.0.2-next.18",
|
|
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": [
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
},
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "https://github.com/huaweicloud/
|
|
18
|
+
"url": "https://github.com/huaweicloud/huaweicloud-devkit.git"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"test": "node --test",
|
|
@@ -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.0.2-next.
|
|
20
|
+
"version": "1.0.2-next.18",
|
|
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-core",
|
|
3
|
-
"version": "1.0.2-next.
|
|
3
|
+
"version": "1.0.2-next.18",
|
|
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",
|
|
@@ -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.0.2-next.
|
|
20
|
+
"version": "1.0.2-next.18",
|
|
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-core",
|
|
3
|
-
"version": "1.0.2-next.
|
|
3
|
+
"version": "1.0.2-next.18",
|
|
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",
|
|
@@ -18,15 +18,38 @@ from pathlib import Path
|
|
|
18
18
|
|
|
19
19
|
DENY_PREFIX = "Huawei Cloud safety hook blocked this action: "
|
|
20
20
|
RULES_PATH = Path(__file__).resolve().parents[1] / "safety" / "rules" / "cloud-risk-rules.json"
|
|
21
|
+
POLICY_PATH = Path(__file__).resolve().parents[1] / "safety" / "policy.json"
|
|
21
22
|
|
|
22
|
-
CONFIG_FILE_RE =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
CONFIG_FILE_RE = None
|
|
24
|
+
SECRET_READ_RE = None
|
|
25
|
+
WRITE_OPERATION_RE = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def load_policy():
|
|
29
|
+
global CONFIG_FILE_RE, SECRET_READ_RE, WRITE_OPERATION_RE
|
|
30
|
+
try:
|
|
31
|
+
with POLICY_PATH.open("r", encoding="utf-8") as file_obj:
|
|
32
|
+
policy = json.load(file_obj)
|
|
33
|
+
cred_patterns = policy.get("credentialFilePatterns", [])
|
|
34
|
+
if cred_patterns:
|
|
35
|
+
CONFIG_FILE_RE = re.compile("|".join(cred_patterns), re.I)
|
|
36
|
+
blocked_secrets = policy.get("blockedSecretOperations", [])
|
|
37
|
+
if blocked_secrets:
|
|
38
|
+
SECRET_READ_RE = re.compile("|".join(re.escape(op) for op in blocked_secrets), re.I)
|
|
39
|
+
write_prefixes = policy.get("writeOperationPrefixes", [])
|
|
40
|
+
if write_prefixes:
|
|
41
|
+
WRITE_OPERATION_RE = re.compile(r"\b(" + "|".join(write_prefixes) + r")\w*", re.I)
|
|
42
|
+
except Exception:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
load_policy()
|
|
47
|
+
|
|
48
|
+
ENV_DUMP_RE = re.compile(
|
|
49
|
+
r"(env|printenv|Get-ChildItem\s+Env:|gci\s+Env:|dir\s+Env:).*(HUAWEICLOUD|HWC_|HCLOUD|OS_)", re.I,
|
|
29
50
|
)
|
|
51
|
+
HCLOUD_RE = re.compile(r"(^|\s)hcloud(\.exe)?\s+", re.I)
|
|
52
|
+
READ_OPERATION_RE = re.compile(r"\b(List|Show|Get|Describe|NovaList|NovaShow)\w*", re.I)
|
|
30
53
|
READ_OPERATION_RE = re.compile(r"\b(List|Show|Get|Describe|NovaList|NovaShow)\w*", re.I)
|
|
31
54
|
|
|
32
55
|
|
|
@@ -117,11 +140,11 @@ def main():
|
|
|
117
140
|
tool_name = data.get("tool_name", "")
|
|
118
141
|
text = command_text(data.get("tool_input", {}))
|
|
119
142
|
|
|
120
|
-
if CONFIG_FILE_RE.search(text):
|
|
143
|
+
if CONFIG_FILE_RE and CONFIG_FILE_RE.search(text):
|
|
121
144
|
deny("reading Huawei Cloud credential/profile files can expose AK/SK or tokens. Use redacted toolkit tools.")
|
|
122
145
|
if ENV_DUMP_RE.search(text):
|
|
123
146
|
deny("dumping cloud credential environment variables is not allowed.")
|
|
124
|
-
if SECRET_READ_RE.search(text):
|
|
147
|
+
if SECRET_READ_RE and SECRET_READ_RE.search(text):
|
|
125
148
|
deny("direct secret value retrieval would put plaintext secrets into the agent context.")
|
|
126
149
|
denied_rule = first_denied_command_rule(text)
|
|
127
150
|
if denied_rule:
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "huaweicloud-devkit",
|
|
3
|
+
"displayName": "HuaweiCloud DevKit",
|
|
4
|
+
"version": "1.0.2-next.18",
|
|
5
|
+
"family": "bundle-plugin",
|
|
6
|
+
"bundleFormat": "codex",
|
|
7
|
+
"description": "Guide coding agents to use Huawei Cloud safely — KooCLI, APIs, SDKs, 28 MCP tools, skills, and safety guardrails.",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "HuaweiCloud Mate",
|
|
10
|
+
"url": "https://github.com/huaweicloud"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/huaweicloud/huaweicloud-devkit",
|
|
13
|
+
"repository": "https://github.com/huaweicloud/huaweicloud-devkit",
|
|
14
|
+
"license": "Apache-2.0",
|
|
15
|
+
"keywords": ["huaweicloud", "huawei-cloud", "koocli", "hcloud", "agent", "mcp", "api", "sdk", "skills", "cloud"],
|
|
16
|
+
"category": "Cloud",
|
|
17
|
+
"capabilities": ["Read", "Interactive"],
|
|
18
|
+
"brandColor": "#C7000B"
|
|
19
|
+
}
|
|
@@ -121,8 +121,24 @@ hcloud <Service> <ListOp> --cli-output=json --cli-query "items[?status=='ACTIVE'
|
|
|
121
121
|
hcloud <Service> <Op> --cli-debug=true
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
## Credential Resolution Priority
|
|
125
|
+
|
|
126
|
+
Credentials are resolved in this order (highest priority first):
|
|
127
|
+
|
|
128
|
+
| Priority | Source | Mechanism | Persistence |
|
|
129
|
+
| -------- | ----------------------- | ---------------------------------------------------------- | ------------------------------- |
|
|
130
|
+
| 1 | Runtime credentials | `huaweicloud_auth_init` tool | Memory (cleared on MCP restart) |
|
|
131
|
+
| 2 | Environment variables | `HW_ACCESS_KEY` / `HW_SECRET_KEY` | MCP process lifetime |
|
|
132
|
+
| 3 | CodeArts project config | `.codeartsdoer/mcp/mcp_settings.json` (project, then user) | File |
|
|
133
|
+
| 4 | Global config file | `~/.config/huaweicloud/credentials.json` | Permanent |
|
|
134
|
+
| 5 | KooCLI profile | `~/.hcloud/config.json` (KooCLI only) | Permanent |
|
|
135
|
+
|
|
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
|
+
|
|
124
138
|
## Preferred Toolkit Tools
|
|
125
139
|
|
|
140
|
+
- `huaweicloud_auth_init`
|
|
141
|
+
- `huaweicloud_auth_status`
|
|
126
142
|
- `huaweicloud_check_cli`
|
|
127
143
|
- `huaweicloud_show_profile_redacted`
|
|
128
144
|
- `huaweicloud_plan_cli_command`
|
|
@@ -100,6 +100,7 @@ When the intent is to **deploy, host, or preview a web app or static website** (
|
|
|
100
100
|
|
|
101
101
|
- Use huaweicloud_search_docs to discover skills covering a topic
|
|
102
102
|
- Use huaweicloud_retrieve_skill to load a full SKILL.md after routing
|
|
103
|
+
- Use huaweicloud_auth_init to switch credentials at runtime when different accounts co-exist in the same session
|
|
103
104
|
- If no built-in skill matches, consult huaweicloud-capability-discovery for external marketplace options
|
|
104
105
|
- Use huaweicloud_list_regions before creating regional resources
|
|
105
106
|
- Use huaweicloud_get_regional_availability when unsure about service-region pairs
|
|
@@ -123,13 +123,16 @@ function officeaceRegistered() {
|
|
|
123
123
|
let hasMcp = false;
|
|
124
124
|
const dbPath = officeaceSqlitePath();
|
|
125
125
|
if (existsSync(dbPath)) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
126
|
+
const nodeMajor = Number(process.versions.node.split('.')[0]);
|
|
127
|
+
if (nodeMajor >= 22) {
|
|
128
|
+
try {
|
|
129
|
+
const { DatabaseSync } = createRequire(import.meta.url)('node:sqlite');
|
|
130
|
+
const db = new DatabaseSync(dbPath, { readonly: true });
|
|
131
|
+
const row = db.prepare("SELECT enabled FROM mcp_connectors WHERE name = 'huaweicloud-devkit'").get();
|
|
132
|
+
db.close();
|
|
133
|
+
hasMcp = Boolean(row?.enabled);
|
|
134
|
+
} catch {}
|
|
135
|
+
}
|
|
133
136
|
}
|
|
134
137
|
|
|
135
138
|
const capFile = join(officeaceCapabilitiesDir(), 'capabilities.json');
|
|
@@ -84,6 +84,13 @@ export function resolveCredentials(options = {}) {
|
|
|
84
84
|
let securityToken = process.env.HW_SECURITY_TOKEN;
|
|
85
85
|
let region = process.env.HW_REGION || process.env.HUAWEICLOUD_REGION || '';
|
|
86
86
|
|
|
87
|
+
const codeartsCreds = isCodeArtsContext() ? readCodeArtsCredentials() : null;
|
|
88
|
+
if (codeartsCreds) {
|
|
89
|
+
if (!ak && codeartsCreds.ak) ak = codeartsCreds.ak;
|
|
90
|
+
if (!sk && codeartsCreds.sk) sk = codeartsCreds.sk;
|
|
91
|
+
if (!region && codeartsCreds.region) region = codeartsCreds.region;
|
|
92
|
+
}
|
|
93
|
+
|
|
87
94
|
const stored = readGlobalCredentials();
|
|
88
95
|
if (stored) {
|
|
89
96
|
if (!ak && stored.ak) ak = stored.ak;
|
|
@@ -101,3 +108,61 @@ export function resolveCredentials(options = {}) {
|
|
|
101
108
|
|
|
102
109
|
return { ak, sk, securityToken, region };
|
|
103
110
|
}
|
|
111
|
+
|
|
112
|
+
function isCodeArtsContext() {
|
|
113
|
+
return existsSync(join(process.cwd(), '.codeartsdoer')) || existsSync(join(homedir(), '.codeartsdoer'));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function readCodeArtsCredentials() {
|
|
117
|
+
const searchPaths = [
|
|
118
|
+
join(process.cwd(), '.codeartsdoer', 'mcp', 'mcp_settings.json'),
|
|
119
|
+
join(homedir(), '.codeartsdoer', 'mcp', 'mcp_settings.json'),
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
for (const path of searchPaths) {
|
|
123
|
+
try {
|
|
124
|
+
if (!existsSync(path)) continue;
|
|
125
|
+
const config = JSON.parse(readFileSync(path, 'utf8'));
|
|
126
|
+
const server = config?.mcpServers?.['huaweicloud-devkit'];
|
|
127
|
+
if (!server?.env) continue;
|
|
128
|
+
|
|
129
|
+
const ak = server.env.HW_ACCESS_KEY;
|
|
130
|
+
const sk = server.env.HW_SECRET_KEY;
|
|
131
|
+
if (ak && sk) {
|
|
132
|
+
return {
|
|
133
|
+
ak,
|
|
134
|
+
sk,
|
|
135
|
+
securityToken: server.env.HW_SECURITY_TOKEN || '',
|
|
136
|
+
region: server.env.HW_REGION || server.env.HUAWEICLOUD_REGION || '',
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
} catch {
|
|
140
|
+
// mcp_settings.json missing or invalid — skip
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let runtimeCredentials = null;
|
|
148
|
+
|
|
149
|
+
export function setRuntimeCredentials(ak, sk, securityToken, region) {
|
|
150
|
+
runtimeCredentials = { ak, sk, securityToken: securityToken || '', region: region || '' };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function clearRuntimeCredentials() {
|
|
154
|
+
runtimeCredentials = null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function resolveCredentialsWithRuntime(options = {}) {
|
|
158
|
+
if (runtimeCredentials) {
|
|
159
|
+
return {
|
|
160
|
+
ak: runtimeCredentials.ak,
|
|
161
|
+
sk: runtimeCredentials.sk,
|
|
162
|
+
securityToken: runtimeCredentials.securityToken,
|
|
163
|
+
region: runtimeCredentials.region,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return resolveCredentials(options);
|
|
168
|
+
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
3
2
|
import { stdin, stdout } from 'node:process';
|
|
4
|
-
import { rmSync, existsSync } from 'node:fs';
|
|
5
|
-
import { resolve, dirname } from 'node:path';
|
|
3
|
+
import { rmSync, existsSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { resolve, dirname, join } from 'node:path';
|
|
6
5
|
import { fileURLToPath } from 'node:url';
|
|
7
6
|
import { TOOL_DEFINITIONS, callTool } from './tools.mjs';
|
|
8
7
|
|
|
@@ -27,6 +26,20 @@ try {
|
|
|
27
26
|
if (existsSync(marker)) rmSync(marker, { force: true });
|
|
28
27
|
} catch {}
|
|
29
28
|
|
|
29
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
const pluginRoot = resolve(__dirname, '..');
|
|
31
|
+
const packageRoot = resolve(pluginRoot, '..', '..');
|
|
32
|
+
let pkgVersion = '0.0.0';
|
|
33
|
+
for (const base of [pluginRoot, packageRoot]) {
|
|
34
|
+
try {
|
|
35
|
+
const version = JSON.parse(readFileSync(join(base, 'package.json'), 'utf8')).version;
|
|
36
|
+
if (version) {
|
|
37
|
+
pkgVersion = version;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
} catch {}
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
let buffer = Buffer.alloc(0);
|
|
31
44
|
let useContentLengthFraming = true;
|
|
32
45
|
|
|
@@ -104,7 +117,7 @@ async function dispatch(method, params) {
|
|
|
104
117
|
},
|
|
105
118
|
serverInfo: {
|
|
106
119
|
name: 'huaweicloud-devkit',
|
|
107
|
-
version:
|
|
120
|
+
version: pkgVersion,
|
|
108
121
|
},
|
|
109
122
|
};
|
|
110
123
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { resolveCredentialsWithRuntime } from '../auth/credentials.mjs';
|
|
3
3
|
import { getProxyDispatcher } from '../proxy/proxy-agent.mjs';
|
|
4
4
|
|
|
5
5
|
const BASE_URL = process.env.HWLINK_ENDPOINT || 'https://devstation.myhuaweicloud.com';
|
|
@@ -77,7 +77,7 @@ function signRequest(method, path, query, body, ak, sk, securitytoken) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
export function getCredentials() {
|
|
80
|
-
const credentials =
|
|
80
|
+
const credentials = resolveCredentialsWithRuntime();
|
|
81
81
|
return { ak: credentials.ak, sk: credentials.sk, securitytoken: credentials.securityToken };
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -377,7 +377,7 @@ function printSandboxWarning(reason) {
|
|
|
377
377
|
console.log(`\x1b[31m 请任选其一继续:\x1b[0m`);
|
|
378
378
|
console.log(`\x1b[31m A. 在码道外的终端安装并使用 KooCLI (推荐):`);
|
|
379
379
|
console.log(`\x1b[31m https://support.huaweicloud.com/qs-hcli/hcli_02_003.html`);
|
|
380
|
-
console.log(`\x1b[31m B. 在码道设置中关闭沙箱模式后重试 (设置 →
|
|
380
|
+
console.log(`\x1b[31m B. 在码道设置中关闭沙箱模式后重试 (设置 → 对话流 → 智能体 终端命令运行模式 → 自动运行)`);
|
|
381
381
|
console.log(`\x1b[31m 关闭沙箱后重新运行: npx huaweicloud-devkit install-hcloud\x1b[0m`);
|
|
382
382
|
}
|
|
383
383
|
|
|
@@ -405,7 +405,12 @@ function copyDir(src, dest) {
|
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
function installRuntimeDeps(pluginsDir) {
|
|
408
|
-
const pkgJson = {
|
|
408
|
+
const pkgJson = {
|
|
409
|
+
name: 'huaweicloud-plugins',
|
|
410
|
+
version: pkgVersion,
|
|
411
|
+
type: 'module',
|
|
412
|
+
dependencies: { undici: '^8.10.0' },
|
|
413
|
+
};
|
|
409
414
|
mkdirSync(pluginsDir, { recursive: true });
|
|
410
415
|
writeFileSync(join(pluginsDir, 'package.json'), JSON.stringify(pkgJson, null, 2));
|
|
411
416
|
const r = spawnSync('npm', ['install', '--omit=dev'], {
|
|
@@ -1427,6 +1432,7 @@ async function installOfficeAce() {
|
|
|
1427
1432
|
copyDir(safetyDir, join(pluginDest, 'safety'));
|
|
1428
1433
|
console.log(` Safety Policy -> ${join(pluginDest, 'safety')}`);
|
|
1429
1434
|
|
|
1435
|
+
installRuntimeDeps(pluginDest);
|
|
1430
1436
|
ensureOfficeaceMcpInSqlite();
|
|
1431
1437
|
registerOfficeaceSkillEntries();
|
|
1432
1438
|
}
|
|
@@ -1444,6 +1450,7 @@ async function updateOfficeAce() {
|
|
|
1444
1450
|
console.log(` MCP Server updated -> ${join(pluginDest, 'src')}`);
|
|
1445
1451
|
copyDir(safetyDir, join(pluginDest, 'safety'));
|
|
1446
1452
|
console.log(` Safety Policy updated -> ${join(pluginDest, 'safety')}`);
|
|
1453
|
+
installRuntimeDeps(pluginDest);
|
|
1447
1454
|
ensureOfficeaceMcpInSqlite();
|
|
1448
1455
|
registerOfficeaceSkillEntries();
|
|
1449
1456
|
mkdirSync(pluginDest, { recursive: true });
|
|
@@ -16,7 +16,12 @@ import {
|
|
|
16
16
|
} from './sandbox/session-manager.mjs';
|
|
17
17
|
import { hdkitCheckUser, hdkitSignAgreement, hdkitConnect, hdkitCredentials } from './sandbox/hdkitservice-api.mjs';
|
|
18
18
|
import { getAuthStatus, syncAuth } from './auth/service.mjs';
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
readGlobalCredentials,
|
|
21
|
+
writeObsConfig as writeObsConfigFile,
|
|
22
|
+
setRuntimeCredentials,
|
|
23
|
+
clearRuntimeCredentials,
|
|
24
|
+
} from './auth/credentials.mjs';
|
|
20
25
|
|
|
21
26
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
27
|
const SKILLS_ROOT_DEV = join(__dirname, '..', 'skills');
|
|
@@ -404,6 +409,20 @@ export const TOOL_DEFINITIONS = [
|
|
|
404
409
|
},
|
|
405
410
|
},
|
|
406
411
|
},
|
|
412
|
+
{
|
|
413
|
+
name: 'huaweicloud_auth_init',
|
|
414
|
+
description:
|
|
415
|
+
'Set or clear runtime Huawei Cloud credentials (AK/SK) for this MCP session. Runtime credentials take highest priority over environment variables and config files for all subsequent API calls. Use when switching accounts within the same Agent session — call with AK/SK to switch, or with clear=true to fall back to env/file credentials.',
|
|
416
|
+
inputSchema: {
|
|
417
|
+
type: 'object',
|
|
418
|
+
properties: {
|
|
419
|
+
ak: { type: 'string', description: 'Huawei Cloud Access Key (required unless clear=true)' },
|
|
420
|
+
sk: { type: 'string', description: 'Huawei Cloud Secret Key (required unless clear=true)' },
|
|
421
|
+
region: { type: 'string', description: 'Default region (optional)' },
|
|
422
|
+
clear: { type: 'boolean', description: 'Set to true to clear runtime credentials and revert to env/file' },
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
},
|
|
407
426
|
{
|
|
408
427
|
name: 'huaweicloud_sandbox_exec_with_session',
|
|
409
428
|
description:
|
|
@@ -570,6 +589,16 @@ export async function callTool(name, args = {}) {
|
|
|
570
589
|
return getAuthStatus(args.target || 'all');
|
|
571
590
|
case 'huaweicloud_auth_sync':
|
|
572
591
|
return syncAuth(args.target || 'all');
|
|
592
|
+
case 'huaweicloud_auth_init':
|
|
593
|
+
if (args.clear) {
|
|
594
|
+
clearRuntimeCredentials();
|
|
595
|
+
return { status: 'cleared', message: 'Runtime credentials cleared. Fallback to env/file.' };
|
|
596
|
+
}
|
|
597
|
+
if (!args.ak || !args.sk) {
|
|
598
|
+
throw new Error('ak and sk are required. Set clear=true to clear runtime credentials.');
|
|
599
|
+
}
|
|
600
|
+
setRuntimeCredentials(args.ak, args.sk, undefined, args.region);
|
|
601
|
+
return { status: 'ok', message: 'Runtime credentials set for this MCP session.' };
|
|
573
602
|
case 'huaweicloud_sandbox_exec_with_session': {
|
|
574
603
|
const sandboxWsId2 = args.workspace_id || DEFAULT_WORKSPACE_ID;
|
|
575
604
|
const sandboxUser2 = args.username || 'root';
|
|
@@ -796,7 +825,7 @@ async function setupObsConfigFromHcloud(profile) {
|
|
|
796
825
|
const SERVICE_EXAMPLES = {
|
|
797
826
|
ECS: { list: 'ECS ListServersDetails', create: 'ECS CreateServers', show: 'IMS GlanceShowImage' },
|
|
798
827
|
VPC: { list: 'VPC ListVpcs', create: 'VPC CreateVpc', show: 'VPC ShowVpc' },
|
|
799
|
-
|
|
828
|
+
FUNCTIONGRAPH: {
|
|
800
829
|
list: 'FunctionGraph ListFunctions',
|
|
801
830
|
create: 'FunctionGraph CreateFunction',
|
|
802
831
|
show: 'FunctionGraph ShowFunctionConfig',
|
|
@@ -805,7 +834,7 @@ const SERVICE_EXAMPLES = {
|
|
|
805
834
|
OBS: { list: 'OBS ls', create: 'OBS mb obs://<bucket>', show: 'OBS stat obs://<bucket>/<key>' },
|
|
806
835
|
RDS: { list: 'RDS ListInstances', create: 'RDS CreateInstance', show: 'RDS ShowInstance' },
|
|
807
836
|
CES: { list: 'CES ListAlarms', create: 'CES CreateAlarm', show: 'CES ListMetrics' },
|
|
808
|
-
|
|
837
|
+
GAUSSDB: { list: 'GaussDB ListInstances', create: 'GaussDB CreateInstance', show: 'GaussDB ShowInstance' },
|
|
809
838
|
DDS: { list: 'DDS ListInstances', create: 'DDS CreateInstance', show: 'DDS ShowInstance' },
|
|
810
839
|
DCS: { list: 'DCS ListInstances', create: 'DCS CreateInstance', show: 'DCS ShowInstance' },
|
|
811
840
|
};
|