huaweicloud-devkit 1.0.2-dev.9 → 1.0.2-next.0
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/.agents/plugins/marketplace.json +20 -20
- package/LICENSE +201 -201
- package/README.md +163 -138
- package/README.zh-CN.md +161 -138
- package/bin/setup.cjs +8 -8
- package/integrations/opencode/commands/huaweicloud-doctor.md +14 -14
- package/integrations/opencode/opencode.json +14 -14
- package/integrations/opencode/skills/huaweicloud-core/SKILL.md +32 -32
- package/package.json +46 -44
- package/plugins/huaweicloud-core/.claude-plugin/plugin.json +44 -44
- package/plugins/huaweicloud-core/.codex-plugin/plugin.json +43 -43
- package/plugins/huaweicloud-core/.cursor-plugin/plugin.json +44 -44
- package/plugins/huaweicloud-core/.mcp.json +15 -15
- package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +44 -44
- package/plugins/huaweicloud-core/hooks/hooks.json +26 -26
- package/plugins/huaweicloud-core/hooks/huaweicloud-safety.py +136 -136
- package/plugins/huaweicloud-core/safety/policy.json +99 -99
- package/plugins/huaweicloud-core/safety/rules/cloud-risk-rules.json +199 -199
- package/plugins/huaweicloud-core/skills/huawei-apig/SKILL.md +164 -164
- package/plugins/huaweicloud-core/skills/huawei-billing/SKILL.md +48 -48
- package/plugins/huaweicloud-core/skills/huawei-cbr/SKILL.md +50 -50
- package/plugins/huaweicloud-core/skills/huawei-cce/SKILL.md +101 -101
- package/plugins/huaweicloud-core/skills/huawei-cloud-eye/SKILL.md +90 -90
- package/plugins/huaweicloud-core/skills/huawei-cloud-find-skills/SKILL.md +190 -190
- package/plugins/huaweicloud-core/skills/huawei-cloud-find-skills/scripts/search-skills.mjs +124 -124
- package/plugins/huaweicloud-core/skills/huawei-cts/SKILL.md +55 -55
- package/plugins/huaweicloud-core/skills/huawei-dds-dcs/SKILL.md +70 -70
- package/plugins/huaweicloud-core/skills/huawei-deployment/SKILL.md +56 -56
- package/plugins/huaweicloud-core/skills/huawei-dew/SKILL.md +97 -97
- package/plugins/huaweicloud-core/skills/huawei-dew/references/csms-usage.md +29 -29
- package/plugins/huaweicloud-core/skills/huawei-dew/references/kms-usage.md +23 -23
- package/plugins/huaweicloud-core/skills/huawei-ecs/SKILL.md +185 -185
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/create-instance.md +133 -133
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/evs.md +31 -31
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/flavors.md +55 -55
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/troubleshooting.md +52 -52
- package/plugins/huaweicloud-core/skills/huawei-functiongraph/SKILL.md +131 -131
- package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/apig-event-format.md +58 -58
- package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/create-function.md +71 -71
- package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/deploy-workflow.md +119 -119
- package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/triggers.md +142 -142
- package/plugins/huaweicloud-core/skills/huawei-gaussdb/SKILL.md +56 -56
- package/plugins/huaweicloud-core/skills/huawei-getting-started/SKILL.md +65 -65
- package/plugins/huaweicloud-core/skills/huawei-iam/SKILL.md +111 -111
- package/plugins/huaweicloud-core/skills/huawei-iam/references/policy-examples.md +122 -122
- package/plugins/huaweicloud-core/skills/huawei-iam/references/quick-ref.md +56 -56
- package/plugins/huaweicloud-core/skills/huawei-modelarts/SKILL.md +65 -65
- package/plugins/huaweicloud-core/skills/huawei-obs/SKILL.md +133 -127
- package/plugins/huaweicloud-core/skills/huawei-obs/references/bucket-create.md +49 -49
- package/plugins/huaweicloud-core/skills/huawei-obs/references/bucket-lifecycle.md +26 -26
- package/plugins/huaweicloud-core/skills/huawei-obs/references/common-pitfalls.md +100 -100
- package/plugins/huaweicloud-core/skills/huawei-obs/references/single-file-share.md +40 -40
- package/plugins/huaweicloud-core/skills/huawei-obs/references/static-website.md +56 -56
- package/plugins/huaweicloud-core/skills/huawei-rds/SKILL.md +224 -224
- package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +135 -134
- package/plugins/huaweicloud-core/skills/huawei-smn-dms/SKILL.md +69 -69
- package/plugins/huaweicloud-core/skills/huawei-vpc/SKILL.md +84 -84
- package/plugins/huaweicloud-core/skills/huawei-vpc/references/network.md +76 -76
- package/plugins/huaweicloud-core/skills/huawei-vpc/references/security-group.md +59 -59
- package/plugins/huaweicloud-core/skills/huawei-vpc/references/subnet.md +50 -50
- package/plugins/huaweicloud-core/skills/huawei-waf-aad/SKILL.md +63 -63
- package/plugins/huaweicloud-core/skills/huaweicloud-api-and-sdk/SKILL.md +56 -56
- package/plugins/huaweicloud-core/skills/huaweicloud-api-and-sdk/agents/openai.yaml +4 -4
- package/plugins/huaweicloud-core/skills/huaweicloud-capability-discovery/SKILL.md +51 -47
- package/plugins/huaweicloud-core/skills/huaweicloud-capability-discovery/agents/openai.yaml +4 -4
- package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +128 -128
- package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/agents/openai.yaml +4 -4
- package/plugins/huaweicloud-core/skills/huaweicloud-core/SKILL.md +110 -95
- package/plugins/huaweicloud-core/skills/huaweicloud-core/agents/openai.yaml +4 -4
- package/plugins/huaweicloud-core/skills/huaweicloud-core/references/report-issue.md +19 -19
- package/plugins/huaweicloud-core/skills/huaweicloud-core/references/select.md +27 -27
- package/plugins/huaweicloud-core/skills/huaweicloud-safety/SKILL.md +60 -60
- package/plugins/huaweicloud-core/skills/huaweicloud-safety/agents/openai.yaml +4 -4
- package/plugins/huaweicloud-core/skills/huaweicloud-troubleshooting/SKILL.md +83 -83
- package/plugins/huaweicloud-core/skills/huaweicloud-troubleshooting/agents/openai.yaml +4 -4
- package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +105 -87
- package/plugins/huaweicloud-core/src/auth/credentials.mjs +95 -95
- package/plugins/huaweicloud-core/src/auth/service.mjs +63 -63
- package/plugins/huaweicloud-core/src/hcloud-cli.mjs +265 -265
- package/plugins/huaweicloud-core/src/mcp-server.mjs +129 -129
- package/plugins/huaweicloud-core/src/proxy/proxy-agent.mjs +155 -0
- package/plugins/huaweicloud-core/src/proxy/proxy-config.mjs +87 -0
- package/plugins/huaweicloud-core/src/risk-rule-engine.mjs +137 -137
- package/plugins/huaweicloud-core/src/safety-policy.mjs +302 -302
- package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +91 -87
- package/plugins/huaweicloud-core/src/sandbox/hwlink-api.mjs +162 -153
- package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +112 -105
- package/plugins/huaweicloud-core/src/search-market.mjs +174 -169
- package/plugins/huaweicloud-core/src/setup-cli.mjs +2017 -1594
- package/plugins/huaweicloud-core/src/tools.mjs +1008 -993
- package/plugins/huaweicloud-core/src/ws-exec/hwlink-exec-client.js +427 -427
- package/plugins/huaweicloud-core/src/ws-exec/hwlink-fair-queue.js +132 -132
- package/plugins/huaweicloud-core/src/ws-exec/hwlink-multiplexer.js +227 -227
- package/plugins/huaweicloud-core/src/ws-exec/hwlink-packet.js +202 -202
- package/plugins/huaweicloud-core/src/ws-exec/hwlink-terminal-channel.js +158 -158
- package/plugins/huaweicloud-core/src/ws-exec/index.js +19 -19
- package/plugins/huaweicloud-core/src/ws-exec/ws-exec-client.js +338 -338
|
@@ -1,993 +1,1008 @@
|
|
|
1
|
-
import { planHcloudCommand, runHcloud } from './hcloud-cli.mjs';
|
|
2
|
-
import { classifyTextCommand, redactSecrets } from './safety-policy.mjs';
|
|
3
|
-
import { evaluateArtifacts, evaluateCommandRisk, evaluateDeployPlan } from './risk-rule-engine.mjs';
|
|
4
|
-
import { readFileSync, readdirSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
5
|
-
import { join, dirname } from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { homedir } from 'node:os';
|
|
8
|
-
import { searchMarketplace } from './search-market.mjs';
|
|
9
|
-
import { execWithSession, closeSession, DEFAULT_WORKSPACE_ID } from './sandbox/session-manager.mjs';
|
|
10
|
-
import { hdkitCheckUser, hdkitSignAgreement, hdkitConnect, hdkitCredentials } from './sandbox/hdkitservice-api.mjs';
|
|
11
|
-
import { getAuthStatus, syncAuth } from './auth/service.mjs';
|
|
12
|
-
import { readGlobalCredentials, writeObsConfig as writeObsConfigFile } from './auth/credentials.mjs';
|
|
13
|
-
|
|
14
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
-
const SKILLS_ROOT_DEV = join(__dirname, '..', 'skills');
|
|
16
|
-
function opencodeSkillsDir() {
|
|
17
|
-
const home = homedir();
|
|
18
|
-
return join(home, '.config', 'opencode', 'skills');
|
|
19
|
-
}
|
|
20
|
-
function codeartsSkillsDir() {
|
|
21
|
-
const home = homedir();
|
|
22
|
-
return join(home, '.codeartsdoer', 'skills');
|
|
23
|
-
}
|
|
24
|
-
function workbuddySkillsDir() {
|
|
25
|
-
const home = homedir();
|
|
26
|
-
return join(home, '.workbuddy', 'skills');
|
|
27
|
-
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return SKILLS_ROOT_DEV;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
type: '
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
type: '
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
return
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
const
|
|
558
|
-
if (
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
const
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if (
|
|
677
|
-
throw new Error('
|
|
678
|
-
}
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
{ keywords: ['
|
|
700
|
-
{ keywords: ['
|
|
701
|
-
{ keywords: ['
|
|
702
|
-
{ keywords: ['
|
|
703
|
-
{ keywords: ['
|
|
704
|
-
{ keywords: ['
|
|
705
|
-
{ keywords: ['
|
|
706
|
-
{ keywords: ['
|
|
707
|
-
{ keywords: ['
|
|
708
|
-
{ keywords: ['
|
|
709
|
-
{ keywords: ['
|
|
710
|
-
{ keywords: ['
|
|
711
|
-
{ keywords: ['
|
|
712
|
-
{ keywords: ['
|
|
713
|
-
{ keywords: ['
|
|
714
|
-
]
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
const
|
|
723
|
-
const
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
'
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
const
|
|
864
|
-
const
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
}
|
|
1
|
+
import { planHcloudCommand, runHcloud } from './hcloud-cli.mjs';
|
|
2
|
+
import { classifyTextCommand, redactSecrets } from './safety-policy.mjs';
|
|
3
|
+
import { evaluateArtifacts, evaluateCommandRisk, evaluateDeployPlan } from './risk-rule-engine.mjs';
|
|
4
|
+
import { readFileSync, readdirSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
5
|
+
import { join, dirname } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { homedir } from 'node:os';
|
|
8
|
+
import { searchMarketplace } from './search-market.mjs';
|
|
9
|
+
import { execWithSession, closeSession, DEFAULT_WORKSPACE_ID } from './sandbox/session-manager.mjs';
|
|
10
|
+
import { hdkitCheckUser, hdkitSignAgreement, hdkitConnect, hdkitCredentials } from './sandbox/hdkitservice-api.mjs';
|
|
11
|
+
import { getAuthStatus, syncAuth } from './auth/service.mjs';
|
|
12
|
+
import { readGlobalCredentials, writeObsConfig as writeObsConfigFile } from './auth/credentials.mjs';
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const SKILLS_ROOT_DEV = join(__dirname, '..', 'skills');
|
|
16
|
+
function opencodeSkillsDir() {
|
|
17
|
+
const home = homedir();
|
|
18
|
+
return join(home, '.config', 'opencode', 'skills');
|
|
19
|
+
}
|
|
20
|
+
function codeartsSkillsDir() {
|
|
21
|
+
const home = homedir();
|
|
22
|
+
return join(home, '.codeartsdoer', 'skills');
|
|
23
|
+
}
|
|
24
|
+
function workbuddySkillsDir() {
|
|
25
|
+
const home = homedir();
|
|
26
|
+
return join(home, '.workbuddy', 'skills');
|
|
27
|
+
}
|
|
28
|
+
function dshSkillsDir() {
|
|
29
|
+
const home = process.env.DSH_HOME || join(homedir(), '.dsh');
|
|
30
|
+
return join(home, 'skills');
|
|
31
|
+
}
|
|
32
|
+
function resolveSkillsRoot() {
|
|
33
|
+
if (existsSync(SKILLS_ROOT_DEV)) return SKILLS_ROOT_DEV;
|
|
34
|
+
if (existsSync(dshSkillsDir())) return dshSkillsDir();
|
|
35
|
+
if (existsSync(codeartsSkillsDir())) return codeartsSkillsDir();
|
|
36
|
+
if (existsSync(opencodeSkillsDir())) return opencodeSkillsDir();
|
|
37
|
+
if (existsSync(workbuddySkillsDir())) return workbuddySkillsDir();
|
|
38
|
+
return SKILLS_ROOT_DEV;
|
|
39
|
+
}
|
|
40
|
+
const SKILLS_ROOT = resolveSkillsRoot();
|
|
41
|
+
|
|
42
|
+
export const TOOL_DEFINITIONS = [
|
|
43
|
+
{
|
|
44
|
+
name: 'huaweicloud_check_cli',
|
|
45
|
+
description: 'Check whether Huawei Cloud KooCLI hcloud is installed. Returns redacted output.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'huaweicloud_plan_cli_command',
|
|
53
|
+
description: 'Classify and plan a Huawei Cloud hcloud command without executing it.',
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: 'object',
|
|
56
|
+
required: ['args'],
|
|
57
|
+
properties: {
|
|
58
|
+
args: {
|
|
59
|
+
type: 'array',
|
|
60
|
+
items: { type: 'string' },
|
|
61
|
+
description: 'hcloud arguments, excluding the hcloud executable.',
|
|
62
|
+
},
|
|
63
|
+
allowWrites: {
|
|
64
|
+
type: 'boolean',
|
|
65
|
+
description: 'Only true after explicit user approval for this exact operation.',
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'huaweicloud_run_readonly_command',
|
|
72
|
+
description: 'Run a read-only hcloud command through the toolkit safety policy and redact output.',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
required: ['args'],
|
|
76
|
+
properties: {
|
|
77
|
+
args: {
|
|
78
|
+
type: 'array',
|
|
79
|
+
items: { type: 'string' },
|
|
80
|
+
},
|
|
81
|
+
timeoutMs: {
|
|
82
|
+
type: 'number',
|
|
83
|
+
description: 'Optional timeout in milliseconds. Defaults to 60000.',
|
|
84
|
+
},
|
|
85
|
+
maxRetries: {
|
|
86
|
+
type: 'number',
|
|
87
|
+
description: 'Optional retry count for transient network errors. Defaults to 1.',
|
|
88
|
+
},
|
|
89
|
+
cwd: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
description: 'Optional working directory for the hcloud process.',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'huaweicloud_list_operations',
|
|
98
|
+
description: 'List KooCLI operations for a Huawei Cloud service by running local/read-only hcloud <Service> --help.',
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
required: ['service'],
|
|
102
|
+
properties: {
|
|
103
|
+
service: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
description: 'KooCLI service name, such as ECS, VPC, IMS, OBS, RDS, or CDN.',
|
|
106
|
+
},
|
|
107
|
+
timeoutMs: {
|
|
108
|
+
type: 'number',
|
|
109
|
+
description: 'Optional timeout in milliseconds. Defaults to 60000.',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'huaweicloud_run_approved_command',
|
|
116
|
+
description: 'Run a write-capable hcloud command only after the exact command has been shown and explicitly approved by the user.',
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: 'object',
|
|
119
|
+
required: ['args', 'approvedCommand', 'approvedByUser'],
|
|
120
|
+
properties: {
|
|
121
|
+
args: {
|
|
122
|
+
type: 'array',
|
|
123
|
+
items: { type: 'string' },
|
|
124
|
+
description: 'hcloud arguments, excluding the hcloud executable.',
|
|
125
|
+
},
|
|
126
|
+
approvedCommand: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
description: 'The exact command string previously shown to the user.',
|
|
129
|
+
},
|
|
130
|
+
approvedByUser: {
|
|
131
|
+
type: 'boolean',
|
|
132
|
+
description: 'Must be true only after the user explicitly approves this exact command.',
|
|
133
|
+
},
|
|
134
|
+
timeoutMs: {
|
|
135
|
+
type: 'number',
|
|
136
|
+
description: 'Optional timeout in milliseconds. Defaults to 60000.',
|
|
137
|
+
},
|
|
138
|
+
maxRetries: {
|
|
139
|
+
type: 'number',
|
|
140
|
+
description: 'Optional retry count for transient network errors. Defaults to 1.',
|
|
141
|
+
},
|
|
142
|
+
cwd: {
|
|
143
|
+
type: 'string',
|
|
144
|
+
description: 'Optional working directory for the hcloud process.',
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'huaweicloud_show_profile_redacted',
|
|
151
|
+
description: 'Inspect a KooCLI profile through hcloud configure show and return only redacted output.',
|
|
152
|
+
inputSchema: {
|
|
153
|
+
type: 'object',
|
|
154
|
+
properties: {
|
|
155
|
+
profile: {
|
|
156
|
+
type: 'string',
|
|
157
|
+
description: 'Optional KooCLI profile name.',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: 'huaweicloud_hook_check_command',
|
|
164
|
+
description: 'Check a planned shell or hcloud command against Huawei Cloud hook risk rules without executing it.',
|
|
165
|
+
inputSchema: {
|
|
166
|
+
type: 'object',
|
|
167
|
+
required: ['command'],
|
|
168
|
+
properties: {
|
|
169
|
+
command: { type: 'string', description: 'The exact command text to inspect.' },
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: 'huaweicloud_hook_check_artifacts',
|
|
175
|
+
description: 'Check generated code, IaC, policy, or config artifacts against Huawei Cloud hook risk rules.',
|
|
176
|
+
inputSchema: {
|
|
177
|
+
type: 'object',
|
|
178
|
+
required: ['artifacts'],
|
|
179
|
+
properties: {
|
|
180
|
+
artifacts: {
|
|
181
|
+
type: 'array',
|
|
182
|
+
items: {
|
|
183
|
+
type: 'object',
|
|
184
|
+
required: ['path', 'content'],
|
|
185
|
+
properties: {
|
|
186
|
+
path: { type: 'string' },
|
|
187
|
+
content: { type: 'string' },
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'huaweicloud_hook_check_deploy_plan',
|
|
196
|
+
description: 'Check a structured or textual deployment plan for Huawei Cloud sandbox, exposure, IAM, and cost risks.',
|
|
197
|
+
inputSchema: {
|
|
198
|
+
type: 'object',
|
|
199
|
+
required: ['plan'],
|
|
200
|
+
properties: {
|
|
201
|
+
plan: {
|
|
202
|
+
description: 'Deployment plan as an object, array, or string.',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: 'huaweicloud_service_catalog',
|
|
209
|
+
description: 'Return the recommended capability sources for Huawei Cloud agent tasks.',
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: 'object',
|
|
212
|
+
properties: {
|
|
213
|
+
intent: {
|
|
214
|
+
type: 'string',
|
|
215
|
+
description: 'Developer intent to route, such as deploy app, use API, debug error, or inspect resources.',
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'huaweicloud_explain_error',
|
|
222
|
+
description: 'Explain a Huawei Cloud CLI, API, SDK, or agent workflow error and suggest next diagnostic steps.',
|
|
223
|
+
inputSchema: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: {
|
|
226
|
+
service: { type: 'string' },
|
|
227
|
+
errorCode: { type: 'string' },
|
|
228
|
+
message: { type: 'string' },
|
|
229
|
+
requestId: { type: 'string' },
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: 'huaweicloud_search_docs',
|
|
235
|
+
description: 'Search across Huawei Cloud SKILL.md files and local documentation. Returns top 10 relevant results with source, name, snippet, and relevance score. Use when the agent needs to discover which skill covers a topic, or when uncertain about API parameters, quotas, or limitations.',
|
|
236
|
+
inputSchema: {
|
|
237
|
+
type: 'object',
|
|
238
|
+
required: ['query'],
|
|
239
|
+
properties: {
|
|
240
|
+
query: { type: 'string', description: 'Search query across skill descriptions and documentation.' },
|
|
241
|
+
topic: { type: 'string', description: 'Optional filter: all | ecs | obs | vpc | iam | rds | cce | modelarts | dew. Defaults to all.' },
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'huaweicloud_retrieve_skill',
|
|
247
|
+
description: 'Retrieve a full SKILL.md by skill name. Returns the complete skill content plus list of reference files. Use when the agent has identified which skill to load and needs the full procedure.',
|
|
248
|
+
inputSchema: {
|
|
249
|
+
type: 'object',
|
|
250
|
+
required: ['name'],
|
|
251
|
+
properties: {
|
|
252
|
+
name: { type: 'string', description: 'Skill name, e.g., huaweicloud-core, huawei-ecs, huawei-obs.' },
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: 'huaweicloud_list_regions',
|
|
258
|
+
description: 'List available Huawei Cloud regions. Returns region IDs, display names, and endpoints. Use when the agent needs to discover available regions before creating resources.',
|
|
259
|
+
inputSchema: {
|
|
260
|
+
type: 'object',
|
|
261
|
+
properties: {},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: 'huaweicloud_get_regional_availability',
|
|
266
|
+
description: 'Check if a specific Huawei Cloud service is available in a target region. Use before creating resources to prevent failures from regional unavailability.',
|
|
267
|
+
inputSchema: {
|
|
268
|
+
type: 'object',
|
|
269
|
+
required: ['service', 'region'],
|
|
270
|
+
properties: {
|
|
271
|
+
service: { type: 'string', description: 'Service name: ecs, obs, rds, gaussdb, cce, modelarts, functiongraph, etc.' },
|
|
272
|
+
region: { type: 'string', description: 'Region ID: cn-south-1, cn-north-4, ap-southeast-3, etc.' },
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
name: 'huaweicloud_search_marketplace',
|
|
278
|
+
description: 'Search the Huawei Cloud agent skill marketplace for available skills. Returns scored results with names, categories, and descriptions. Use when built-in skills are insufficient or the user asks what skills exist.',
|
|
279
|
+
inputSchema: {
|
|
280
|
+
type: 'object',
|
|
281
|
+
properties: {
|
|
282
|
+
query: { type: 'string', description: 'Search query across skill name, description, triggers, and service.' },
|
|
283
|
+
category: { type: 'string', description: 'Optional category filter: computing, storage, network, security, devtools, monitoring, etc.' },
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: 'huaweicloud_setup_obs_config',
|
|
289
|
+
description: 'Synchronize KooCLI credentials to OBS config (~/.obsutilconfig). KooCLI and OBS use separate credential stores — hcloud commands work fine but OBS commands fail with "Please set ak, sk" unless this sync is done. Run this once to enable OBS operations; re-run after changing hcloud credentials.',
|
|
290
|
+
inputSchema: {
|
|
291
|
+
type: 'object',
|
|
292
|
+
properties: {
|
|
293
|
+
profile: { type: 'string', description: 'Optional KooCLI profile name. Uses the active profile by default.' },
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
name: 'huaweicloud_auth_status',
|
|
299
|
+
description: 'Check unified Huawei Cloud authentication status across the global credential vault, OBS, KooCLI, and all supported agent MCP registrations. Returns only redacted/status information, never credentials.',
|
|
300
|
+
inputSchema: {
|
|
301
|
+
type: 'object',
|
|
302
|
+
properties: {
|
|
303
|
+
target: { type: 'string', description: 'Agent target to check: opencode, codex, codex-desktop, codearts, workbuddy, dsh, or all (default).' },
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
name: 'huaweicloud_auth_sync',
|
|
309
|
+
description: 'Synchronize credentials from the global Huawei Cloud credential vault to OBS and report agent registration status. Does not write secrets into any agent config.',
|
|
310
|
+
inputSchema: {
|
|
311
|
+
type: 'object',
|
|
312
|
+
properties: {
|
|
313
|
+
target: { type: 'string', description: 'Agent target to report after sync: opencode, codex, codex-desktop, codearts, workbuddy, dsh, or all (default).' },
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: 'huaweicloud_sandbox_exec_with_session',
|
|
319
|
+
description: 'Execute a command on a workspace terminal with session reuse (state persists across calls). Shell state (cd, env vars, aliases) carries over between calls.',
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: 'object',
|
|
322
|
+
required: ['command'],
|
|
323
|
+
properties: {
|
|
324
|
+
command: { type: 'string', description: 'The shell command to execute on the remote workspace' },
|
|
325
|
+
workspace_id: { type: 'string', description: 'The workspace ID' },
|
|
326
|
+
username: { type: 'string', description: 'Login username for the remote terminal (default: root)' },
|
|
327
|
+
timeout_ms: { type: 'number', description: 'Execution timeout in milliseconds (default: 30000)' },
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
name: 'huaweicloud_sandbox_close_session',
|
|
333
|
+
description: 'Close the persistent terminal session for a workspace.',
|
|
334
|
+
inputSchema: {
|
|
335
|
+
type: 'object',
|
|
336
|
+
properties: {
|
|
337
|
+
workspace_id: { type: 'string', description: 'The workspace ID' },
|
|
338
|
+
username: { type: 'string', description: 'Login username (default: root)' },
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: 'huaweicloud_sandbox_check_user',
|
|
344
|
+
description: 'Check if the current user has completed real-name verification and signed the required agreements. Returns realnameVerified and agreementSigned status.',
|
|
345
|
+
inputSchema: {
|
|
346
|
+
type: 'object',
|
|
347
|
+
properties: {},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
name: 'huaweicloud_sandbox_sign_agreement',
|
|
352
|
+
description: 'Sign all unsigned or outdated agreements for the current user. Required before huaweicloud_sandbox_connect if check-user returns agreementSigned=false. CRITICAL: only call after the user explicitly consents to signing — never sign agreements on the user\'s behalf without their explicit request.',
|
|
353
|
+
inputSchema: {
|
|
354
|
+
type: 'object',
|
|
355
|
+
properties: {},
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: 'huaweicloud_sandbox_connect',
|
|
360
|
+
description: 'Connect to a sandbox via hdkitservice. One user one instance - reuses existing sandbox if available, otherwise creates a new one. Returns session_id, dev_stage_id, connection_id, and connection_address.',
|
|
361
|
+
inputSchema: {
|
|
362
|
+
type: 'object',
|
|
363
|
+
properties: {
|
|
364
|
+
source: { type: 'string', description: 'Source identifier (default: WEB). Options: VSCODE, CLI, WEB, WEBVNC, WEBPTY, WEBIDE, CURSOR, etc.' },
|
|
365
|
+
template_id: { type: 'string', description: 'Template ID; overrides server default (only for new sandbox)' },
|
|
366
|
+
flavor_id: { type: 'string', description: 'Flavor ID; overrides server default (only for new sandbox)' },
|
|
367
|
+
env: { type: 'object', description: 'Environment variables to set in the sandbox (only for new sandbox)' },
|
|
368
|
+
git: {
|
|
369
|
+
type: 'object',
|
|
370
|
+
description: 'Git repo config (only for new sandbox)',
|
|
371
|
+
properties: {
|
|
372
|
+
repo_url: { type: 'string', description: 'Git repository URL' },
|
|
373
|
+
repo_branch: { type: 'string', description: 'Git branch' },
|
|
374
|
+
repo_name: { type: 'string', description: 'Repository name' },
|
|
375
|
+
target_path: { type: 'string', description: 'Clone target path in sandbox' },
|
|
376
|
+
open_type: { type: 'string', description: 'Open type' },
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
name: 'huaweicloud_sandbox_credentials',
|
|
384
|
+
description: 'Configure temporary AK/SK for a sandbox via hdkitservice. Injects temporary credentials into the sandbox. The sandbox must be in RUNNING state.',
|
|
385
|
+
inputSchema: {
|
|
386
|
+
type: 'object',
|
|
387
|
+
properties: {
|
|
388
|
+
session_id: { type: 'string', description: 'Session ID from huaweicloud_sandbox_connect' },
|
|
389
|
+
dev_stage_id: { type: 'string', description: 'DevStation environment ID (alternative to session_id)' },
|
|
390
|
+
enable_sts: { type: 'boolean', description: 'Whether to enable STS temporary AK/SK (default: true)' },
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
];
|
|
396
|
+
|
|
397
|
+
export async function callTool(name, args = {}) {
|
|
398
|
+
switch (name) {
|
|
399
|
+
case 'huaweicloud_check_cli':
|
|
400
|
+
return runVersionCheck();
|
|
401
|
+
case 'huaweicloud_plan_cli_command':
|
|
402
|
+
return planHcloudCommand(args.args || [], { allowWrites: args.allowWrites === true });
|
|
403
|
+
case 'huaweicloud_run_readonly_command':
|
|
404
|
+
return runHcloud(args.args || [], {
|
|
405
|
+
timeoutMs: args.timeoutMs,
|
|
406
|
+
maxRetries: args.maxRetries,
|
|
407
|
+
cwd: args.cwd,
|
|
408
|
+
stdin: args.stdin,
|
|
409
|
+
});
|
|
410
|
+
case 'huaweicloud_list_operations':
|
|
411
|
+
return listOperations(args.service, { timeoutMs: args.timeoutMs });
|
|
412
|
+
case 'huaweicloud_run_approved_command':
|
|
413
|
+
return runApprovedCommand(args);
|
|
414
|
+
case 'huaweicloud_show_profile_redacted':
|
|
415
|
+
return showProfileRedacted(args.profile);
|
|
416
|
+
case 'huaweicloud_hook_check_command':
|
|
417
|
+
return hookResult(evaluateCommandRisk(args.command || ''));
|
|
418
|
+
case 'huaweicloud_hook_check_artifacts':
|
|
419
|
+
return hookResult(evaluateArtifacts(args.artifacts || []));
|
|
420
|
+
case 'huaweicloud_hook_check_deploy_plan':
|
|
421
|
+
return hookResult(evaluateDeployPlan(args.plan || {}));
|
|
422
|
+
case 'huaweicloud_service_catalog':
|
|
423
|
+
return serviceCatalog(args.intent);
|
|
424
|
+
case 'huaweicloud_search_docs':
|
|
425
|
+
return searchDocs(args.query || '', args.topic || 'all');
|
|
426
|
+
case 'huaweicloud_retrieve_skill':
|
|
427
|
+
return retrieveSkill(args.name || '');
|
|
428
|
+
case 'huaweicloud_list_regions':
|
|
429
|
+
return listRegions();
|
|
430
|
+
case 'huaweicloud_get_regional_availability':
|
|
431
|
+
return getRegionalAvailability(args.service || '', args.region || '');
|
|
432
|
+
case 'huaweicloud_explain_error':
|
|
433
|
+
return explainError(args);
|
|
434
|
+
case 'huaweicloud_search_marketplace':
|
|
435
|
+
return searchMarketplace(args.query || '', args.category || '');
|
|
436
|
+
case 'huaweicloud_setup_obs_config':
|
|
437
|
+
return setupObsConfig(args.profile);
|
|
438
|
+
case 'huaweicloud_auth_status':
|
|
439
|
+
return getAuthStatus(args.target || 'all');
|
|
440
|
+
case 'huaweicloud_auth_sync':
|
|
441
|
+
return syncAuth(args.target || 'all');
|
|
442
|
+
case 'huaweicloud_sandbox_exec_with_session': {
|
|
443
|
+
const sandboxWsId2 = args.workspace_id || DEFAULT_WORKSPACE_ID;
|
|
444
|
+
const sandboxUser2 = args.username || 'root';
|
|
445
|
+
const sandboxTimeout2 = args.timeout_ms || 30000;
|
|
446
|
+
const sandboxResult2 = await execWithSession(sandboxWsId2, args.command, sandboxUser2, sandboxTimeout2);
|
|
447
|
+
return { stdout: sandboxResult2.stdout, exitCode: sandboxResult2.exitCode };
|
|
448
|
+
}
|
|
449
|
+
case 'huaweicloud_sandbox_close_session': {
|
|
450
|
+
const sandboxWsId3 = args.workspace_id || DEFAULT_WORKSPACE_ID;
|
|
451
|
+
const sandboxUser3 = args.username || 'root';
|
|
452
|
+
const closed = await closeSession(sandboxWsId3, sandboxUser3);
|
|
453
|
+
return closed ? 'ok' : 'not_connected';
|
|
454
|
+
}
|
|
455
|
+
case 'huaweicloud_sandbox_check_user':
|
|
456
|
+
return await hdkitCheckUser();
|
|
457
|
+
case 'huaweicloud_sandbox_sign_agreement':
|
|
458
|
+
return await hdkitSignAgreement();
|
|
459
|
+
case 'huaweicloud_sandbox_connect':
|
|
460
|
+
return await hdkitConnect(args);
|
|
461
|
+
case 'huaweicloud_sandbox_credentials':
|
|
462
|
+
return await hdkitCredentials(args.session_id, args.dev_stage_id, args.enable_sts !== false);
|
|
463
|
+
default:
|
|
464
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function hookResult(result) {
|
|
469
|
+
return {
|
|
470
|
+
ok: result.decision !== 'deny',
|
|
471
|
+
decision: result.decision,
|
|
472
|
+
findings: result.findings,
|
|
473
|
+
nextStep: result.decision === 'deny'
|
|
474
|
+
? 'Revise the command, artifact, or deployment plan before execution.'
|
|
475
|
+
: result.decision === 'warn'
|
|
476
|
+
? 'Review the warnings with the user before proceeding.'
|
|
477
|
+
: 'No Huawei Cloud hook risk rule matched.',
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
export async function runVersionCheck(options = {}) {
|
|
482
|
+
const result = await runHcloud(['version'], {
|
|
483
|
+
...options,
|
|
484
|
+
maxRetries: options.maxRetries ?? 0,
|
|
485
|
+
});
|
|
486
|
+
const errorText = result.error || result.stderr || '';
|
|
487
|
+
const isSpawnError = /ENOENT|SPAWN_ERROR/i.test(errorText) || result.code === 'SPAWN_ERROR';
|
|
488
|
+
return {
|
|
489
|
+
installed: result.ok,
|
|
490
|
+
authenticated: result.ok && !/配置文件中不存在配置项|USE_ERROR.*配置/i.test(result.stdout || ''),
|
|
491
|
+
errorCode: isSpawnError ? 'HCLOUD_NOT_FOUND' : undefined,
|
|
492
|
+
output: result.ok ? result.stdout : errorText,
|
|
493
|
+
nextStep: result.ok
|
|
494
|
+
? 'Use huaweicloud_show_profile_redacted to inspect the active KooCLI profile safely.'
|
|
495
|
+
: isSpawnError
|
|
496
|
+
? 'hcloud executable not found. Set HCLOUD_BIN to the full hcloud path, or install KooCLI: npx huaweicloud-devkit install-hcloud. Then restart the agent.'
|
|
497
|
+
: 'Install Huawei Cloud KooCLI: npx huaweicloud-devkit install-hcloud. Configure credentials outside the agent conversation.',
|
|
498
|
+
authHint: 'If hcloud is installed but commands fail with "配置文件中不存在配置项", run `hcloud configure set --cli-access-key=<AK> --cli-secret-key=<SK> --cli-region=<region>` outside agent chat to configure credentials.',
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
async function showProfileRedacted(profile) {
|
|
503
|
+
const args = ['configure', 'show'];
|
|
504
|
+
if (profile) {
|
|
505
|
+
args.push('--cli-profile', String(profile));
|
|
506
|
+
}
|
|
507
|
+
const result = await runHcloud(args, { allowWrites: false, allowCredentialRead: true }).catch((error) => ({
|
|
508
|
+
ok: false,
|
|
509
|
+
blocked: true,
|
|
510
|
+
reason: error.message,
|
|
511
|
+
}));
|
|
512
|
+
if (result.blocked) {
|
|
513
|
+
return {
|
|
514
|
+
ok: false,
|
|
515
|
+
blockedByPolicy: true,
|
|
516
|
+
reason: result.reason,
|
|
517
|
+
safeAlternative: 'Use huaweicloud_show_profile_redacted so profile output is returned through the redaction pipeline.',
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
ok: result.ok,
|
|
522
|
+
note: result.ok
|
|
523
|
+
? 'Profile information was returned through the toolkit redaction pipeline.'
|
|
524
|
+
: 'Failed to retrieve profile — hcloud may not be installed or configured.',
|
|
525
|
+
result: redactSecrets(result),
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
async function setupObsConfig(profile) {
|
|
530
|
+
const stored = readGlobalCredentials();
|
|
531
|
+
if (stored?.ak && stored?.sk) {
|
|
532
|
+
try {
|
|
533
|
+
const obs = writeObsConfigFile(stored);
|
|
534
|
+
return {
|
|
535
|
+
ok: true,
|
|
536
|
+
existed: false,
|
|
537
|
+
created: true,
|
|
538
|
+
path: obs.path,
|
|
539
|
+
region: stored.region,
|
|
540
|
+
endpoint: obs.endpoint,
|
|
541
|
+
source: 'global-credentials',
|
|
542
|
+
note: 'OBS credentials synced from the global credential vault. OBS commands (hcloud OBS ls, mb, cp, etc.) should now work.',
|
|
543
|
+
};
|
|
544
|
+
} catch (error) {
|
|
545
|
+
return {
|
|
546
|
+
ok: false,
|
|
547
|
+
error: error.message,
|
|
548
|
+
nextStep: 'Run "npx huaweicloud-devkit auth init" to refresh credentials and region.',
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return setupObsConfigFromHcloud(profile);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
async function setupObsConfigFromHcloud(profile) {
|
|
557
|
+
const obsConfigPath = join(homedir(), '.obsutilconfig');
|
|
558
|
+
if (existsSync(obsConfigPath)) {
|
|
559
|
+
return { ok: true, existed: true, path: obsConfigPath, note: 'OBS config already exists. Delete ~/.obsutilconfig first if you need to re-sync.' };
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const args = ['configure', 'show'];
|
|
563
|
+
if (profile) args.push('--cli-profile', String(profile));
|
|
564
|
+
const result = await runHcloud(args, { allowWrites: false, allowCredentialRead: true });
|
|
565
|
+
|
|
566
|
+
if (!result.ok) {
|
|
567
|
+
return {
|
|
568
|
+
ok: false,
|
|
569
|
+
error: 'Failed to read hcloud profile.',
|
|
570
|
+
detail: result.error || result.stderr || 'hcloud not installed or not configured',
|
|
571
|
+
nextStep: 'Run "npx huaweicloud-devkit auth init" outside agent chat, then retry.',
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
let accessKeyId = '';
|
|
576
|
+
let secretAccessKey = '';
|
|
577
|
+
let region = '';
|
|
578
|
+
|
|
579
|
+
try {
|
|
580
|
+
const parsed = typeof result.stdout === 'string' ? JSON.parse(result.stdout) : result.stdout;
|
|
581
|
+
const cred = parsed.currentCredential || {};
|
|
582
|
+
accessKeyId = cred.accessKeyId || cred.ak || cred.access_key || '';
|
|
583
|
+
secretAccessKey = cred.secretAccessKey || cred.sk || cred.secret_key || '';
|
|
584
|
+
region = parsed.currentRegion || parsed.region || '';
|
|
585
|
+
} catch {
|
|
586
|
+
return {
|
|
587
|
+
ok: false,
|
|
588
|
+
error: 'Failed to parse hcloud profile output.',
|
|
589
|
+
detail: 'hcloud configure show returned unexpected format',
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
594
|
+
return {
|
|
595
|
+
ok: false,
|
|
596
|
+
error: 'No credentials found in hcloud profile.',
|
|
597
|
+
nextStep: 'Run "npx huaweicloud-devkit auth init" outside agent chat to set up credentials first.',
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (!region) {
|
|
602
|
+
return {
|
|
603
|
+
ok: false,
|
|
604
|
+
error: 'No region found in hcloud profile.',
|
|
605
|
+
nextStep: 'Run "hcloud configure set --cli-region=<region>" outside agent chat to set a default region.',
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const endpoint = `https://obs.${region}.myhuaweicloud.com`;
|
|
610
|
+
// Flat key=value format (no [default] section) as written by KooCLI 7.x `hcloud OBS config`.
|
|
611
|
+
const configContent = `endpoint=${endpoint}\nak=${accessKeyId}\nsk=${secretAccessKey}\n`;
|
|
612
|
+
|
|
613
|
+
try {
|
|
614
|
+
writeFileSync(obsConfigPath, configContent, { encoding: 'utf8', mode: 0o600 });
|
|
615
|
+
} catch (e) {
|
|
616
|
+
return {
|
|
617
|
+
ok: false,
|
|
618
|
+
error: 'Failed to write OBS config file.',
|
|
619
|
+
detail: e.message,
|
|
620
|
+
path: obsConfigPath,
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return {
|
|
625
|
+
ok: true,
|
|
626
|
+
existed: false,
|
|
627
|
+
created: true,
|
|
628
|
+
path: obsConfigPath,
|
|
629
|
+
region,
|
|
630
|
+
endpoint,
|
|
631
|
+
note: 'OBS credentials synced from hcloud profile. OBS commands (hcloud OBS ls, mb, cp, etc.) should now work.',
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const SERVICE_EXAMPLES = {
|
|
636
|
+
ECS: { list: 'ECS ListServersDetails', create: 'ECS CreateServers', show: 'IMS GlanceShowImage' },
|
|
637
|
+
VPC: { list: 'VPC ListVpcs', create: 'VPC CreateVpc', show: 'VPC ShowVpc' },
|
|
638
|
+
FunctionGraph: { list: 'FunctionGraph ListFunctions', create: 'FunctionGraph CreateFunction', show: 'FunctionGraph ShowFunctionConfig' },
|
|
639
|
+
APIG: { list: 'APIG ListInstancesV2', create: 'APIG CreateInstanceV2', show: 'APIG ShowDetailsOfInstanceV2' },
|
|
640
|
+
OBS: { list: 'OBS ls', create: 'OBS mb obs://<bucket>', show: 'OBS stat obs://<bucket>/<key>' },
|
|
641
|
+
RDS: { list: 'RDS ListInstances', create: 'RDS CreateInstance', show: 'RDS ShowInstance' },
|
|
642
|
+
CES: { list: 'CES ListAlarms', create: 'CES CreateAlarm', show: 'CES ListMetrics' },
|
|
643
|
+
GaussDB: { list: 'GaussDB ListInstances', create: 'GaussDB CreateInstance', show: 'GaussDB ShowInstance' },
|
|
644
|
+
DDS: { list: 'DDS ListInstances', create: 'DDS CreateInstance', show: 'DDS ShowInstance' },
|
|
645
|
+
DCS: { list: 'DCS ListInstances', create: 'DCS CreateInstance', show: 'DCS ShowInstance' },
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
async function listOperations(service, options = {}) {
|
|
649
|
+
const serviceName = String(service || '').trim();
|
|
650
|
+
if (!/^[A-Za-z][A-Za-z0-9-]{1,63}$/.test(serviceName)) {
|
|
651
|
+
throw new Error('service must be a KooCLI service name such as ECS, VPC, IMS, OBS, RDS, or CDN.');
|
|
652
|
+
}
|
|
653
|
+
const isObs = /^obs$/i.test(serviceName);
|
|
654
|
+
const svc = isObs ? 'obs' : serviceName;
|
|
655
|
+
const args = isObs ? ['obs', 'help'] : [svc, '--help'];
|
|
656
|
+
let result = await runHcloud(args, {
|
|
657
|
+
timeoutMs: options.timeoutMs,
|
|
658
|
+
maxRetries: 0,
|
|
659
|
+
});
|
|
660
|
+
if (!result.ok && !isObs) {
|
|
661
|
+
result = await runHcloud([svc, 'help'], {
|
|
662
|
+
timeoutMs: options.timeoutMs,
|
|
663
|
+
maxRetries: 0,
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
return {
|
|
667
|
+
service: serviceName,
|
|
668
|
+
command: isObs ? 'hcloud obs help' : `hcloud ${svc} --help`,
|
|
669
|
+
selectionRule: 'Use this help text to select the exact KooCLI operation name before planning any service command.',
|
|
670
|
+
examples: SERVICE_EXAMPLES[serviceName.toUpperCase()] || { note: `No cached examples for ${serviceName}. Use the help text above to discover available operations.` },
|
|
671
|
+
result,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
async function runApprovedCommand(args = {}) {
|
|
676
|
+
if (args.approvedByUser !== true) {
|
|
677
|
+
throw new Error('approvedByUser must be true after explicit user approval for this exact command.');
|
|
678
|
+
}
|
|
679
|
+
const strictPlan = planHcloudCommand(args.args || [], { allowWrites: false });
|
|
680
|
+
const plan = planHcloudCommand(args.args || [], { allowWrites: true });
|
|
681
|
+
if (String(args.approvedCommand || '') !== plan.command) {
|
|
682
|
+
throw new Error('approvedCommand must exactly match the planned hcloud command.');
|
|
683
|
+
}
|
|
684
|
+
const result = await runHcloud(args.args || [], {
|
|
685
|
+
allowWrites: true,
|
|
686
|
+
timeoutMs: args.timeoutMs,
|
|
687
|
+
maxRetries: args.maxRetries,
|
|
688
|
+
cwd: args.cwd,
|
|
689
|
+
stdin: args.stdin,
|
|
690
|
+
});
|
|
691
|
+
result.approved = true;
|
|
692
|
+
result.plan = strictPlan;
|
|
693
|
+
return result;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function serviceCatalog(intent = '') {
|
|
697
|
+
const it = String(intent).toLowerCase();
|
|
698
|
+
const routeMap = [
|
|
699
|
+
{ keywords: ['ecs', 'server', 'vm', 'instance', 'compute', 'flavor', 'image'], skills: ['huawei-ecs'], services: ['ECS'] },
|
|
700
|
+
{ keywords: ['vpc', 'subnet', 'network', 'security group', 'eip', 'nat', 'vpn', 'bandwidth'], skills: ['huawei-vpc'], services: ['VPC', 'EIP'] },
|
|
701
|
+
{ keywords: ['obs', 'bucket', 'storage', 'object', 'static website', 'static site', 'hosting'], skills: ['huawei-obs'], services: ['OBS'] },
|
|
702
|
+
{ keywords: ['functiongraph', 'serverless', 'function', 'lambda', 'trigger', 'faas'], skills: ['huawei-functiongraph'], services: ['FunctionGraph'] },
|
|
703
|
+
{ keywords: ['cce', 'kubernetes', 'k8s', 'container', 'cluster', 'node pool', 'swr', 'docker', 'image registry'], skills: ['huawei-cce'], services: ['CCE', 'SWR'] },
|
|
704
|
+
{ keywords: ['apig', 'api gateway', 'publish', 'throttle'], skills: ['huawei-apig'], services: ['APIG'] },
|
|
705
|
+
{ keywords: ['rds', 'mysql', 'postgresql', 'database', 'db'], skills: ['huawei-rds'], services: ['RDS'] },
|
|
706
|
+
{ keywords: ['gaussdb', 'distributed', 'sharding', 'opengauss'], skills: ['huawei-gaussdb'], services: ['GaussDB'] },
|
|
707
|
+
{ keywords: ['iam', 'permission', 'policy', 'role', 'user', 'ak/sk', 'access key', 'agency'], skills: ['huawei-iam'], services: ['IAM'] },
|
|
708
|
+
{ keywords: ['dew', 'secret', 'kms', 'encrypt', 'decrypt', 'certificate', 'csms'], skills: ['huawei-dew'], services: ['CSMS', 'KMS'] },
|
|
709
|
+
{ keywords: ['modelarts', 'ai', 'model', 'training', 'inference', 'machine learning'], skills: ['huawei-modelarts'], services: ['ModelArts'] },
|
|
710
|
+
{ keywords: ['billing', 'cost', 'bill', 'budget', 'expense', 'bss'], skills: ['huawei-billing'], services: ['BSS'] },
|
|
711
|
+
{ keywords: ['waf', 'aad', 'ddos', 'firewall', 'web protection'], skills: ['huawei-waf-aad'], services: ['WAF', 'AAD'] },
|
|
712
|
+
{ keywords: ['smn', 'dms', 'notification', 'message', 'kafka', 'rabbitmq'], skills: ['huawei-smn-dms'], services: ['SMN', 'DMS'] },
|
|
713
|
+
{ keywords: ['ces', 'monitor', 'alarm', 'metric', 'dashboard', 'cloud eye'], skills: ['huawei-cloud-eye'], services: ['CES'] },
|
|
714
|
+
{ keywords: ['cts', 'audit', 'trace', 'tracker'], skills: ['huawei-cts'], services: ['CTS'] },
|
|
715
|
+
{ keywords: ['cbr', 'backup', 'restore', 'vault', 'snapshot'], skills: ['huawei-cbr'], services: ['CBR'] },
|
|
716
|
+
{ keywords: ['deployment', 'deploy', 'ci/cd', 'pipeline', 'release'], skills: ['huawei-deployment'], services: ['CloudDeploy'] },
|
|
717
|
+
{ keywords: ['sandbox', 'devstation', 'workspace', 'terminal', 'preview', 'hwlink', 'website', 'web app', 'webapp', 'hosting', '网站', '网页', '静态'], skills: ['huawei-sandbox'], services: ['Sandbox', 'DevStation'] },
|
|
718
|
+
{ keywords: ['dds', 'dcs', 'mongodb', 'redis', 'memcached', 'cache', 'document db'], skills: ['huawei-dds-dcs'], services: ['DDS', 'DCS'] },
|
|
719
|
+
];
|
|
720
|
+
const matched = [];
|
|
721
|
+
const tokens = it.split(/[\s,./-]+/).filter((t) => t.length > 0);
|
|
722
|
+
const cjk = /[\u4e00-\u9fff]/;
|
|
723
|
+
for (const route of routeMap) {
|
|
724
|
+
if (route.keywords.some((kw) => (kw.includes(' ') || cjk.test(kw)) ? it.includes(kw) : tokens.includes(kw))) {
|
|
725
|
+
matched.push(route);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
const recommendedSkills = [...new Set(matched.flatMap((r) => r.skills))];
|
|
729
|
+
const recommendedServices = [...new Set(matched.flatMap((r) => r.services))].slice(0, 5);
|
|
730
|
+
|
|
731
|
+
// Deployment intent (deploy/host/publish a web app or static website) must never
|
|
732
|
+
// default to a storage/other service — recommend the sandbox first.
|
|
733
|
+
const deploymentIntent = /deploy|host|hosting|publish|website|web app|preview|部署|托管|发布|网站|网页/.test(it);
|
|
734
|
+
if (deploymentIntent && recommendedSkills.includes('huawei-sandbox')) {
|
|
735
|
+
const idx = recommendedSkills.indexOf('huawei-sandbox');
|
|
736
|
+
recommendedSkills.splice(idx, 1);
|
|
737
|
+
recommendedSkills.unshift('huawei-sandbox');
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return {
|
|
741
|
+
intent,
|
|
742
|
+
recommendedSkills: recommendedSkills.length ? recommendedSkills : ['Use huaweicloud-core to route intent.'],
|
|
743
|
+
recommendedServices: recommendedServices.length ? recommendedServices : ['Run hcloud --help to list available services.'],
|
|
744
|
+
capabilityOrder: [
|
|
745
|
+
'Huawei Cloud Skills for task-specific workflows and examples',
|
|
746
|
+
'KooCLI hcloud for local authenticated operations and quick inspection',
|
|
747
|
+
'Huawei Cloud API documentation for exact request and response contracts',
|
|
748
|
+
'Huawei Cloud SDKs for application code integration',
|
|
749
|
+
'Huawei Cloud MCP when an official or approved server is available',
|
|
750
|
+
'Terraform Provider only when IaC reviewability and repeatability are important',
|
|
751
|
+
],
|
|
752
|
+
ruleOfThumb: {
|
|
753
|
+
skills: 'Start here when the user describes a scenario or wants a guided workflow.',
|
|
754
|
+
cli: 'Use for local diagnostics, read-only inspection, and commands the user can review.',
|
|
755
|
+
api: 'Use for exact service contract, region endpoint, project_id, pagination, and error codes.',
|
|
756
|
+
sdk: 'Use when writing application code that calls Huawei Cloud services.',
|
|
757
|
+
mcp: 'Prefer approved MCP tools when available because tools can carry structured schemas.',
|
|
758
|
+
terraform: 'Keep low priority in V1; suggest it for reviewed infrastructure changes, not quick diagnosis.',
|
|
759
|
+
},
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function explainError({ service = 'unknown', errorCode = '', message = '', requestId = '' } = {}) {
|
|
764
|
+
const combined = `${errorCode} ${message}`.toLowerCase();
|
|
765
|
+
const suggestions = [];
|
|
766
|
+
const svc = String(service).toLowerCase();
|
|
767
|
+
|
|
768
|
+
const SERVICE_ALIASES = {
|
|
769
|
+
'functiongraph': 'FSS',
|
|
770
|
+
'fgs': 'FSS',
|
|
771
|
+
};
|
|
772
|
+
const patternKey = SERVICE_ALIASES[svc] || service;
|
|
773
|
+
|
|
774
|
+
const hwErrorPatterns = {
|
|
775
|
+
OBS: {
|
|
776
|
+
'InvalidAccessKeyId': 'OBS uses AK/SK directly (not IAM tokens). Verify AK/SK validity, OBS endpoint, and OBS permissions.',
|
|
777
|
+
'UserRestricted': 'This IAM user is restricted from OBS operations (403). Check IAM console → Users → Permissions: grant OBS bucket/object actions, or use an unrestricted account. If the account is a sub-account, the main account may have imposed restrictions.',
|
|
778
|
+
},
|
|
779
|
+
APIG: {
|
|
780
|
+
'APIC.7241': 'The enterprise_project_id is required for enterprise accounts. Add --enterprise_project_id=0.',
|
|
781
|
+
'APIC.7242': 'The EIP binding method depends on loadbalancer_provider. Use AddIngressEipV2 for elb, AddEipV2 for lvs.',
|
|
782
|
+
'APIC.7256': 'Bandwidth minimum is 5 Mbps. Use --bandwidth_size=5 or higher.',
|
|
783
|
+
'APIC.7310': 'available_zone_ids must use AZ codes (e.g. ap-southeast-3a), NOT UUIDs from ListAvailableZonesV2.',
|
|
784
|
+
},
|
|
785
|
+
FSS: {
|
|
786
|
+
'FSS.0403': 'Missing FunctionGraph IAM permissions. Attach FunctionGraph FullAccess role or grant specific actions.',
|
|
787
|
+
'FSS.1078': '--code_filename is filename-only (no path). cd to the file directory before running the command.',
|
|
788
|
+
'FSS.1417': 'event_data field validation failed. Check parameter format: use dotted key=value, verify required hidden-optional fields.',
|
|
789
|
+
},
|
|
790
|
+
VPC: {
|
|
791
|
+
'VPC.0301': 'Bandwidth name is required for PER type EIPs, even though --help marks it optional.',
|
|
792
|
+
},
|
|
793
|
+
APIGW: {
|
|
794
|
+
'APIGW.0802': 'The current IAM user has no permissions in the requested region. Go to IAM console → Users → Permissions → add the target region, or switch to a different region.',
|
|
795
|
+
},
|
|
796
|
+
};
|
|
797
|
+
if (hwErrorPatterns[patternKey] && hwErrorPatterns[patternKey][errorCode]) {
|
|
798
|
+
suggestions.push(hwErrorPatterns[patternKey][errorCode]);
|
|
799
|
+
}
|
|
800
|
+
const svcPatterns = hwErrorPatterns[patternKey] || {};
|
|
801
|
+
for (const [code, tip] of Object.entries(svcPatterns)) {
|
|
802
|
+
if (errorCode && code.includes(errorCode)) {
|
|
803
|
+
if (!suggestions.includes(tip)) suggestions.push(tip);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
if (/auth|token|credential|ak|sk|401|403|unauthorized|forbidden|Incorrect IAM/i.test(combined)) {
|
|
808
|
+
if (svc === 'obs') {
|
|
809
|
+
suggestions.push('OBS uses AK/SK directly, not IAM tokens. Verify AK/SK validity and OBS bucket permissions via hcloud configure list or the Huawei Cloud console.');
|
|
810
|
+
} else {
|
|
811
|
+
suggestions.push('Check KooCLI profile, region, project_id, and IAM permissions without printing secrets.');
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
if (/APIGW\.(\d+)/i.test(errorCode)) {
|
|
815
|
+
suggestions.push('APIGW.' + (errorCode.match(/APIGW\.(\d+)/i) || [])[1] + ': API Gateway layer error. ' + (errorCode === 'APIGW.0802' ? 'IAM user has no region permissions — check IAM console → User → Permissions → add target region.' : 'Verify the API request, region endpoint, and IAM permissions.'));
|
|
816
|
+
}
|
|
817
|
+
if (/region|endpoint|project/i.test(combined)) {
|
|
818
|
+
suggestions.push('Confirm the service endpoint, region, and project_id match the target resource.');
|
|
819
|
+
}
|
|
820
|
+
if (/quota|limit|insufficient|reach the limit/i.test(combined)) {
|
|
821
|
+
suggestions.push('Check quota and resource limits before retrying a create or scale operation. Consider switching accounts or requesting a quota increase.');
|
|
822
|
+
}
|
|
823
|
+
if (/not.?found|404/i.test(combined)) {
|
|
824
|
+
if (/list.?regions/i.test(svc)) {
|
|
825
|
+
suggestions.push('Use hcloud IAM KeystoneListRegions (not list-regions).');
|
|
826
|
+
} else {
|
|
827
|
+
suggestions.push('List resources in the same region/project and verify the resource identifier.');
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
if (!suggestions.length) {
|
|
831
|
+
suggestions.push('Collect service name, operation, region, project_id, request_id, and the full redacted error message.');
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
if (requestId) {
|
|
835
|
+
suggestions.push('Provide the Request ID (' + requestId + ') when contacting Huawei Cloud support.');
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
const uniqueSuggestions = suggestions.filter((s, i, arr) => {
|
|
839
|
+
return !arr.slice(0, i).some((prev) =>
|
|
840
|
+
prev.substring(0, 50).toLowerCase() === s.substring(0, 50).toLowerCase());
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
return {
|
|
844
|
+
service,
|
|
845
|
+
errorCode,
|
|
846
|
+
requestId,
|
|
847
|
+
suggestions: uniqueSuggestions,
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
async function searchDocs(query, topic = 'all') {
|
|
852
|
+
const q = String(query || '').toLowerCase();
|
|
853
|
+
const tokens = q.split(/\s+/).filter((t) => t.length > 0);
|
|
854
|
+
const results = [];
|
|
855
|
+
try {
|
|
856
|
+
if (existsSync(SKILLS_ROOT)) {
|
|
857
|
+
const dirs = readdirSync(SKILLS_ROOT, { withFileTypes: true })
|
|
858
|
+
.filter((d) => d.isDirectory())
|
|
859
|
+
.map((d) => d.name);
|
|
860
|
+
for (const dir of dirs) {
|
|
861
|
+
const skillPath = join(SKILLS_ROOT, dir, 'SKILL.md');
|
|
862
|
+
if (!existsSync(skillPath)) continue;
|
|
863
|
+
const content = readFileSync(skillPath, 'utf8');
|
|
864
|
+
const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
865
|
+
let description = '';
|
|
866
|
+
let name = dir;
|
|
867
|
+
if (frontmatter) {
|
|
868
|
+
const fm = frontmatter[1];
|
|
869
|
+
const nameMatch = fm.match(/^name:\s*(.+)$/m);
|
|
870
|
+
if (nameMatch) name = nameMatch[1].trim();
|
|
871
|
+
const descMatch = fm.match(/^description:\s*(.+)$/m);
|
|
872
|
+
if (descMatch) description = descMatch[1].trim();
|
|
873
|
+
}
|
|
874
|
+
if (topic !== 'all') {
|
|
875
|
+
const topicLower = topic.toLowerCase();
|
|
876
|
+
if (!name.toLowerCase().includes(topicLower) && !description.toLowerCase().includes(topicLower)) continue;
|
|
877
|
+
}
|
|
878
|
+
const descLower = description.toLowerCase();
|
|
879
|
+
const nameLower = name.toLowerCase();
|
|
880
|
+
const contentLower = content.toLowerCase();
|
|
881
|
+
const relevance = tokens.reduce((score, token) => {
|
|
882
|
+
return score + (descLower.includes(token) ? 3 : 0) + (nameLower.includes(token) ? 2 : 0) + (contentLower.includes(token) ? 1 : 0);
|
|
883
|
+
}, 0);
|
|
884
|
+
if (relevance > 0) {
|
|
885
|
+
results.push({
|
|
886
|
+
source: "skills/" + dir + "/SKILL.md",
|
|
887
|
+
name,
|
|
888
|
+
snippet: description.substring(0, 200),
|
|
889
|
+
relevance,
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
} catch (err) {
|
|
895
|
+
return { ok: false, error: err.message, results: [] };
|
|
896
|
+
}
|
|
897
|
+
results.sort((a, b) => b.relevance - a.relevance);
|
|
898
|
+
return { ok: true, query: q, topic, count: results.length, results: results.slice(0, 10) };
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
async function retrieveSkill(name) {
|
|
902
|
+
const skillName = String(name || '').trim();
|
|
903
|
+
if (!skillName) return { ok: false, error: 'Skill name is required.' };
|
|
904
|
+
const skillPath = join(SKILLS_ROOT, skillName, 'SKILL.md');
|
|
905
|
+
if (!existsSync(skillPath)) {
|
|
906
|
+
const dirs = existsSync(SKILLS_ROOT)
|
|
907
|
+
? readdirSync(SKILLS_ROOT, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name)
|
|
908
|
+
: [];
|
|
909
|
+
return { ok: false, error: 'Skill "' + skillName + '" not found. Available: ' + dirs.join(', ') };
|
|
910
|
+
}
|
|
911
|
+
const content = readFileSync(skillPath, 'utf8');
|
|
912
|
+
const references = [];
|
|
913
|
+
const refDir = join(SKILLS_ROOT, skillName, 'references');
|
|
914
|
+
if (existsSync(refDir)) {
|
|
915
|
+
readdirSync(refDir).forEach((f) => {
|
|
916
|
+
const refPath = join(refDir, f);
|
|
917
|
+
references.push({ filename: f, content: readFileSync(refPath, 'utf8').substring(0, 4000) });
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
921
|
+
let version = 1, description = '';
|
|
922
|
+
if (frontmatter) {
|
|
923
|
+
const fm = frontmatter[1];
|
|
924
|
+
const vm = fm.match(/^version:\s*(.+)$/m);
|
|
925
|
+
if (vm) version = vm[1].trim();
|
|
926
|
+
const dm = fm.match(/^description:\s*(.+)$/m);
|
|
927
|
+
if (dm) description = dm[1].trim();
|
|
928
|
+
}
|
|
929
|
+
return { ok: true, name: skillName, version, description, content, references };
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
async function listRegions() {
|
|
933
|
+
const result = await runHcloud(['IAM', 'KeystoneListRegions'], { timeoutMs: 30000, maxRetries: 0 })
|
|
934
|
+
.catch((err) => ({ ok: false, error: err.message }));
|
|
935
|
+
if (!result.ok) {
|
|
936
|
+
return {
|
|
937
|
+
ok: false,
|
|
938
|
+
error: result.error || 'Failed to list regions.',
|
|
939
|
+
fallback: 'Check https://developer.huaweicloud.com/endpoint for available regions.',
|
|
940
|
+
staticRegions: [
|
|
941
|
+
{ id: 'cn-north-1', description: '华北-北京一' },
|
|
942
|
+
{ id: 'cn-north-4', description: '华北-北京四' },
|
|
943
|
+
{ id: 'cn-east-3', description: '华东-上海一' },
|
|
944
|
+
{ id: 'cn-east-2', description: '华东-上海二' },
|
|
945
|
+
{ id: 'cn-south-1', description: '华南-广州' },
|
|
946
|
+
{ id: 'ap-southeast-1', description: '香港' },
|
|
947
|
+
{ id: 'ap-southeast-3', description: '新加坡' },
|
|
948
|
+
{ id: 'ap-southeast-2', description: '曼谷' },
|
|
949
|
+
{ id: 'af-south-1', description: '约翰内斯堡' },
|
|
950
|
+
],
|
|
951
|
+
note: 'hcloud unavailable. Showing static region list. For the complete list, visit the fallback URL.',
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
let regions = [];
|
|
955
|
+
try {
|
|
956
|
+
const parsed = typeof result.stdout === 'string' ? JSON.parse(result.stdout) : result.stdout;
|
|
957
|
+
const rawRegions = parsed.regions || [];
|
|
958
|
+
regions = rawRegions.map((r) => ({
|
|
959
|
+
id: r.id,
|
|
960
|
+
description: r.description || r.names,
|
|
961
|
+
type: r.type,
|
|
962
|
+
locales: r.locales,
|
|
963
|
+
}));
|
|
964
|
+
} catch {
|
|
965
|
+
regions = [{ raw: String(result.stdout).substring(0, 1000) }];
|
|
966
|
+
}
|
|
967
|
+
regions.sort((a, b) => String(a.id || '').localeCompare(String(b.id || '')));
|
|
968
|
+
return { ok: true, count: regions.length, regions };
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
async function getRegionalAvailability(service, region) {
|
|
972
|
+
const svc = String(service || '').toLowerCase().trim();
|
|
973
|
+
const reg = String(region || '').toLowerCase().trim();
|
|
974
|
+
if (!svc || !reg) return { ok: false, error: 'Both service and region are required.' };
|
|
975
|
+
const known = {
|
|
976
|
+
ecs: ['cn-south-1','cn-north-4','cn-north-1','cn-east-3','cn-east-2','ap-southeast-3','ap-southeast-2','ap-southeast-1','ap-southeast-4','af-south-1','tr-west-1','sa-brazil-1','la-north-2','na-mexico-1','me-east-1'],
|
|
977
|
+
obs: ['cn-south-1','cn-north-4','cn-north-1','cn-east-3','cn-east-2','ap-southeast-3','ap-southeast-2','ap-southeast-1','af-south-1'],
|
|
978
|
+
vpc: ['cn-south-1','cn-north-4','cn-north-1','cn-east-3','cn-east-2','ap-southeast-3','ap-southeast-2','ap-southeast-1','ap-southeast-4','af-south-1','tr-west-1','sa-brazil-1','la-north-2','me-east-1'],
|
|
979
|
+
iam: ['global'],
|
|
980
|
+
rds: ['cn-south-1','cn-north-4','cn-north-1','cn-east-3','cn-east-2','ap-southeast-3','ap-southeast-2','ap-southeast-1'],
|
|
981
|
+
gaussdb: ['cn-south-1','cn-north-4','cn-east-3'],
|
|
982
|
+
cce: ['cn-south-1','cn-north-4','cn-north-1','cn-east-3','cn-east-2','ap-southeast-3','ap-southeast-2','ap-southeast-1'],
|
|
983
|
+
modelarts: ['cn-south-1','cn-north-4','cn-east-3'],
|
|
984
|
+
functiongraph: ['cn-south-1','cn-north-4','cn-north-1','cn-east-3','cn-east-2','ap-southeast-3','ap-southeast-2','ap-southeast-1'],
|
|
985
|
+
dew: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
986
|
+
smn: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
987
|
+
ces: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
988
|
+
cts: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
989
|
+
apig: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
990
|
+
cbr: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
991
|
+
dds: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
992
|
+
dcs: ['cn-south-1','cn-north-4','cn-east-3','ap-southeast-3'],
|
|
993
|
+
};
|
|
994
|
+
if (!known[svc]) return { ok: false, service: svc, region: reg, available: false, note: 'Service ' + svc + ' is not in the regional availability cache. Run hcloud ' + svc.toUpperCase() + ' --help to verify, or check https://developer.huaweicloud.com/endpoint.' };
|
|
995
|
+
const available = known[svc].includes(reg) || known[svc].includes('global');
|
|
996
|
+
return {
|
|
997
|
+
ok: true, service: svc, region: reg, available,
|
|
998
|
+
note: available
|
|
999
|
+
? svc + ' is available in ' + reg + '.'
|
|
1000
|
+
: svc + ' availability in ' + reg + ' could not be confirmed. Verify at https://developer.huaweicloud.com/endpoint.',
|
|
1001
|
+
sourcedFrom: 'static cache, update via npm package upgrade',
|
|
1002
|
+
disclaimer: 'This result reflects service-level availability only. It does NOT guarantee that your IAM user has permissions in this region. Account-level restrictions (e.g., APIGW.0802) may block actual API calls even when the service is available.',
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
export function classifyRawCommand(command) {
|
|
1007
|
+
return classifyTextCommand(command);
|
|
1008
|
+
}
|