huaweicloud-devkit 1.1.1-next.1 → 1.1.1-next.3
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/safety/rules/cloud-risk-rules.json +22 -1
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/framework-commands.md +20 -0
- package/plugins/huaweicloud-core/skills/huawei-sandbox/references/nginx-templates.md +2 -1
- package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +1 -1
- package/plugins/huaweicloud-core/src/auth/credentials.mjs +6 -6
- package/plugins/huaweicloud-core/src/detect-framework.mjs +1 -1
- package/plugins/huaweicloud-core/src/hcloud-cli.mjs +84 -2
- package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +1 -0
- package/plugins/huaweicloud-core/src/setup-cli.mjs +18 -17
- package/plugins/huaweicloud-core/src/tools.mjs +13 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.1.1-next.
|
|
3
|
+
"version": "1.1.1-next.3",
|
|
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.1-next.
|
|
20
|
+
"version": "1.1.1-next.3",
|
|
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.1-next.
|
|
23
|
+
"version": "1.1.1-next.3",
|
|
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.1-next.
|
|
20
|
+
"version": "1.1.1-next.3",
|
|
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.1-next.
|
|
3
|
+
"version": "1.1.1-next.3",
|
|
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.1-next.
|
|
3
|
+
"version": "1.1.1-next.3",
|
|
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.1-next.
|
|
5
|
+
"version": "1.1.1-next.3",
|
|
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.",
|
|
@@ -214,7 +214,7 @@
|
|
|
214
214
|
},
|
|
215
215
|
{
|
|
216
216
|
"field": "text",
|
|
217
|
-
"regex": "(\\s--force|\\s-f\\s|\\s--recursive|\\s-r\\s
|
|
217
|
+
"regex": "(\\s--force|\\s-f\\s|\\s--recursive|\\s-r\\s)"
|
|
218
218
|
}
|
|
219
219
|
]
|
|
220
220
|
},
|
|
@@ -242,6 +242,27 @@
|
|
|
242
242
|
"message": "This hcloud command will delete, detach, or remove cloud resources. The operation may be irreversible.",
|
|
243
243
|
"remediation": "List the resources to be affected first, confirm with the user, and require explicit approval before executing any destructive operation."
|
|
244
244
|
},
|
|
245
|
+
{
|
|
246
|
+
"id": "hwc-destructive-delete-cascade",
|
|
247
|
+
"title": "Cascading cloud resource deletion",
|
|
248
|
+
"category": "destructive",
|
|
249
|
+
"severity": "warn",
|
|
250
|
+
"stages": ["command"],
|
|
251
|
+
"match": {
|
|
252
|
+
"all": [
|
|
253
|
+
{
|
|
254
|
+
"field": "text",
|
|
255
|
+
"regex": "(Delete|BatchDelete|Remove|\\brm\\b|delete)"
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"field": "text",
|
|
259
|
+
"regex": "(delete_publicip\\s*[=:]\\s*true|delete_volume\\s*[=:]\\s*true)"
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
"message": "This delete command will also remove associated resources (EIP, volume). Check that these should be deleted together.",
|
|
264
|
+
"remediation": "Confirm with the user whether to delete the associated resources, or set delete_publicip/delete_volume to false to keep them."
|
|
265
|
+
},
|
|
245
266
|
{
|
|
246
267
|
"id": "hwc-sandbox-missing-ttl",
|
|
247
268
|
"title": "Sandbox deployment missing cleanup metadata",
|
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
Maps web frameworks to install, build, serve commands and output directories for sandbox deployment.
|
|
4
4
|
|
|
5
|
+
## Architecture Compatibility
|
|
6
|
+
|
|
7
|
+
The sandbox runs **HCE OS on aarch64**. Frameworks that depend on native binaries (e.g., `@swc/core`, `esbuild`, `sharp`, `prisma`) may fail to install or build inside the sandbox since prebuilt binaries target x86_64 by default.
|
|
8
|
+
|
|
9
|
+
**Recommended strategy**: build locally (x86_64) then upload the dist output to the sandbox for serving.
|
|
10
|
+
|
|
11
|
+
| Dependency | Frameworks Affected | Mitigation |
|
|
12
|
+
| ---------------- | ------------------------ | ------------------------------------- |
|
|
13
|
+
| `@swc/core` | Taro, Next.js 13+ | Pre-build locally, upload dist |
|
|
14
|
+
| `esbuild` | Vite, Nuxt, uni-app | Usually has aarch64 binary; try build |
|
|
15
|
+
| `sharp` | Gatsby, Next.js images | Pre-build locally, upload dist |
|
|
16
|
+
| `prisma` | Next.js, Nuxt (database) | Use `binaryTargets = ["linux-arm64"]` |
|
|
17
|
+
| `node-gyp` (C++) | node-sass, bcrypt | `build-essential` is pre-installed |
|
|
18
|
+
|
|
19
|
+
**Pre-build workflow**:
|
|
20
|
+
|
|
21
|
+
1. Build on local machine (x86_64): `npm install && npm run build`
|
|
22
|
+
2. Use `huaweicloud_sandbox_connect` with git config (auto-transfers code) or `huaweicloud_sandbox_upload_project` to upload dist
|
|
23
|
+
3. Deploy with nginx static/SPA template — no native deps needed at runtime
|
|
24
|
+
|
|
5
25
|
## SSR Frameworks
|
|
6
26
|
|
|
7
27
|
| Framework | Install | Build | Serve | Output Dir | Port | Nginx |
|
|
@@ -64,7 +64,7 @@ NGINX_EOF
|
|
|
64
64
|
sudo nginx -s reload 2>/dev/null || sudo nginx
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
## Template 3: Static Site (
|
|
67
|
+
## Template 3: Static Site (with clean URL support)
|
|
68
68
|
|
|
69
69
|
Use for: Hugo, Hexo, plain static HTML
|
|
70
70
|
|
|
@@ -76,6 +76,7 @@ server {
|
|
|
76
76
|
index index.html;
|
|
77
77
|
|
|
78
78
|
location / {
|
|
79
|
+
try_files $uri $uri.html $uri/ =404;
|
|
79
80
|
autoindex off;
|
|
80
81
|
}
|
|
81
82
|
|
|
@@ -82,7 +82,7 @@ function codeartsRegistered() {
|
|
|
82
82
|
function codeartsWorkRegistered() {
|
|
83
83
|
const path = join(baseHome(), '.codeartswork', 'mcp', 'mcp_settings.json');
|
|
84
84
|
const cfg = readJsonSafe(path);
|
|
85
|
-
return Boolean(cfg?.
|
|
85
|
+
return Boolean(cfg?.mcp?.['huaweicloud-devkit']);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
function workbuddyRegistered() {
|
|
@@ -164,16 +164,16 @@ function readCodeArtsCredentials() {
|
|
|
164
164
|
try {
|
|
165
165
|
if (existsSync(path)) {
|
|
166
166
|
const config = JSON.parse(readFileSync(path, 'utf8'));
|
|
167
|
-
const server = config?.
|
|
168
|
-
if (server?.
|
|
169
|
-
const ak = server.
|
|
170
|
-
const sk = server.
|
|
167
|
+
const server = config?.mcp?.['huaweicloud-devkit'];
|
|
168
|
+
if (server?.environment) {
|
|
169
|
+
const ak = server.environment.HW_ACCESS_KEY;
|
|
170
|
+
const sk = server.environment.HW_SECRET_KEY;
|
|
171
171
|
if (ak && sk) {
|
|
172
172
|
return {
|
|
173
173
|
ak,
|
|
174
174
|
sk,
|
|
175
|
-
securityToken: server.
|
|
176
|
-
region: server.
|
|
175
|
+
securityToken: server.environment.HW_SECURITY_TOKEN || '',
|
|
176
|
+
region: server.environment.HW_REGION || server.environment.HUAWEICLOUD_REGION || '',
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
179
|
}
|
|
@@ -244,7 +244,7 @@ function readVitepressOutDir(projectPath) {
|
|
|
244
244
|
if (!existsSync(configPath)) continue;
|
|
245
245
|
try {
|
|
246
246
|
const content = readFileSync(configPath, 'utf8');
|
|
247
|
-
const match = content.match(/outDir\s*:\s*['"]([^'"]+)['"]
|
|
247
|
+
const match = content.match(/outDir\s*:\s*['"`]?([^'"`\s,}]+)['"`]?/);
|
|
248
248
|
if (match) return match[1];
|
|
249
249
|
} catch {}
|
|
250
250
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
@@ -51,11 +51,92 @@ function saveLargeOutput(rawStdout) {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function preflightSecurityGroupCheck(normalizedArgs) {
|
|
55
|
+
const service = normalizedArgs[0];
|
|
56
|
+
const operation = normalizedArgs[1];
|
|
57
|
+
if (service !== 'ECS' || !/CreateServers|RunInstances/i.test(operation)) return [];
|
|
58
|
+
|
|
59
|
+
const sgIds = [];
|
|
60
|
+
for (const arg of normalizedArgs) {
|
|
61
|
+
const m = arg.match(/^--security_group_id(\.\d+)?=(.+)/);
|
|
62
|
+
if (m) sgIds.push(m[2]);
|
|
63
|
+
}
|
|
64
|
+
if (sgIds.length === 0) return [];
|
|
65
|
+
|
|
66
|
+
const findings = [];
|
|
67
|
+
for (const sgId of sgIds) {
|
|
68
|
+
try {
|
|
69
|
+
const hcloudBin = process.env.HCLOUD_BIN || 'hcloud';
|
|
70
|
+
const r = spawnSync(hcloudBin, ['VPC', 'ListSecurityGroupRules', `--security_group_id=${sgId}`], {
|
|
71
|
+
shell: false,
|
|
72
|
+
windowsHide: true,
|
|
73
|
+
stdio: 'pipe',
|
|
74
|
+
timeout: 20000,
|
|
75
|
+
});
|
|
76
|
+
const stdout = (r.stdout || '').toString();
|
|
77
|
+
if (r.status !== 0 || !stdout.includes('security_group_rules')) continue;
|
|
78
|
+
|
|
79
|
+
const bracketIdx = stdout.indexOf('{');
|
|
80
|
+
const jsonText = bracketIdx >= 0 ? stdout.slice(bracketIdx) : stdout;
|
|
81
|
+
const data = JSON.parse(jsonText);
|
|
82
|
+
const rules = data?.security_group_rules || [];
|
|
83
|
+
|
|
84
|
+
for (const rule of rules) {
|
|
85
|
+
const direction = rule.direction || '';
|
|
86
|
+
const remoteIp = rule.remote_ip_prefix || rule.remote_address_group_id || '';
|
|
87
|
+
const portMin = String(rule.port_range_min || rule.multiport || '');
|
|
88
|
+
const portMax = String(rule.port_range_max || rule.multiport || '');
|
|
89
|
+
const protocol = (rule.protocol || '').toLowerCase();
|
|
90
|
+
if (direction !== 'ingress') continue;
|
|
91
|
+
if (remoteIp !== '0.0.0.0/0' && remoteIp !== '::/0') continue;
|
|
92
|
+
if (protocol === 'icmp' || protocol === 'icmpv6') {
|
|
93
|
+
findings.push({
|
|
94
|
+
severity: 'warn',
|
|
95
|
+
title: `Security group ${sgId}: ICMP open to public`,
|
|
96
|
+
message: `安全组 ${sgId} 对公网开放了 ICMP (ping),可能被用于探测。是否继续?`,
|
|
97
|
+
});
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const sensitivePorts = ['22', '3389', '3306', '5432', '6379', '9200', '27017', '8080', '8443'];
|
|
101
|
+
const port = portMin || portMax;
|
|
102
|
+
if (port && sensitivePorts.includes(port)) {
|
|
103
|
+
findings.push({
|
|
104
|
+
severity: 'deny',
|
|
105
|
+
title: `Security group ${sgId}: port ${port} open to public`,
|
|
106
|
+
message: `安全组 ${sgId} 已对公网开放 ${port} 端口(${protocol || 'TCP'})。确认继续创建 ECS?`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch (error) {
|
|
111
|
+
// Preflight failed silently; don't block the plan
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return findings;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function applyPreflightFindings(classification, sgFindings) {
|
|
118
|
+
if (!sgFindings || sgFindings.length === 0) return classification;
|
|
119
|
+
const hasDeny = sgFindings.some((f) => f.severity === 'deny');
|
|
120
|
+
if (hasDeny) {
|
|
121
|
+
return {
|
|
122
|
+
...classification,
|
|
123
|
+
decision: 'deny',
|
|
124
|
+
risk: 'public_exposure',
|
|
125
|
+
reason: sgFindings[0].message,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return classification;
|
|
129
|
+
}
|
|
130
|
+
|
|
54
131
|
export function planHcloudCommand(args, options = {}) {
|
|
55
132
|
const normalizedArgs = Array.isArray(args) ? args.map(String) : [];
|
|
56
133
|
const classification = classifyHcloudArgs(normalizedArgs, options);
|
|
57
134
|
const command = ['hcloud', ...normalizedArgs].map((arg) => quoteShellArg(arg)).join(' ');
|
|
58
135
|
const warnings = planningWarnings(normalizedArgs);
|
|
136
|
+
const sgFindings = preflightSecurityGroupCheck(normalizedArgs);
|
|
137
|
+
if (sgFindings.length > 0) {
|
|
138
|
+
for (const f of sgFindings) warnings.push(f);
|
|
139
|
+
}
|
|
59
140
|
const paramValidation = validateRequiredParams(normalizedArgs);
|
|
60
141
|
if (paramValidation.missing.length > 0) {
|
|
61
142
|
warnings.push('Missing required parameters: ' + paramValidation.missing.join(', '));
|
|
@@ -69,7 +150,8 @@ export function planHcloudCommand(args, options = {}) {
|
|
|
69
150
|
command: redactOutput(command),
|
|
70
151
|
executableBlock: redactOutput(command),
|
|
71
152
|
warnings,
|
|
72
|
-
classification,
|
|
153
|
+
classification: applyPreflightFindings(classification, sgFindings),
|
|
154
|
+
sgFindings,
|
|
73
155
|
approvalToken: createApprovalToken(normalizedArgs),
|
|
74
156
|
safeToRun: classification.decision === 'allow',
|
|
75
157
|
};
|
|
@@ -1272,36 +1272,37 @@ function codeartsStatus() {
|
|
|
1272
1272
|
function registerCodeartsWorkMcp() {
|
|
1273
1273
|
const configPath = codeartsWorkMcpSettingsFile();
|
|
1274
1274
|
const mcpPath = join(codeartsWorkPluginsDir(), 'src', 'mcp-server.mjs').replace(/\\/g, '/');
|
|
1275
|
-
const
|
|
1275
|
+
const environment = { HUAWEICLOUD_AGENT_TOOLKIT_MODE: 'local' };
|
|
1276
1276
|
const hcloudBin = findHcloudBin();
|
|
1277
|
-
if (hcloudBin)
|
|
1277
|
+
if (hcloudBin) environment.HCLOUD_BIN = hcloudBin.replace(/\\/g, '/');
|
|
1278
1278
|
let config = {};
|
|
1279
1279
|
if (existsSync(configPath)) {
|
|
1280
1280
|
try {
|
|
1281
1281
|
config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
1282
1282
|
} catch {
|
|
1283
1283
|
console.log(
|
|
1284
|
-
` \x1b[33m[WARN]\x1b[0m Could not parse ${configPath}. Skipping MCP config write; ensure "
|
|
1284
|
+
` \x1b[33m[WARN]\x1b[0m Could not parse ${configPath}. Skipping MCP config write; ensure "mcp.huaweicloud-devkit" points to ${mcpPath}.`,
|
|
1285
1285
|
);
|
|
1286
1286
|
return;
|
|
1287
1287
|
}
|
|
1288
|
-
const existing = config.
|
|
1288
|
+
const existing = config.mcp?.['huaweicloud-devkit'];
|
|
1289
1289
|
if (
|
|
1290
1290
|
existing &&
|
|
1291
|
-
existing.
|
|
1292
|
-
Array.isArray(existing.
|
|
1293
|
-
existing.
|
|
1291
|
+
existing.type === 'local' &&
|
|
1292
|
+
Array.isArray(existing.command) &&
|
|
1293
|
+
existing.command[0] === 'node' &&
|
|
1294
|
+
existing.command[1] === mcpPath &&
|
|
1294
1295
|
existing.timeout === 300000
|
|
1295
1296
|
) {
|
|
1296
1297
|
console.log(` MCP config unchanged: ${configPath}`);
|
|
1297
1298
|
return;
|
|
1298
1299
|
}
|
|
1299
1300
|
}
|
|
1300
|
-
config.
|
|
1301
|
-
config.
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1301
|
+
config.mcp = config.mcp || {};
|
|
1302
|
+
config.mcp['huaweicloud-devkit'] = {
|
|
1303
|
+
type: 'local',
|
|
1304
|
+
command: ['node', mcpPath],
|
|
1305
|
+
environment,
|
|
1305
1306
|
enabled: true,
|
|
1306
1307
|
timeout: 300000,
|
|
1307
1308
|
};
|
|
@@ -1369,9 +1370,9 @@ function uninstallCodeArtsWork() {
|
|
|
1369
1370
|
try {
|
|
1370
1371
|
config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
1371
1372
|
} catch {}
|
|
1372
|
-
if (config.
|
|
1373
|
-
delete config.
|
|
1374
|
-
if (Object.keys(config.
|
|
1373
|
+
if (config.mcp?.['huaweicloud-devkit']) {
|
|
1374
|
+
delete config.mcp['huaweicloud-devkit'];
|
|
1375
|
+
if (Object.keys(config.mcp).length === 0) delete config.mcp;
|
|
1375
1376
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
1376
1377
|
console.log(` Config cleaned: ${configPath}`);
|
|
1377
1378
|
}
|
|
@@ -1399,7 +1400,7 @@ function codeartsWorkStatus() {
|
|
|
1399
1400
|
try {
|
|
1400
1401
|
const config = JSON.parse(readFileSync(codeartsWorkMcpSettingsFile(), 'utf8'));
|
|
1401
1402
|
console.log(
|
|
1402
|
-
` MCP config: ${config.
|
|
1403
|
+
` MCP config: ${config.mcp?.['huaweicloud-devkit'] ? '\x1b[32mConfigured\x1b[0m' : '\x1b[31mNot configured\x1b[0m'}`,
|
|
1403
1404
|
);
|
|
1404
1405
|
} catch {
|
|
1405
1406
|
console.log(` MCP config: \x1b[31mInvalid\x1b[0m`);
|
|
@@ -3146,7 +3147,7 @@ async function cmdDoctor() {
|
|
|
3146
3147
|
if (!mcpConfigured && existsSync(codeartsWorkCfg)) {
|
|
3147
3148
|
try {
|
|
3148
3149
|
const cfg = JSON.parse(readFileSync(codeartsWorkCfg, 'utf8'));
|
|
3149
|
-
if (cfg.
|
|
3150
|
+
if (cfg.mcp && cfg.mcp['huaweicloud-devkit']) {
|
|
3150
3151
|
mcpConfigured = true;
|
|
3151
3152
|
mcpCfgTarget = 'CodeArts Work';
|
|
3152
3153
|
}
|
|
@@ -734,7 +734,8 @@ export const TOOL_DEFINITIONS = [
|
|
|
734
734
|
},
|
|
735
735
|
{
|
|
736
736
|
name: 'huaweicloud_voucher_status',
|
|
737
|
-
description:
|
|
737
|
+
description:
|
|
738
|
+
'查询代金券领取状态。用户首次使用、开始会话或询问插件能力时,应主动调用本工具检查:未领取(claimed=false)则主动提示可领取一张代金券;已领取(claimed=true)则不提示、不打扰。',
|
|
738
739
|
inputSchema: {
|
|
739
740
|
type: 'object',
|
|
740
741
|
properties: {
|
|
@@ -1054,6 +1055,9 @@ export async function callTool(name, args = {}) {
|
|
|
1054
1055
|
try {
|
|
1055
1056
|
await execOneShot(devStageId, 'devbridge delete-all 2>/dev/null || true', 'root', 15000);
|
|
1056
1057
|
} catch {}
|
|
1058
|
+
try {
|
|
1059
|
+
await execWithSession(devStageId, 'export PATH=$HOME/.huawei/bin${PATH:+:$PATH}', 'root', 10000);
|
|
1060
|
+
} catch {}
|
|
1057
1061
|
await transferGitRepo(args, devStageId, connectResult);
|
|
1058
1062
|
}
|
|
1059
1063
|
return connectResult;
|
|
@@ -1326,7 +1330,14 @@ async function runApprovedCommand(args = {}) {
|
|
|
1326
1330
|
}
|
|
1327
1331
|
const providedArgs = Array.isArray(args.args) ? args.args.map(String) : [];
|
|
1328
1332
|
if (JSON.stringify(storedArgs) !== JSON.stringify(providedArgs)) {
|
|
1329
|
-
|
|
1333
|
+
const redactedStored = redactSecrets(storedArgs);
|
|
1334
|
+
const redactedProvided = redactSecrets(providedArgs);
|
|
1335
|
+
if (JSON.stringify(redactedStored) !== JSON.stringify(redactedProvided)) {
|
|
1336
|
+
throw new Error(
|
|
1337
|
+
'Provided args do not match the approved plan. Use the exact args from the plan. ' +
|
|
1338
|
+
'If the plan shows <redacted> for passwords or secrets, replace <redacted> with the actual values in approvedCommand.',
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1330
1341
|
}
|
|
1331
1342
|
const strictPlan = planHcloudCommand(providedArgs, { allowWrites: false });
|
|
1332
1343
|
const result = await runHcloud(providedArgs, {
|