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
|
@@ -8,7 +8,6 @@ import { createInterface } from 'node:readline';
|
|
|
8
8
|
import { spawnSync } from 'node:child_process';
|
|
9
9
|
import { getAuthStatus, syncAuth } from './auth/service.mjs';
|
|
10
10
|
import { globalCredentialsPath, readGlobalCredentials, writeGlobalCredentials, writeObsConfig } from './auth/credentials.mjs';
|
|
11
|
-
import { proxyConfigPath, readProxyConfig, writeProxyConfig, clearProxyConfig, getProxySettings } from './proxy/proxy-config.mjs';
|
|
12
11
|
|
|
13
12
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
13
|
const PLUGIN_ROOT = resolve(__dirname, '..');
|
|
@@ -57,15 +56,6 @@ function workbuddySkillsDir() { return join(homedir(), '.workbuddy', 'skills');
|
|
|
57
56
|
function workbuddyMcpConfigFile() { return join(homedir(), '.workbuddy', 'mcp.json'); }
|
|
58
57
|
function workbuddyPluginsDir() { return join(homedir(), '.workbuddy', 'huaweicloud-plugins'); }
|
|
59
58
|
|
|
60
|
-
function dshRoot() { return process.env.DSH_HOME || join(homedir(), '.dsh'); }
|
|
61
|
-
function dshSkillsDir() { return join(dshRoot(), 'skills'); }
|
|
62
|
-
function dshProfileDir() { return join(dshRoot(), 'profiles', 'web'); }
|
|
63
|
-
function dshPatchFile() { return join(dshProfileDir(), 'cordis.patch.yml'); }
|
|
64
|
-
function dshPluginsDir() { return join(dshRoot(), 'huaweicloud-plugins'); }
|
|
65
|
-
|
|
66
|
-
const DSH_MCP_PATCH_START = '# HuaweiCloud DevKit DSH integration start';
|
|
67
|
-
const DSH_MCP_PATCH_END = '# HuaweiCloud DevKit DSH integration end';
|
|
68
|
-
|
|
69
59
|
// Detect CodeArts sandbox mode (bash_mode in permission config).
|
|
70
60
|
function detectCodeartsSandbox() {
|
|
71
61
|
try {
|
|
@@ -768,261 +758,6 @@ function workbuddyStatus() {
|
|
|
768
758
|
}
|
|
769
759
|
}
|
|
770
760
|
|
|
771
|
-
function dshMcpServerPath() {
|
|
772
|
-
return join(dshPluginsDir(), 'src', 'mcp-server.mjs').replace(/\\/g, '/');
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
function dshPatchBlock() {
|
|
776
|
-
const hcloudBin = findHcloudBin();
|
|
777
|
-
const envLines = [
|
|
778
|
-
' HUAWEICLOUD_AGENT_TOOLKIT_MODE: local',
|
|
779
|
-
" HDKITSERVICE_ENDPOINT: ''",
|
|
780
|
-
];
|
|
781
|
-
if (hcloudBin) {
|
|
782
|
-
envLines.push(` HCLOUD_BIN: '${hcloudBin.replace(/\\/g, '/').replace(/'/g, "''")}'`);
|
|
783
|
-
}
|
|
784
|
-
return [
|
|
785
|
-
DSH_MCP_PATCH_START,
|
|
786
|
-
'- insert:',
|
|
787
|
-
' - id: mcp-huaweicloud',
|
|
788
|
-
" name: '@deepseek-ai/dsh-mcp-client'",
|
|
789
|
-
' config:',
|
|
790
|
-
' serverName: huaweicloud',
|
|
791
|
-
' transport: stdio',
|
|
792
|
-
' command: node',
|
|
793
|
-
' args:',
|
|
794
|
-
` - '${dshMcpServerPath().replace(/'/g, "''")}'`,
|
|
795
|
-
' env:',
|
|
796
|
-
...envLines,
|
|
797
|
-
' failOnStartupError: false',
|
|
798
|
-
DSH_MCP_PATCH_END,
|
|
799
|
-
].join('\n');
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
function escapeRegExp(value) {
|
|
803
|
-
return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
function removeManagedDshPatchBlock(content) {
|
|
807
|
-
const pattern = new RegExp(`\\n?${escapeRegExp(DSH_MCP_PATCH_START)}[\\s\\S]*?${escapeRegExp(DSH_MCP_PATCH_END)}\\s*`, 'g');
|
|
808
|
-
return String(content || '').replace(pattern, '\n').replace(/\n{3,}/g, '\n\n').trimEnd();
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
function dshPatchHasOnlyCommentsOrEmptyList(content) {
|
|
812
|
-
const meaningful = String(content || '')
|
|
813
|
-
.split(/\r?\n/)
|
|
814
|
-
.map((line) => line.trim())
|
|
815
|
-
.filter((line) => line && !line.startsWith('#'));
|
|
816
|
-
return meaningful.length === 0 || (meaningful.length === 1 && meaningful[0] === '[]');
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
function ensureDshMcpPatch() {
|
|
820
|
-
const patchFile = dshPatchFile();
|
|
821
|
-
const existing = existsSync(patchFile) ? readFileSync(patchFile, 'utf8') : '';
|
|
822
|
-
const cleaned = removeManagedDshPatchBlock(existing);
|
|
823
|
-
const block = dshPatchBlock();
|
|
824
|
-
let next;
|
|
825
|
-
if (dshPatchHasOnlyCommentsOrEmptyList(cleaned)) {
|
|
826
|
-
const prefix = cleaned
|
|
827
|
-
.split(/\r?\n/)
|
|
828
|
-
.filter((line) => line.trim() !== '[]')
|
|
829
|
-
.join('\n')
|
|
830
|
-
.trimEnd();
|
|
831
|
-
next = `${prefix ? `${prefix}\n` : ''}${block}\n`;
|
|
832
|
-
} else {
|
|
833
|
-
next = `${cleaned}\n\n${block}\n`;
|
|
834
|
-
}
|
|
835
|
-
if (existing.replace(/\r\n/g, '\n') === next) {
|
|
836
|
-
console.log(` DSH patch unchanged: ${patchFile}`);
|
|
837
|
-
return false;
|
|
838
|
-
}
|
|
839
|
-
mkdirSync(dirname(patchFile), { recursive: true });
|
|
840
|
-
writeFileSync(patchFile, next);
|
|
841
|
-
console.log(` DSH patch updated: ${patchFile}`);
|
|
842
|
-
return true;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
function removeDshMcpPatch() {
|
|
846
|
-
const patchFile = dshPatchFile();
|
|
847
|
-
if (!existsSync(patchFile)) return false;
|
|
848
|
-
const existing = readFileSync(patchFile, 'utf8');
|
|
849
|
-
const cleaned = removeManagedDshPatchBlock(existing);
|
|
850
|
-
if (cleaned === existing.trimEnd()) return false;
|
|
851
|
-
const prefix = cleaned
|
|
852
|
-
.split(/\r?\n/)
|
|
853
|
-
.filter((line) => line.trim() !== '[]')
|
|
854
|
-
.join('\n')
|
|
855
|
-
.trimEnd();
|
|
856
|
-
const next = dshPatchHasOnlyCommentsOrEmptyList(cleaned)
|
|
857
|
-
? `${prefix ? `${prefix}\n` : ''}[]\n`
|
|
858
|
-
: `${cleaned}\n`;
|
|
859
|
-
writeFileSync(patchFile, next);
|
|
860
|
-
console.log(` DSH patch cleaned: ${patchFile}`);
|
|
861
|
-
return true;
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
function dshPatchConfigured() {
|
|
865
|
-
const patchFile = dshPatchFile();
|
|
866
|
-
if (!existsSync(patchFile)) return false;
|
|
867
|
-
try {
|
|
868
|
-
const patch = readFileSync(patchFile, 'utf8');
|
|
869
|
-
return patch.includes('id: mcp-huaweicloud')
|
|
870
|
-
&& patch.includes("@deepseek-ai/dsh-mcp-client")
|
|
871
|
-
&& patch.includes('serverName: huaweicloud');
|
|
872
|
-
} catch {
|
|
873
|
-
return false;
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
function commandAvailable(command, args = ['--version']) {
|
|
878
|
-
try {
|
|
879
|
-
const r = spawnSync(command, args, { shell: false, windowsHide: true, stdio: 'pipe', timeout: 10000 });
|
|
880
|
-
if (r.status === 0) return true;
|
|
881
|
-
} catch {}
|
|
882
|
-
if (process.platform === 'win32') {
|
|
883
|
-
try {
|
|
884
|
-
const w = spawnSync('where.exe', [command], { windowsHide: true, stdio: 'pipe', timeout: 10000 });
|
|
885
|
-
return w.status === 0 && w.stdout.toString().trim().length > 0;
|
|
886
|
-
} catch {}
|
|
887
|
-
}
|
|
888
|
-
return false;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
function dshMcpClientAvailable() {
|
|
892
|
-
const modulePath = join('node_modules', '@deepseek-ai', 'dsh-mcp-client', 'package.json');
|
|
893
|
-
const candidates = [
|
|
894
|
-
join(dshProfileDir(), modulePath),
|
|
895
|
-
join(dshRoot(), 'profiles', modulePath),
|
|
896
|
-
join(dshRoot(), modulePath),
|
|
897
|
-
];
|
|
898
|
-
if (candidates.some((p) => existsSync(p))) return true;
|
|
899
|
-
const pkgPath = join(dshProfileDir(), 'package.json');
|
|
900
|
-
if (!existsSync(pkgPath)) return false;
|
|
901
|
-
try {
|
|
902
|
-
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
903
|
-
return Boolean(pkg.dependencies?.['@deepseek-ai/dsh-mcp-client']
|
|
904
|
-
|| pkg.devDependencies?.['@deepseek-ai/dsh-mcp-client']);
|
|
905
|
-
} catch {
|
|
906
|
-
return false;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
function tryInstallDshMcpClient() {
|
|
911
|
-
if (process.env.HUAWEICLOUD_DEVKIT_SKIP_DSH_PLUGIN_INSTALL === '1') {
|
|
912
|
-
console.log(' DSH MCP client install skipped by environment');
|
|
913
|
-
return false;
|
|
914
|
-
}
|
|
915
|
-
if (dshMcpClientAvailable()) {
|
|
916
|
-
console.log(' DSH MCP client package detected');
|
|
917
|
-
return true;
|
|
918
|
-
}
|
|
919
|
-
if (commandAvailable('dsh')) {
|
|
920
|
-
const r = spawnSync('dsh', ['plugin', '--profile', 'web', 'add', '@deepseek-ai/dsh-mcp-client'], {
|
|
921
|
-
env: { ...process.env, DSH_HOME: dshRoot() },
|
|
922
|
-
windowsHide: true,
|
|
923
|
-
stdio: 'pipe',
|
|
924
|
-
timeout: 60000,
|
|
925
|
-
});
|
|
926
|
-
if (r.status === 0) {
|
|
927
|
-
console.log(' DSH MCP client package installed via dsh');
|
|
928
|
-
return true;
|
|
929
|
-
}
|
|
930
|
-
const err = `${r.stderr || ''}${r.stdout || ''}`.trim().split(/\r?\n/).slice(-2).join(' ');
|
|
931
|
-
console.log(` \x1b[33m[WARN]\x1b[0m DSH MCP client auto-install failed${err ? `: ${err}` : ''}`);
|
|
932
|
-
}
|
|
933
|
-
if (commandAvailable('pnpm') && existsSync(join(dshProfileDir(), 'package.json'))) {
|
|
934
|
-
const r = spawnSync('pnpm', ['--dir', dshProfileDir(), 'add', '@deepseek-ai/dsh-mcp-client'], {
|
|
935
|
-
windowsHide: true,
|
|
936
|
-
stdio: 'pipe',
|
|
937
|
-
timeout: 60000,
|
|
938
|
-
});
|
|
939
|
-
if (r.status === 0) {
|
|
940
|
-
console.log(' DSH MCP client package installed via pnpm');
|
|
941
|
-
return true;
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
console.log(' \x1b[33m[WARN]\x1b[0m DSH MCP client package not detected.');
|
|
945
|
-
console.log(' Manual: npx @deepseek-ai/dsh plugin --profile web add @deepseek-ai/dsh-mcp-client');
|
|
946
|
-
console.log(' If pnpm is missing, run: corepack enable pnpm');
|
|
947
|
-
return false;
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
async function installDsh() {
|
|
951
|
-
const skillsSrc = join(PLUGIN_ROOT, 'skills');
|
|
952
|
-
const srcDir = join(PLUGIN_ROOT, 'src');
|
|
953
|
-
const safetyDir = join(PLUGIN_ROOT, 'safety');
|
|
954
|
-
const pluginDest = dshPluginsDir();
|
|
955
|
-
|
|
956
|
-
copyDir(skillsSrc, dshSkillsDir());
|
|
957
|
-
console.log(` Skills -> ${dshSkillsDir()}`);
|
|
958
|
-
copyDir(srcDir, join(pluginDest, 'src'));
|
|
959
|
-
console.log(` MCP Server -> ${join(pluginDest, 'src')}`);
|
|
960
|
-
copyDir(safetyDir, join(pluginDest, 'safety'));
|
|
961
|
-
console.log(` Safety Policy -> ${join(pluginDest, 'safety')}`);
|
|
962
|
-
ensureDshMcpPatch();
|
|
963
|
-
tryInstallDshMcpClient();
|
|
964
|
-
mkdirSync(pluginDest, { recursive: true });
|
|
965
|
-
writeFileSync(join(pluginDest, '.installed'), new Date().toISOString());
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
async function updateDsh() {
|
|
969
|
-
const skillsSrc = join(PLUGIN_ROOT, 'skills');
|
|
970
|
-
const srcDir = join(PLUGIN_ROOT, 'src');
|
|
971
|
-
const safetyDir = join(PLUGIN_ROOT, 'safety');
|
|
972
|
-
const pluginDest = dshPluginsDir();
|
|
973
|
-
|
|
974
|
-
copyDir(skillsSrc, dshSkillsDir());
|
|
975
|
-
const stale = pruneStale(dshSkillsDir(), skillsSrc);
|
|
976
|
-
console.log(` Skills updated -> ${dshSkillsDir()}${stale > 0 ? ` (removed ${stale} stale)` : ''}`);
|
|
977
|
-
copyDir(srcDir, join(pluginDest, 'src'));
|
|
978
|
-
console.log(` MCP Server updated -> ${join(pluginDest, 'src')}`);
|
|
979
|
-
copyDir(safetyDir, join(pluginDest, 'safety'));
|
|
980
|
-
console.log(` Safety Policy updated -> ${join(pluginDest, 'safety')}`);
|
|
981
|
-
ensureDshMcpPatch();
|
|
982
|
-
tryInstallDshMcpClient();
|
|
983
|
-
mkdirSync(pluginDest, { recursive: true });
|
|
984
|
-
writeFileSync(join(pluginDest, '.installed'), new Date().toISOString());
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
function uninstallDsh() {
|
|
988
|
-
const skillsDir = dshSkillsDir();
|
|
989
|
-
let removed = 0;
|
|
990
|
-
if (existsSync(skillsDir)) {
|
|
991
|
-
for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
992
|
-
if (entry.name.startsWith('huawei')) {
|
|
993
|
-
removeIfExists(join(skillsDir, entry.name));
|
|
994
|
-
removed++;
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
if (removed > 0) console.log(` Removed ${removed} skills`);
|
|
998
|
-
try {
|
|
999
|
-
if (readdirSync(skillsDir).length === 0) {
|
|
1000
|
-
rmSync(skillsDir, { recursive: true, force: true });
|
|
1001
|
-
console.log(` Removed empty skills directory: ${skillsDir}`);
|
|
1002
|
-
}
|
|
1003
|
-
} catch {}
|
|
1004
|
-
}
|
|
1005
|
-
if (removeIfExists(dshPluginsDir())) {
|
|
1006
|
-
console.log(' Removed MCP server and safety policy');
|
|
1007
|
-
}
|
|
1008
|
-
removeDshMcpPatch();
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
function dshStatus() {
|
|
1012
|
-
const pluginDir = dshPluginsDir();
|
|
1013
|
-
const skillsDir = dshSkillsDir();
|
|
1014
|
-
console.log(` MCP Server: ${existsSync(join(pluginDir, 'src', 'mcp-server.mjs')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`);
|
|
1015
|
-
console.log(` Safety Policy: ${existsSync(join(pluginDir, 'safety', 'policy.json')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`);
|
|
1016
|
-
let skillCount = 0;
|
|
1017
|
-
if (existsSync(skillsDir)) {
|
|
1018
|
-
skillCount = readdirSync(skillsDir, { withFileTypes: true })
|
|
1019
|
-
.filter((d) => d.isDirectory() && d.name.startsWith('huawei')).length;
|
|
1020
|
-
}
|
|
1021
|
-
console.log(` Skills: ${skillCount > 0 ? `\x1b[32m${skillCount} installed\x1b[0m` : '\x1b[31mNot installed\x1b[0m'}`);
|
|
1022
|
-
console.log(` DSH patch: ${dshPatchConfigured() ? '\x1b[32mConfigured\x1b[0m' : '\x1b[31mNot configured\x1b[0m'}`);
|
|
1023
|
-
console.log(` DSH MCP client package: ${dshMcpClientAvailable() ? '\x1b[32mDetected\x1b[0m' : '\x1b[33mCheck DSH profile\x1b[0m'}`);
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
761
|
function opencodeStatus() {
|
|
1027
762
|
const pluginDir = opencodePluginsDir();
|
|
1028
763
|
const skillsDir = opencodeSkillsDir();
|
|
@@ -1053,7 +788,6 @@ function parseTarget() {
|
|
|
1053
788
|
if (val === 'codex-desktop') return 'codex-desktop';
|
|
1054
789
|
if (val === 'codearts') return 'codearts';
|
|
1055
790
|
if (val === 'workbuddy') return 'workbuddy';
|
|
1056
|
-
if (val === 'dsh') return 'dsh';
|
|
1057
791
|
if (val === 'all') return 'all';
|
|
1058
792
|
return 'opencode';
|
|
1059
793
|
}
|
|
@@ -1080,10 +814,6 @@ async function cmdInstall() {
|
|
|
1080
814
|
console.log('\n[WorkBuddy]');
|
|
1081
815
|
await installWorkBuddy();
|
|
1082
816
|
}
|
|
1083
|
-
if (target === 'dsh' || target === 'all') {
|
|
1084
|
-
console.log('\n[DSH]');
|
|
1085
|
-
await installDsh();
|
|
1086
|
-
}
|
|
1087
817
|
if (target === 'codex' || target === 'all') {
|
|
1088
818
|
console.log('\n[Codex]');
|
|
1089
819
|
if (!hasCodexCLI()) {
|
|
@@ -1106,13 +836,11 @@ async function cmdInstall() {
|
|
|
1106
836
|
} else {
|
|
1107
837
|
installCodex();
|
|
1108
838
|
}
|
|
1109
|
-
}
|
|
1110
|
-
console.log(`\n\x1b[32mInstallation complete!\x1b[0m`);
|
|
839
|
+
} console.log(`\n\x1b[32mInstallation complete!\x1b[0m`);
|
|
1111
840
|
const appName = target === 'codearts' ? 'CodeArts'
|
|
1112
841
|
: target === 'codex-desktop' ? 'Codex Desktop'
|
|
1113
842
|
: target === 'codex' ? 'Codex'
|
|
1114
843
|
: target === 'workbuddy' ? 'WorkBuddy'
|
|
1115
|
-
: target === 'dsh' ? 'DSH'
|
|
1116
844
|
: 'OpenCode';
|
|
1117
845
|
const pad = ' '.repeat(24 - appName.length);
|
|
1118
846
|
console.log(`\n\x1b[1m\x1b[33m╔══════════════════════════════════════════════════════╗`);
|
|
@@ -1135,8 +863,7 @@ async function cmdInstall() {
|
|
|
1135
863
|
console.log(` 3. 运行自检:npx huaweicloud-devkit doctor`);
|
|
1136
864
|
|
|
1137
865
|
// Write install marker for doctor to detect
|
|
1138
|
-
const markerDir = target === '
|
|
1139
|
-
: target === 'codearts' ? codeartsPluginsDir()
|
|
866
|
+
const markerDir = target === 'codearts' ? codeartsPluginsDir()
|
|
1140
867
|
: target === 'workbuddy' ? workbuddyPluginsDir()
|
|
1141
868
|
: target === 'codex-desktop' ? codexDesktopPluginsDir()
|
|
1142
869
|
: opencodePluginsDir();
|
|
@@ -1154,9 +881,6 @@ async function cmdInstall() {
|
|
|
1154
881
|
if (target === 'workbuddy' || target === 'all') {
|
|
1155
882
|
console.log('Or describe your Huawei Cloud task in WorkBuddy');
|
|
1156
883
|
}
|
|
1157
|
-
if (target === 'dsh' || target === 'all') {
|
|
1158
|
-
console.log('Or describe your Huawei Cloud task in DSH');
|
|
1159
|
-
}
|
|
1160
884
|
}
|
|
1161
885
|
|
|
1162
886
|
async function cmdUninstall() {
|
|
@@ -1176,10 +900,6 @@ async function cmdUninstall() {
|
|
|
1176
900
|
console.log('\n[WorkBuddy]');
|
|
1177
901
|
uninstallWorkBuddy();
|
|
1178
902
|
}
|
|
1179
|
-
if (target === 'dsh' || target === 'all') {
|
|
1180
|
-
console.log('\n[DSH]');
|
|
1181
|
-
uninstallDsh();
|
|
1182
|
-
}
|
|
1183
903
|
if (target === 'codex-desktop' || target === 'codex' || target === 'all') {
|
|
1184
904
|
console.log('\n[Codex]');
|
|
1185
905
|
uninstallCodexDesktop();
|
|
@@ -1224,10 +944,6 @@ async function cmdStatus() {
|
|
|
1224
944
|
console.log('\n[WorkBuddy]');
|
|
1225
945
|
workbuddyStatus();
|
|
1226
946
|
}
|
|
1227
|
-
if (target === 'dsh' || target === 'all') {
|
|
1228
|
-
console.log('\n[DSH]');
|
|
1229
|
-
dshStatus();
|
|
1230
|
-
}
|
|
1231
947
|
if (target === 'codex' || target === 'all') {
|
|
1232
948
|
console.log('\n[Codex]');
|
|
1233
949
|
if (!hasCodexCLI()) {
|
|
@@ -1255,22 +971,16 @@ async function cmdDoctor() {
|
|
|
1255
971
|
// Node.js
|
|
1256
972
|
check('Node.js >= 20', process.versions.node.split('.')[0] >= 20, 'Run: nvm install 20 && nvm use 20');
|
|
1257
973
|
|
|
1258
|
-
// MCP server — check OpenCode, Codex Desktop, CodeArts,
|
|
974
|
+
// MCP server — check OpenCode, Codex Desktop, CodeArts, and WorkBuddy paths
|
|
1259
975
|
const opencodePluginDir = opencodePluginsDir();
|
|
1260
976
|
const codexPluginDir = codexDesktopPluginsDir();
|
|
1261
|
-
const codeartsPluginDir = codeartsPluginsDir();
|
|
1262
977
|
const workbuddyPluginDir = workbuddyPluginsDir();
|
|
1263
|
-
const dshPluginDir = dshPluginsDir();
|
|
1264
978
|
const mcpOk = existsSync(join(opencodePluginDir, 'src', 'mcp-server.mjs'))
|
|
1265
979
|
|| existsSync(join(codexPluginDir, 'src', 'mcp-server.mjs'))
|
|
1266
|
-
|| existsSync(join(
|
|
1267
|
-
|| existsSync(join(workbuddyPluginDir, 'src', 'mcp-server.mjs'))
|
|
1268
|
-
|| existsSync(join(dshPluginDir, 'src', 'mcp-server.mjs'));
|
|
980
|
+
|| existsSync(join(workbuddyPluginDir, 'src', 'mcp-server.mjs'));
|
|
1269
981
|
const mcpTarget = existsSync(join(opencodePluginDir, 'src', 'mcp-server.mjs')) ? 'OpenCode'
|
|
1270
982
|
: existsSync(join(codexPluginDir, 'src', 'mcp-server.mjs')) ? 'Codex Desktop'
|
|
1271
|
-
: existsSync(join(
|
|
1272
|
-
: existsSync(join(workbuddyPluginDir, 'src', 'mcp-server.mjs')) ? 'WorkBuddy'
|
|
1273
|
-
: existsSync(join(dshPluginDir, 'src', 'mcp-server.mjs')) ? 'DSH' : '';
|
|
983
|
+
: existsSync(join(workbuddyPluginDir, 'src', 'mcp-server.mjs')) ? 'WorkBuddy' : '';
|
|
1274
984
|
check('MCP server installed', mcpOk, 'Run: npx huaweicloud-devkit install');
|
|
1275
985
|
|
|
1276
986
|
if (mcpOk) {
|
|
@@ -1279,12 +989,10 @@ async function cmdDoctor() {
|
|
|
1279
989
|
|
|
1280
990
|
const safetyOk = existsSync(join(opencodePluginDir, 'safety', 'policy.json'))
|
|
1281
991
|
|| existsSync(join(codexPluginDir, 'safety', 'policy.json'))
|
|
1282
|
-
|| existsSync(join(
|
|
1283
|
-
|| existsSync(join(workbuddyPluginDir, 'safety', 'policy.json'))
|
|
1284
|
-
|| existsSync(join(dshPluginDir, 'safety', 'policy.json'));
|
|
992
|
+
|| existsSync(join(workbuddyPluginDir, 'safety', 'policy.json'));
|
|
1285
993
|
check('Safety policy installed', safetyOk, 'Run: npx huaweicloud-devkit install');
|
|
1286
994
|
|
|
1287
|
-
// MCP config — check OpenCode, Codex Desktop,
|
|
995
|
+
// MCP config — check OpenCode, Codex Desktop, and WorkBuddy
|
|
1288
996
|
let mcpConfigured = false;
|
|
1289
997
|
let mcpCfgTarget = '';
|
|
1290
998
|
const opencodeCfg = opencodeConfigFile();
|
|
@@ -1301,13 +1009,6 @@ async function cmdDoctor() {
|
|
|
1301
1009
|
if (cfg.includes('[mcp_servers.huaweicloud-devkit]')) { mcpConfigured = true; mcpCfgTarget = 'Codex Desktop'; }
|
|
1302
1010
|
} catch {}
|
|
1303
1011
|
}
|
|
1304
|
-
const codeartsCfg = codeartsMcpSettingsFile();
|
|
1305
|
-
if (!mcpConfigured && existsSync(codeartsCfg)) {
|
|
1306
|
-
try {
|
|
1307
|
-
const cfg = JSON.parse(readFileSync(codeartsCfg, 'utf8'));
|
|
1308
|
-
if (cfg.mcpServers && cfg.mcpServers['huaweicloud-devkit']) { mcpConfigured = true; mcpCfgTarget = 'CodeArts'; }
|
|
1309
|
-
} catch {}
|
|
1310
|
-
}
|
|
1311
1012
|
const workbuddyCfg = workbuddyMcpConfigFile();
|
|
1312
1013
|
if (!mcpConfigured && existsSync(workbuddyCfg)) {
|
|
1313
1014
|
try {
|
|
@@ -1315,10 +1016,6 @@ async function cmdDoctor() {
|
|
|
1315
1016
|
if (cfg.mcpServers && cfg.mcpServers['huaweicloud-devkit']) { mcpConfigured = true; mcpCfgTarget = 'WorkBuddy'; }
|
|
1316
1017
|
} catch {}
|
|
1317
1018
|
}
|
|
1318
|
-
if (!mcpConfigured && dshPatchConfigured()) {
|
|
1319
|
-
mcpConfigured = true;
|
|
1320
|
-
mcpCfgTarget = 'DSH';
|
|
1321
|
-
}
|
|
1322
1019
|
check('MCP configured', mcpConfigured, mcpCfgTarget ? `Found in ${mcpCfgTarget} config` : 'Run: npx huaweicloud-devkit install');
|
|
1323
1020
|
|
|
1324
1021
|
// hcloud CLI
|
|
@@ -1348,7 +1045,7 @@ async function cmdDoctor() {
|
|
|
1348
1045
|
}
|
|
1349
1046
|
|
|
1350
1047
|
// Skills
|
|
1351
|
-
const skillsOptions = [opencodeSkillsDir(), codexDesktopSkillsDir(), codeartsSkillsDir(), workbuddySkillsDir()
|
|
1048
|
+
const skillsOptions = [opencodeSkillsDir(), codexDesktopSkillsDir(), codeartsSkillsDir(), workbuddySkillsDir()];
|
|
1352
1049
|
let skillCount = 0, skillsDir = '', missingSkills = [];
|
|
1353
1050
|
for (const dir of skillsOptions) {
|
|
1354
1051
|
if (!existsSync(dir)) continue;
|
|
@@ -1367,14 +1064,6 @@ async function cmdDoctor() {
|
|
|
1367
1064
|
warn++;
|
|
1368
1065
|
}
|
|
1369
1066
|
|
|
1370
|
-
const proxyConfig = readProxyConfig();
|
|
1371
|
-
const proxyEnv = process.env.HTTPS_PROXY || process.env.https_proxy || process.env.HTTP_PROXY || process.env.http_proxy;
|
|
1372
|
-
if (proxyConfig || proxyEnv) {
|
|
1373
|
-
const source = proxyEnv ? 'env' : 'file';
|
|
1374
|
-
const proxyUrl = proxyEnv || proxyConfig.https_proxy || proxyConfig.http_proxy;
|
|
1375
|
-
console.log(` \x1b[36m[INFO]\x1b[0m Proxy configured (${source}): ${proxyUrl}`);
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
1067
|
console.log(`\nResults: ${pass} pass, ${warn} warn, ${fail} fail`);
|
|
1379
1068
|
|
|
1380
1069
|
if (mcpConfigured && !hcloudOk) {
|
|
@@ -1393,7 +1082,6 @@ async function cmdDoctor() {
|
|
|
1393
1082
|
{ path: join(codexDesktopPluginsDir(), '.installed'), name: 'Codex Desktop' },
|
|
1394
1083
|
{ path: join(workbuddyPluginsDir(), '.installed'), name: 'WorkBuddy' },
|
|
1395
1084
|
{ path: join(codeartsPluginsDir(), '.installed'), name: 'CodeArts' },
|
|
1396
|
-
{ path: join(dshPluginsDir(), '.installed'), name: 'DSH' },
|
|
1397
1085
|
];
|
|
1398
1086
|
for (const marker of installedMarkers) {
|
|
1399
1087
|
if (existsSync(marker.path)) {
|
|
@@ -1475,18 +1163,6 @@ async function cmdUpdate() {
|
|
|
1475
1163
|
return;
|
|
1476
1164
|
}
|
|
1477
1165
|
|
|
1478
|
-
if (target === 'dsh') {
|
|
1479
|
-
if (!existsSync(join(dshPluginsDir(), 'src', 'mcp-server.mjs'))) {
|
|
1480
|
-
console.log('\x1b[33mNot installed. Use "install" command first.\x1b[0m');
|
|
1481
|
-
return;
|
|
1482
|
-
}
|
|
1483
|
-
console.log('[DSH]');
|
|
1484
|
-
await updateDsh();
|
|
1485
|
-
console.log(`\n\x1b[32mUpdate complete.\x1b[0m`);
|
|
1486
|
-
console.log(`\x1b[33mRestart the DSH session for changes to take effect.\x1b[0m`);
|
|
1487
|
-
return;
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
1166
|
if (target === 'all') {
|
|
1491
1167
|
let updatedAny = false;
|
|
1492
1168
|
if (existsSync(join(opencodePluginsDir(), 'src', 'mcp-server.mjs'))) {
|
|
@@ -1509,11 +1185,6 @@ async function cmdUpdate() {
|
|
|
1509
1185
|
await updateWorkBuddy();
|
|
1510
1186
|
updatedAny = true;
|
|
1511
1187
|
}
|
|
1512
|
-
if (existsSync(join(dshPluginsDir(), 'src', 'mcp-server.mjs'))) {
|
|
1513
|
-
console.log('\n[DSH]');
|
|
1514
|
-
await updateDsh();
|
|
1515
|
-
updatedAny = true;
|
|
1516
|
-
}
|
|
1517
1188
|
if (codexStatus()) {
|
|
1518
1189
|
console.log('\n[Codex]');
|
|
1519
1190
|
installCodex();
|
|
@@ -1853,93 +1524,6 @@ async function cmdAuth() {
|
|
|
1853
1524
|
return cmdAuthStatus();
|
|
1854
1525
|
}
|
|
1855
1526
|
|
|
1856
|
-
async function cmdProxyInit() {
|
|
1857
|
-
console.log(BANNER);
|
|
1858
|
-
console.log('HuaweiCloud DevKit Proxy Configuration\n');
|
|
1859
|
-
console.log('Configure HTTP/HTTPS proxy for connections to Huawei Cloud services.');
|
|
1860
|
-
console.log('Proxy settings are saved to ~/.config/huaweicloud/proxy.json\n');
|
|
1861
|
-
|
|
1862
|
-
const existing = readProxyConfig() || {};
|
|
1863
|
-
const interactive = process.stdin.isTTY && process.stdout.isTTY;
|
|
1864
|
-
|
|
1865
|
-
if (!interactive) {
|
|
1866
|
-
console.error('\x1b[31mNon-interactive session. Set proxy via environment variables:\x1b[0m');
|
|
1867
|
-
console.error(' HTTPS_PROXY=http://proxy:port');
|
|
1868
|
-
console.error(' HTTP_PROXY=http://proxy:port');
|
|
1869
|
-
console.error(' NO_PROXY=localhost,127.0.0.1');
|
|
1870
|
-
console.error('\nOr run "npx huaweicloud-devkit proxy init" in a real terminal.');
|
|
1871
|
-
process.exitCode = 1;
|
|
1872
|
-
return;
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
const httpsProxy = await readLineQuestion(`HTTPS proxy [${existing.https_proxy || 'none'}]: `);
|
|
1876
|
-
const httpProxy = await readLineQuestion(`HTTP proxy [${existing.http_proxy || 'none'}]: `);
|
|
1877
|
-
const noProxy = await readLineQuestion(`NO_PROXY hosts [${existing.no_proxy || 'localhost,127.0.0.1'}]: `);
|
|
1878
|
-
|
|
1879
|
-
const config = {
|
|
1880
|
-
https_proxy: httpsProxy || existing.https_proxy || '',
|
|
1881
|
-
http_proxy: httpProxy || existing.http_proxy || '',
|
|
1882
|
-
no_proxy: noProxy || existing.no_proxy || 'localhost,127.0.0.1',
|
|
1883
|
-
};
|
|
1884
|
-
|
|
1885
|
-
const path = writeProxyConfig(config);
|
|
1886
|
-
console.log(`\nProxy configuration saved to ${path}`);
|
|
1887
|
-
console.log('\nEffective settings:');
|
|
1888
|
-
console.log(` HTTPS_PROXY: ${config.https_proxy || '(none)'}`);
|
|
1889
|
-
console.log(` HTTP_PROXY: ${config.http_proxy || '(none)'}`);
|
|
1890
|
-
console.log(` NO_PROXY: ${config.no_proxy || '(none)'}`);
|
|
1891
|
-
console.log('\nEnvironment variables (HTTPS_PROXY, HTTP_PROXY, NO_PROXY) override file settings.');
|
|
1892
|
-
}
|
|
1893
|
-
|
|
1894
|
-
async function cmdProxyShow() {
|
|
1895
|
-
console.log(BANNER);
|
|
1896
|
-
console.log('HuaweiCloud DevKit Proxy Configuration\n');
|
|
1897
|
-
|
|
1898
|
-
const config = readProxyConfig();
|
|
1899
|
-
const configPath = proxyConfigPath();
|
|
1900
|
-
|
|
1901
|
-
console.log(`Config file: ${configPath}`);
|
|
1902
|
-
console.log(`File exists: ${config ? 'yes' : 'no'}\n`);
|
|
1903
|
-
|
|
1904
|
-
if (config) {
|
|
1905
|
-
console.log('File settings:');
|
|
1906
|
-
console.log(` https_proxy: ${config.https_proxy || '(empty)'}`);
|
|
1907
|
-
console.log(` http_proxy: ${config.http_proxy || '(empty)'}`);
|
|
1908
|
-
console.log(` no_proxy: ${config.no_proxy || '(empty)'}`);
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
console.log('\nEnvironment variables:');
|
|
1912
|
-
console.log(` HTTPS_PROXY: ${process.env.HTTPS_PROXY || process.env.https_proxy || '(not set)'}`);
|
|
1913
|
-
console.log(` HTTP_PROXY: ${process.env.HTTP_PROXY || process.env.http_proxy || '(not set)'}`);
|
|
1914
|
-
console.log(` NO_PROXY: ${process.env.NO_PROXY || process.env.no_proxy || '(not set)'}`);
|
|
1915
|
-
|
|
1916
|
-
const effective = getProxySettings();
|
|
1917
|
-
console.log('\nEffective (env > file):');
|
|
1918
|
-
if (effective) {
|
|
1919
|
-
console.log(` https_proxy: ${effective.https_proxy || '(none)'}`);
|
|
1920
|
-
console.log(` http_proxy: ${effective.http_proxy || '(none)'}`);
|
|
1921
|
-
console.log(` no_proxy: ${effective.no_proxy || '(none)'}`);
|
|
1922
|
-
} else {
|
|
1923
|
-
console.log(' (no proxy configured)');
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
|
|
1927
|
-
async function cmdProxyClear() {
|
|
1928
|
-
const removed = clearProxyConfig();
|
|
1929
|
-
if (removed) {
|
|
1930
|
-
console.log('Proxy configuration removed.');
|
|
1931
|
-
} else {
|
|
1932
|
-
console.log('No proxy configuration file found.');
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
|
-
async function cmdProxy() {
|
|
1937
|
-
const sub = (process.argv[3] || 'show').toLowerCase();
|
|
1938
|
-
if (sub === 'init' || sub === 'setup') return cmdProxyInit();
|
|
1939
|
-
if (sub === 'clear' || sub === 'remove' || sub === 'reset') return cmdProxyClear();
|
|
1940
|
-
return cmdProxyShow();
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
1527
|
async function main() {
|
|
1944
1528
|
const cmd = process.argv[2] || 'help';
|
|
1945
1529
|
|
|
@@ -1973,15 +1557,12 @@ async function main() {
|
|
|
1973
1557
|
case 'auth':
|
|
1974
1558
|
await cmdAuth();
|
|
1975
1559
|
break;
|
|
1976
|
-
case 'proxy':
|
|
1977
|
-
await cmdProxy();
|
|
1978
|
-
break;
|
|
1979
1560
|
case 'help':
|
|
1980
1561
|
case '--help':
|
|
1981
1562
|
case '-h':
|
|
1982
1563
|
default:
|
|
1983
1564
|
console.log(BANNER);
|
|
1984
|
-
console.log('Usage: npx huaweicloud-devkit <command> [--target <opencode|codex|codearts|workbuddy|
|
|
1565
|
+
console.log('Usage: npx huaweicloud-devkit <command> [--target <opencode|codex|codearts|workbuddy|all>]\n');
|
|
1985
1566
|
console.log('Commands:');
|
|
1986
1567
|
console.log(' install Install skills, MCP server, safety policy');
|
|
1987
1568
|
console.log(' uninstall Remove installed files');
|
|
@@ -1991,22 +1572,18 @@ async function main() {
|
|
|
1991
1572
|
console.log(' doctor Self-check: hcloud, MCP, skills, auth');
|
|
1992
1573
|
console.log(' install-hcloud Show KooCLI install commands for your OS');
|
|
1993
1574
|
console.log(' auth Manage unified auth: init | sync | status');
|
|
1994
|
-
console.log(' proxy Manage proxy config: init | show | clear');
|
|
1995
1575
|
console.log(' help Show this help');
|
|
1996
1576
|
console.log('\nOptions:');
|
|
1997
|
-
console.log(' --target Target agent: opencode (default), codex, codearts, workbuddy,
|
|
1577
|
+
console.log(' --target Target agent: opencode (default), codex, codearts, workbuddy, all');
|
|
1998
1578
|
console.log('\nExamples:');
|
|
1999
1579
|
console.log(' npx huaweicloud-devkit install');
|
|
2000
1580
|
console.log(' npx huaweicloud-devkit install --target codex');
|
|
2001
1581
|
console.log(' npx huaweicloud-devkit install --target codearts');
|
|
2002
1582
|
console.log(' npx huaweicloud-devkit install --target workbuddy');
|
|
2003
|
-
console.log(' npx huaweicloud-devkit install --target dsh');
|
|
2004
1583
|
console.log(' npx huaweicloud-devkit install --target all');
|
|
2005
1584
|
console.log(' npx huaweicloud-devkit auth init');
|
|
2006
1585
|
console.log(' npx huaweicloud-devkit auth sync --target all');
|
|
2007
1586
|
console.log(' npx huaweicloud-devkit auth status --target all');
|
|
2008
|
-
console.log(' npx huaweicloud-devkit proxy init');
|
|
2009
|
-
console.log(' npx huaweicloud-devkit proxy show');
|
|
2010
1587
|
break;
|
|
2011
1588
|
}
|
|
2012
1589
|
}
|