huaweicloud-devkit 1.0.2-next.2 → 1.0.3-dev.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/README.md +1 -25
- package/README.zh-CN.md +1 -23
- package/bin/setup.cjs +0 -0
- package/package.json +1 -3
- package/plugins/huaweicloud-core/.claude-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.codex-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.cursor-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/skills/huawei-obs/SKILL.md +0 -6
- package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +4 -5
- package/plugins/huaweicloud-core/skills/huaweicloud-capability-discovery/SKILL.md +0 -4
- package/plugins/huaweicloud-core/skills/huaweicloud-core/SKILL.md +3 -18
- package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +1 -19
- package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +3 -7
- package/plugins/huaweicloud-core/src/sandbox/hwlink-api.mjs +3 -12
- package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +0 -7
- package/plugins/huaweicloud-core/src/search-market.mjs +2 -7
- package/plugins/huaweicloud-core/src/setup-cli.mjs +10 -433
- package/plugins/huaweicloud-core/src/tools.mjs +6 -21
- package/plugins/huaweicloud-core/src/proxy/proxy-agent.mjs +0 -155
- package/plugins/huaweicloud-core/src/proxy/proxy-config.mjs +0 -87
|
@@ -25,13 +25,8 @@ function workbuddySkillsDir() {
|
|
|
25
25
|
const home = homedir();
|
|
26
26
|
return join(home, '.workbuddy', 'skills');
|
|
27
27
|
}
|
|
28
|
-
function dshSkillsDir() {
|
|
29
|
-
const home = process.env.DSH_HOME || join(homedir(), '.dsh');
|
|
30
|
-
return join(home, 'skills');
|
|
31
|
-
}
|
|
32
28
|
function resolveSkillsRoot() {
|
|
33
29
|
if (existsSync(SKILLS_ROOT_DEV)) return SKILLS_ROOT_DEV;
|
|
34
|
-
if (existsSync(dshSkillsDir())) return dshSkillsDir();
|
|
35
30
|
if (existsSync(codeartsSkillsDir())) return codeartsSkillsDir();
|
|
36
31
|
if (existsSync(opencodeSkillsDir())) return opencodeSkillsDir();
|
|
37
32
|
if (existsSync(workbuddySkillsDir())) return workbuddySkillsDir();
|
|
@@ -300,7 +295,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
300
295
|
inputSchema: {
|
|
301
296
|
type: 'object',
|
|
302
297
|
properties: {
|
|
303
|
-
target: { type: 'string', description: 'Agent target to check: opencode, codex, codex-desktop, codearts, workbuddy,
|
|
298
|
+
target: { type: 'string', description: 'Agent target to check: opencode, codex, codex-desktop, codearts, workbuddy, or all (default).' },
|
|
304
299
|
},
|
|
305
300
|
},
|
|
306
301
|
},
|
|
@@ -310,7 +305,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
310
305
|
inputSchema: {
|
|
311
306
|
type: 'object',
|
|
312
307
|
properties: {
|
|
313
|
-
target: { type: 'string', description: 'Agent target to report after sync: opencode, codex, codex-desktop, codearts, workbuddy,
|
|
308
|
+
target: { type: 'string', description: 'Agent target to report after sync: opencode, codex, codex-desktop, codearts, workbuddy, or all (default).' },
|
|
314
309
|
},
|
|
315
310
|
},
|
|
316
311
|
},
|
|
@@ -341,7 +336,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
341
336
|
},
|
|
342
337
|
{
|
|
343
338
|
name: 'huaweicloud_sandbox_check_user',
|
|
344
|
-
description: 'Check if the current user has completed real-name verification and signed the required agreements. Returns
|
|
339
|
+
description: 'Check if the current user has completed real-name verification and signed the required agreements. Returns realname_verified and agreement_signed status.',
|
|
345
340
|
inputSchema: {
|
|
346
341
|
type: 'object',
|
|
347
342
|
properties: {},
|
|
@@ -349,7 +344,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
349
344
|
},
|
|
350
345
|
{
|
|
351
346
|
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
|
|
347
|
+
description: 'Sign all unsigned or outdated agreements for the current user. Required before huaweicloud_sandbox_connect if check-user returns agreement_signed=false.',
|
|
353
348
|
inputSchema: {
|
|
354
349
|
type: 'object',
|
|
355
350
|
properties: {},
|
|
@@ -714,29 +709,19 @@ function serviceCatalog(intent = '') {
|
|
|
714
709
|
{ keywords: ['cts', 'audit', 'trace', 'tracker'], skills: ['huawei-cts'], services: ['CTS'] },
|
|
715
710
|
{ keywords: ['cbr', 'backup', 'restore', 'vault', 'snapshot'], skills: ['huawei-cbr'], services: ['CBR'] },
|
|
716
711
|
{ keywords: ['deployment', 'deploy', 'ci/cd', 'pipeline', 'release'], skills: ['huawei-deployment'], services: ['CloudDeploy'] },
|
|
717
|
-
{ keywords: ['sandbox', 'devstation', 'workspace', 'terminal', 'preview', 'hwlink'
|
|
712
|
+
{ keywords: ['sandbox', 'devstation', 'workspace', 'terminal', 'preview', 'hwlink'], skills: ['huawei-sandbox'], services: ['Sandbox', 'DevStation'] },
|
|
718
713
|
{ keywords: ['dds', 'dcs', 'mongodb', 'redis', 'memcached', 'cache', 'document db'], skills: ['huawei-dds-dcs'], services: ['DDS', 'DCS'] },
|
|
719
714
|
];
|
|
720
715
|
const matched = [];
|
|
721
716
|
const tokens = it.split(/[\s,./-]+/).filter((t) => t.length > 0);
|
|
722
|
-
const cjk = /[\u4e00-\u9fff]/;
|
|
723
717
|
for (const route of routeMap) {
|
|
724
|
-
if (route.keywords.some((kw) =>
|
|
718
|
+
if (route.keywords.some((kw) => tokens.includes(kw))) {
|
|
725
719
|
matched.push(route);
|
|
726
720
|
}
|
|
727
721
|
}
|
|
728
722
|
const recommendedSkills = [...new Set(matched.flatMap((r) => r.skills))];
|
|
729
723
|
const recommendedServices = [...new Set(matched.flatMap((r) => r.services))].slice(0, 5);
|
|
730
724
|
|
|
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
725
|
return {
|
|
741
726
|
intent,
|
|
742
727
|
recommendedSkills: recommendedSkills.length ? recommendedSkills : ['Use huaweicloud-core to route intent.'],
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import { getProxyUrlForTarget } from './proxy-config.mjs';
|
|
2
|
-
|
|
3
|
-
let cachedDispatcher = undefined;
|
|
4
|
-
let cachedDispatcherProxyUrl = null;
|
|
5
|
-
|
|
6
|
-
export async function getProxyDispatcher(targetUrl) {
|
|
7
|
-
const proxyUrl = getProxyUrlForTarget(targetUrl);
|
|
8
|
-
if (!proxyUrl) return undefined;
|
|
9
|
-
|
|
10
|
-
if (cachedDispatcher && cachedDispatcherProxyUrl === proxyUrl) {
|
|
11
|
-
return cachedDispatcher;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { ProxyAgent } = await import('undici');
|
|
15
|
-
cachedDispatcher = new ProxyAgent(proxyUrl);
|
|
16
|
-
cachedDispatcherProxyUrl = proxyUrl;
|
|
17
|
-
return cachedDispatcher;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function clearProxyDispatcherCache() {
|
|
21
|
-
cachedDispatcher = undefined;
|
|
22
|
-
cachedDispatcherProxyUrl = null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function createProxyWebSocket(url, protocols) {
|
|
26
|
-
const proxyUrl = getProxyUrlForTarget(url);
|
|
27
|
-
if (!proxyUrl) {
|
|
28
|
-
return new globalThis.WebSocket(url, protocols);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const dispatcher = await getProxyDispatcher(url);
|
|
32
|
-
const { WebSocket: UndiciWebSocket } = await import('undici');
|
|
33
|
-
|
|
34
|
-
const wsOptions = { dispatcher };
|
|
35
|
-
if (protocols) {
|
|
36
|
-
if (Array.isArray(protocols)) {
|
|
37
|
-
wsOptions.protocols = protocols;
|
|
38
|
-
} else {
|
|
39
|
-
wsOptions.protocols = [protocols];
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return new UndiciWebSocket(url, wsOptions);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function getWebSocketImpl(targetUrl) {
|
|
47
|
-
const proxyUrl = getProxyUrlForTarget(targetUrl);
|
|
48
|
-
if (!proxyUrl) return globalThis.WebSocket;
|
|
49
|
-
|
|
50
|
-
return (url, protocols) => {
|
|
51
|
-
const proxyUrlForTarget = getProxyUrlForTarget(url);
|
|
52
|
-
if (!proxyUrlForTarget) {
|
|
53
|
-
return new globalThis.WebSocket(url, protocols);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const wsPromise = (async () => {
|
|
57
|
-
const dispatcher = await getProxyDispatcher(url);
|
|
58
|
-
const { WebSocket: UndiciWebSocket } = await import('undici');
|
|
59
|
-
|
|
60
|
-
const wsOptions = { dispatcher };
|
|
61
|
-
if (protocols) {
|
|
62
|
-
if (Array.isArray(protocols)) {
|
|
63
|
-
wsOptions.protocols = protocols;
|
|
64
|
-
} else {
|
|
65
|
-
wsOptions.protocols = [protocols];
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return new UndiciWebSocket(url, wsOptions);
|
|
70
|
-
})();
|
|
71
|
-
|
|
72
|
-
return createSyncProxyWebSocketWrapper(wsPromise);
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function createSyncProxyWebSocketWrapper(wsPromise) {
|
|
77
|
-
const pendingEvents = [];
|
|
78
|
-
const eventHandlers = new Map();
|
|
79
|
-
let ws = null;
|
|
80
|
-
let settled = false;
|
|
81
|
-
let readyState = 0;
|
|
82
|
-
let binaryType = 'arraybuffer';
|
|
83
|
-
|
|
84
|
-
const wrapper = {
|
|
85
|
-
get readyState() { return ws ? ws.readyState : readyState; },
|
|
86
|
-
get url() { return ws ? ws.url : ''; },
|
|
87
|
-
get protocol() { return ws ? ws.protocol : ''; },
|
|
88
|
-
get binaryType() { return ws ? ws.binaryType : binaryType; },
|
|
89
|
-
set binaryType(v) {
|
|
90
|
-
binaryType = v;
|
|
91
|
-
if (ws) ws.binaryType = v;
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
send(data, callback) {
|
|
95
|
-
if (ws) {
|
|
96
|
-
if (ws.send.length >= 2) return ws.send(data, callback);
|
|
97
|
-
try { ws.send(data); if (callback) callback(null); } catch (e) { if (callback) callback(e); }
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
pendingEvents.push({ type: 'send', data, callback });
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
close(code, reason) {
|
|
104
|
-
if (ws) { ws.close(code, reason); return; }
|
|
105
|
-
readyState = 3;
|
|
106
|
-
pendingEvents.push({ type: 'close', code, reason });
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
addEventListener(type, handler) {
|
|
110
|
-
if (!eventHandlers.has(type)) eventHandlers.set(type, new Set());
|
|
111
|
-
eventHandlers.get(type).add(handler);
|
|
112
|
-
if (ws) ws.addEventListener(type, handler);
|
|
113
|
-
},
|
|
114
|
-
|
|
115
|
-
removeEventListener(type, handler) {
|
|
116
|
-
const handlers = eventHandlers.get(type);
|
|
117
|
-
if (handlers) handlers.delete(handler);
|
|
118
|
-
if (ws) ws.removeEventListener(type, handler);
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
on(type, handler) { wrapper.addEventListener(type, handler); },
|
|
122
|
-
off(type, handler) { wrapper.removeEventListener(type, handler); },
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
function flushPendingEvents() {
|
|
126
|
-
for (const evt of pendingEvents) {
|
|
127
|
-
if (evt.type === 'send') {
|
|
128
|
-
if (ws.send.length >= 2) ws.send(evt.data, evt.callback);
|
|
129
|
-
else { try { ws.send(evt.data); if (evt.callback) evt.callback(null); } catch (e) { if (evt.callback) evt.callback(e); } }
|
|
130
|
-
} else if (evt.type === 'close') {
|
|
131
|
-
ws.close(evt.code, evt.reason);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
pendingEvents.length = 0;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
wsPromise.then((resolvedWs) => {
|
|
138
|
-
ws = resolvedWs;
|
|
139
|
-
if ('binaryType' in ws) ws.binaryType = binaryType;
|
|
140
|
-
for (const [type, handlers] of eventHandlers) {
|
|
141
|
-
for (const handler of handlers) {
|
|
142
|
-
ws.addEventListener(type, handler);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
flushPendingEvents();
|
|
146
|
-
}).catch((err) => {
|
|
147
|
-
readyState = 3;
|
|
148
|
-
const handlers = eventHandlers.get('error');
|
|
149
|
-
if (handlers) for (const h of handlers) h(err instanceof Error ? err : new Error(String(err)));
|
|
150
|
-
const closeHandlers = eventHandlers.get('close');
|
|
151
|
-
if (closeHandlers) for (const h of closeHandlers) h({ code: 1006, reason: err.message || String(err) });
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
return wrapper;
|
|
155
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
|
|
5
|
-
function baseHome() {
|
|
6
|
-
return process.env.HUAWEICLOUD_HOME || homedir();
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function proxyConfigPath() {
|
|
10
|
-
return join(baseHome(), '.config', 'huaweicloud', 'proxy.json');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function readProxyConfig() {
|
|
14
|
-
const path = proxyConfigPath();
|
|
15
|
-
if (!existsSync(path)) return null;
|
|
16
|
-
try {
|
|
17
|
-
return JSON.parse(readFileSync(path, 'utf8'));
|
|
18
|
-
} catch {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function writeProxyConfig(config = {}) {
|
|
24
|
-
const path = proxyConfigPath();
|
|
25
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
26
|
-
const payload = {
|
|
27
|
-
https_proxy: String(config.https_proxy || ''),
|
|
28
|
-
http_proxy: String(config.http_proxy || ''),
|
|
29
|
-
no_proxy: String(config.no_proxy || ''),
|
|
30
|
-
};
|
|
31
|
-
writeFileSync(path, JSON.stringify(payload, null, 2), { encoding: 'utf8' });
|
|
32
|
-
return path;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function clearProxyConfig() {
|
|
36
|
-
const path = proxyConfigPath();
|
|
37
|
-
if (!existsSync(path)) return false;
|
|
38
|
-
rmSync(path);
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function shouldBypassProxy(hostname, noProxyList) {
|
|
43
|
-
if (!noProxyList.length) return false;
|
|
44
|
-
const lower = hostname.toLowerCase();
|
|
45
|
-
for (const pattern of noProxyList) {
|
|
46
|
-
const p = pattern.trim().toLowerCase();
|
|
47
|
-
if (!p) continue;
|
|
48
|
-
if (p === lower) return true;
|
|
49
|
-
if (p === '*') return true;
|
|
50
|
-
if (p.startsWith('.') && lower.endsWith(p)) return true;
|
|
51
|
-
if (lower.endsWith('.' + p)) return true;
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function getProxySettings(targetUrl) {
|
|
57
|
-
const envHttps = process.env.HTTPS_PROXY || process.env.https_proxy || '';
|
|
58
|
-
const envHttp = process.env.HTTP_PROXY || process.env.http_proxy || '';
|
|
59
|
-
const envNoProxy = process.env.NO_PROXY || process.env.no_proxy || '';
|
|
60
|
-
|
|
61
|
-
const fileConfig = readProxyConfig();
|
|
62
|
-
|
|
63
|
-
const https_proxy = envHttps || (fileConfig?.https_proxy || '');
|
|
64
|
-
const http_proxy = envHttp || (fileConfig?.http_proxy || '');
|
|
65
|
-
const no_proxy = envNoProxy || (fileConfig?.no_proxy || '');
|
|
66
|
-
|
|
67
|
-
if (!https_proxy && !http_proxy) return null;
|
|
68
|
-
|
|
69
|
-
const noProxyList = no_proxy.split(',').map((s) => s.trim()).filter(Boolean);
|
|
70
|
-
|
|
71
|
-
if (targetUrl) {
|
|
72
|
-
const parsed = new URL(targetUrl);
|
|
73
|
-
if (shouldBypassProxy(parsed.hostname, noProxyList)) return null;
|
|
74
|
-
const isHttps = parsed.protocol === 'https:';
|
|
75
|
-
const proxyUrl = isHttps ? https_proxy : http_proxy;
|
|
76
|
-
if (!proxyUrl) return null;
|
|
77
|
-
return { proxyUrl, noProxyList, targetProtocol: parsed.protocol };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return { https_proxy, http_proxy, no_proxy, noProxyList };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function getProxyUrlForTarget(targetUrl) {
|
|
84
|
-
const settings = getProxySettings(targetUrl);
|
|
85
|
-
if (!settings) return null;
|
|
86
|
-
return settings.proxyUrl || null;
|
|
87
|
-
}
|