huaweicloud-devkit 1.0.2-next.3 → 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.
Files changed (97) hide show
  1. package/.agents/plugins/marketplace.json +20 -20
  2. package/LICENSE +201 -201
  3. package/README.md +139 -163
  4. package/README.zh-CN.md +139 -161
  5. package/bin/setup.cjs +8 -8
  6. package/integrations/opencode/commands/huaweicloud-doctor.md +14 -14
  7. package/integrations/opencode/opencode.json +14 -14
  8. package/integrations/opencode/skills/huaweicloud-core/SKILL.md +32 -32
  9. package/package.json +44 -47
  10. package/plugins/huaweicloud-core/.claude-plugin/plugin.json +44 -44
  11. package/plugins/huaweicloud-core/.codex-plugin/plugin.json +43 -43
  12. package/plugins/huaweicloud-core/.cursor-plugin/plugin.json +44 -44
  13. package/plugins/huaweicloud-core/.mcp.json +15 -15
  14. package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +44 -44
  15. package/plugins/huaweicloud-core/hooks/hooks.json +26 -26
  16. package/plugins/huaweicloud-core/hooks/huaweicloud-safety.py +136 -136
  17. package/plugins/huaweicloud-core/safety/policy.json +99 -99
  18. package/plugins/huaweicloud-core/safety/rules/cloud-risk-rules.json +199 -199
  19. package/plugins/huaweicloud-core/skills/huawei-apig/SKILL.md +164 -164
  20. package/plugins/huaweicloud-core/skills/huawei-billing/SKILL.md +48 -48
  21. package/plugins/huaweicloud-core/skills/huawei-cbr/SKILL.md +50 -50
  22. package/plugins/huaweicloud-core/skills/huawei-cce/SKILL.md +101 -101
  23. package/plugins/huaweicloud-core/skills/huawei-cloud-eye/SKILL.md +90 -90
  24. package/plugins/huaweicloud-core/skills/huawei-cloud-find-skills/SKILL.md +190 -190
  25. package/plugins/huaweicloud-core/skills/huawei-cloud-find-skills/scripts/search-skills.mjs +124 -124
  26. package/plugins/huaweicloud-core/skills/huawei-cts/SKILL.md +55 -55
  27. package/plugins/huaweicloud-core/skills/huawei-dds-dcs/SKILL.md +70 -70
  28. package/plugins/huaweicloud-core/skills/huawei-deployment/SKILL.md +56 -56
  29. package/plugins/huaweicloud-core/skills/huawei-dew/SKILL.md +97 -97
  30. package/plugins/huaweicloud-core/skills/huawei-dew/references/csms-usage.md +29 -29
  31. package/plugins/huaweicloud-core/skills/huawei-dew/references/kms-usage.md +23 -23
  32. package/plugins/huaweicloud-core/skills/huawei-ecs/SKILL.md +185 -185
  33. package/plugins/huaweicloud-core/skills/huawei-ecs/references/create-instance.md +133 -133
  34. package/plugins/huaweicloud-core/skills/huawei-ecs/references/evs.md +31 -31
  35. package/plugins/huaweicloud-core/skills/huawei-ecs/references/flavors.md +55 -55
  36. package/plugins/huaweicloud-core/skills/huawei-ecs/references/troubleshooting.md +52 -52
  37. package/plugins/huaweicloud-core/skills/huawei-functiongraph/SKILL.md +131 -131
  38. package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/apig-event-format.md +58 -58
  39. package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/create-function.md +71 -71
  40. package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/deploy-workflow.md +119 -119
  41. package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/triggers.md +142 -142
  42. package/plugins/huaweicloud-core/skills/huawei-gaussdb/SKILL.md +56 -56
  43. package/plugins/huaweicloud-core/skills/huawei-getting-started/SKILL.md +65 -65
  44. package/plugins/huaweicloud-core/skills/huawei-iam/SKILL.md +111 -111
  45. package/plugins/huaweicloud-core/skills/huawei-iam/references/policy-examples.md +122 -122
  46. package/plugins/huaweicloud-core/skills/huawei-iam/references/quick-ref.md +56 -56
  47. package/plugins/huaweicloud-core/skills/huawei-modelarts/SKILL.md +65 -65
  48. package/plugins/huaweicloud-core/skills/huawei-obs/SKILL.md +127 -133
  49. package/plugins/huaweicloud-core/skills/huawei-obs/references/bucket-create.md +49 -49
  50. package/plugins/huaweicloud-core/skills/huawei-obs/references/bucket-lifecycle.md +26 -26
  51. package/plugins/huaweicloud-core/skills/huawei-obs/references/common-pitfalls.md +100 -100
  52. package/plugins/huaweicloud-core/skills/huawei-obs/references/single-file-share.md +40 -40
  53. package/plugins/huaweicloud-core/skills/huawei-obs/references/static-website.md +56 -56
  54. package/plugins/huaweicloud-core/skills/huawei-rds/SKILL.md +224 -224
  55. package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +134 -139
  56. package/plugins/huaweicloud-core/skills/huawei-smn-dms/SKILL.md +69 -69
  57. package/plugins/huaweicloud-core/skills/huawei-vpc/SKILL.md +84 -84
  58. package/plugins/huaweicloud-core/skills/huawei-vpc/references/network.md +76 -76
  59. package/plugins/huaweicloud-core/skills/huawei-vpc/references/security-group.md +59 -59
  60. package/plugins/huaweicloud-core/skills/huawei-vpc/references/subnet.md +50 -50
  61. package/plugins/huaweicloud-core/skills/huawei-waf-aad/SKILL.md +63 -63
  62. package/plugins/huaweicloud-core/skills/huaweicloud-api-and-sdk/SKILL.md +56 -56
  63. package/plugins/huaweicloud-core/skills/huaweicloud-api-and-sdk/agents/openai.yaml +4 -4
  64. package/plugins/huaweicloud-core/skills/huaweicloud-capability-discovery/SKILL.md +47 -51
  65. package/plugins/huaweicloud-core/skills/huaweicloud-capability-discovery/agents/openai.yaml +4 -4
  66. package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +128 -128
  67. package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/agents/openai.yaml +4 -4
  68. package/plugins/huaweicloud-core/skills/huaweicloud-core/SKILL.md +95 -110
  69. package/plugins/huaweicloud-core/skills/huaweicloud-core/agents/openai.yaml +4 -4
  70. package/plugins/huaweicloud-core/skills/huaweicloud-core/references/report-issue.md +19 -19
  71. package/plugins/huaweicloud-core/skills/huaweicloud-core/references/select.md +27 -27
  72. package/plugins/huaweicloud-core/skills/huaweicloud-safety/SKILL.md +60 -60
  73. package/plugins/huaweicloud-core/skills/huaweicloud-safety/agents/openai.yaml +4 -4
  74. package/plugins/huaweicloud-core/skills/huaweicloud-troubleshooting/SKILL.md +83 -83
  75. package/plugins/huaweicloud-core/skills/huaweicloud-troubleshooting/agents/openai.yaml +4 -4
  76. package/plugins/huaweicloud-core/src/auth/agent-registration.mjs +87 -105
  77. package/plugins/huaweicloud-core/src/auth/credentials.mjs +95 -95
  78. package/plugins/huaweicloud-core/src/auth/service.mjs +63 -63
  79. package/plugins/huaweicloud-core/src/hcloud-cli.mjs +265 -265
  80. package/plugins/huaweicloud-core/src/mcp-server.mjs +129 -129
  81. package/plugins/huaweicloud-core/src/risk-rule-engine.mjs +137 -137
  82. package/plugins/huaweicloud-core/src/safety-policy.mjs +302 -302
  83. package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +87 -91
  84. package/plugins/huaweicloud-core/src/sandbox/hwlink-api.mjs +153 -162
  85. package/plugins/huaweicloud-core/src/sandbox/session-manager.mjs +105 -112
  86. package/plugins/huaweicloud-core/src/search-market.mjs +169 -174
  87. package/plugins/huaweicloud-core/src/setup-cli.mjs +1594 -2017
  88. package/plugins/huaweicloud-core/src/tools.mjs +993 -1008
  89. package/plugins/huaweicloud-core/src/ws-exec/hwlink-exec-client.js +427 -427
  90. package/plugins/huaweicloud-core/src/ws-exec/hwlink-fair-queue.js +132 -132
  91. package/plugins/huaweicloud-core/src/ws-exec/hwlink-multiplexer.js +227 -227
  92. package/plugins/huaweicloud-core/src/ws-exec/hwlink-packet.js +202 -202
  93. package/plugins/huaweicloud-core/src/ws-exec/hwlink-terminal-channel.js +158 -158
  94. package/plugins/huaweicloud-core/src/ws-exec/index.js +19 -19
  95. package/plugins/huaweicloud-core/src/ws-exec/ws-exec-client.js +338 -338
  96. package/plugins/huaweicloud-core/src/proxy/proxy-agent.mjs +0 -155
  97. package/plugins/huaweicloud-core/src/proxy/proxy-config.mjs +0 -87
@@ -1,105 +1,87 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { homedir } from 'node:os';
4
- import { spawnSync } from 'node:child_process';
5
-
6
- export const SUPPORTED_AGENT_TARGETS = ['opencode', 'codex', 'codex-desktop', 'codearts', 'workbuddy', 'dsh'];
7
-
8
- function baseHome() {
9
- return process.env.HUAWEICLOUD_HOME || homedir();
10
- }
11
-
12
- function opencodeConfigFile() {
13
- const jsonc = join(baseHome(), '.config', 'opencode', 'opencode.jsonc');
14
- if (existsSync(jsonc)) return jsonc;
15
- return join(baseHome(), '.config', 'opencode', 'opencode.json');
16
- }
17
-
18
- function readJsonSafe(path) {
19
- if (!existsSync(path)) return null;
20
- try {
21
- return JSON.parse(readFileSync(path, 'utf8'));
22
- } catch {
23
- return null;
24
- }
25
- }
26
-
27
- function opencodeRegistered() {
28
- const path = opencodeConfigFile();
29
- const cfg = readJsonSafe(path);
30
- return Boolean(cfg?.mcp?.['huaweicloud-devkit']);
31
- }
32
-
33
- function codexDesktopRegistered() {
34
- const path = join(baseHome(), '.codex', 'config.toml');
35
- if (!existsSync(path)) return false;
36
- try {
37
- return readFileSync(path, 'utf8').includes('[mcp_servers.huaweicloud-devkit]');
38
- } catch {
39
- return false;
40
- }
41
- }
42
-
43
- function codexCliRegistered() {
44
- try {
45
- const r = spawnSync('codex', ['plugin', 'list'], {
46
- shell: false,
47
- windowsHide: true,
48
- stdio: 'pipe',
49
- timeout: 10000,
50
- });
51
- const out = `${r.stdout || ''}${r.stderr || ''}`;
52
- return out.includes('huaweicloud-core');
53
- } catch {
54
- return false;
55
- }
56
- }
57
-
58
- function codeartsRegistered() {
59
- const paths = [
60
- join(baseHome(), '.codeartsdoer', 'mcp', 'mcp_settings.json'),
61
- join(process.cwd(), '.codeartsdoer', 'mcp', 'mcp_settings.json'),
62
- ];
63
- return paths.some((path) => {
64
- const cfg = readJsonSafe(path);
65
- return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
66
- });
67
- }
68
-
69
- function workbuddyRegistered() {
70
- const cfg = readJsonSafe(join(baseHome(), '.workbuddy', 'mcp.json'));
71
- return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
72
- }
73
-
74
- function dshRoot() {
75
- return process.env.DSH_HOME || join(baseHome(), '.dsh');
76
- }
77
-
78
- function dshRegistered() {
79
- const patchPath = join(dshRoot(), 'profiles', 'web', 'cordis.patch.yml');
80
- if (!existsSync(patchPath)) return false;
81
- try {
82
- const patch = readFileSync(patchPath, 'utf8');
83
- return patch.includes('id: mcp-huaweicloud')
84
- && patch.includes("@deepseek-ai/dsh-mcp-client")
85
- && patch.includes('serverName: huaweicloud');
86
- } catch {
87
- return false;
88
- }
89
- }
90
-
91
- export function getAgentRegistrationStatuses(target = 'all') {
92
- const requested = target === 'all' ? SUPPORTED_AGENT_TARGETS : [target];
93
- const result = { target, agents: {} };
94
- for (const agent of requested) {
95
- let configured = false;
96
- if (agent === 'opencode') configured = opencodeRegistered();
97
- if (agent === 'codex-desktop') configured = codexDesktopRegistered();
98
- if (agent === 'codex') configured = codexCliRegistered();
99
- if (agent === 'codearts') configured = codeartsRegistered();
100
- if (agent === 'workbuddy') configured = workbuddyRegistered();
101
- if (agent === 'dsh') configured = dshRegistered();
102
- result.agents[agent] = { configured };
103
- }
104
- return result;
105
- }
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { spawnSync } from 'node:child_process';
5
+
6
+ export const SUPPORTED_AGENT_TARGETS = ['opencode', 'codex', 'codex-desktop', 'codearts', 'workbuddy'];
7
+
8
+ function baseHome() {
9
+ return process.env.HUAWEICLOUD_HOME || homedir();
10
+ }
11
+
12
+ function opencodeConfigFile() {
13
+ const jsonc = join(baseHome(), '.config', 'opencode', 'opencode.jsonc');
14
+ if (existsSync(jsonc)) return jsonc;
15
+ return join(baseHome(), '.config', 'opencode', 'opencode.json');
16
+ }
17
+
18
+ function readJsonSafe(path) {
19
+ if (!existsSync(path)) return null;
20
+ try {
21
+ return JSON.parse(readFileSync(path, 'utf8'));
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+
27
+ function opencodeRegistered() {
28
+ const path = opencodeConfigFile();
29
+ const cfg = readJsonSafe(path);
30
+ return Boolean(cfg?.mcp?.['huaweicloud-devkit']);
31
+ }
32
+
33
+ function codexDesktopRegistered() {
34
+ const path = join(baseHome(), '.codex', 'config.toml');
35
+ if (!existsSync(path)) return false;
36
+ try {
37
+ return readFileSync(path, 'utf8').includes('[mcp_servers.huaweicloud-devkit]');
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+
43
+ function codexCliRegistered() {
44
+ try {
45
+ const r = spawnSync('codex', ['plugin', 'list'], {
46
+ shell: false,
47
+ windowsHide: true,
48
+ stdio: 'pipe',
49
+ timeout: 10000,
50
+ });
51
+ const out = `${r.stdout || ''}${r.stderr || ''}`;
52
+ return out.includes('huaweicloud-core');
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ function codeartsRegistered() {
59
+ const paths = [
60
+ join(baseHome(), '.codeartsdoer', 'mcp', 'mcp_settings.json'),
61
+ join(process.cwd(), '.codeartsdoer', 'mcp', 'mcp_settings.json'),
62
+ ];
63
+ return paths.some((path) => {
64
+ const cfg = readJsonSafe(path);
65
+ return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
66
+ });
67
+ }
68
+
69
+ function workbuddyRegistered() {
70
+ const cfg = readJsonSafe(join(baseHome(), '.workbuddy', 'mcp.json'));
71
+ return Boolean(cfg?.mcpServers?.['huaweicloud-devkit']);
72
+ }
73
+
74
+ export function getAgentRegistrationStatuses(target = 'all') {
75
+ const requested = target === 'all' ? SUPPORTED_AGENT_TARGETS : [target];
76
+ const result = { target, agents: {} };
77
+ for (const agent of requested) {
78
+ let configured = false;
79
+ if (agent === 'opencode') configured = opencodeRegistered();
80
+ if (agent === 'codex-desktop') configured = codexDesktopRegistered();
81
+ if (agent === 'codex') configured = codexCliRegistered();
82
+ if (agent === 'codearts') configured = codeartsRegistered();
83
+ if (agent === 'workbuddy') configured = workbuddyRegistered();
84
+ result.agents[agent] = { configured };
85
+ }
86
+ return result;
87
+ }
@@ -1,95 +1,95 @@
1
- import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
3
- import { homedir } from 'node:os';
4
-
5
- // Verify a credential file ended up with 0600. On Windows-mounted drives inside WSL
6
- // (drvfs/9p) chmod is silently ignored, so the file can be world-readable (0777).
7
- // Native Windows has no POSIX modes (statSync always reports 0666), so skip the check there.
8
- function ensurePrivateMode(path) {
9
- if (process.platform === 'win32') return;
10
- try { chmodSync(path, 0o600); } catch {}
11
- try {
12
- const mode = statSync(path).mode & 0o777;
13
- if (mode !== 0o600) {
14
- console.warn(`\x1b[33m[WARN]\x1b[0m Could not set 0600 on ${path} (current mode ${mode.toString(8)}). Credentials may be readable by other users.`);
15
- console.warn(`\x1b[33m If running under WSL, move the credential home to the Linux filesystem:\x1b[0m`);
16
- console.warn(`\x1b[33m export HUAWEICLOUD_HOME=$HOME (then re-run auth init)\x1b[0m`);
17
- console.warn(`\x1b[33m Or skip file storage entirely with HW_ACCESS_KEY/HW_SECRET_KEY environment variables.\x1b[0m`);
18
- }
19
- } catch {}
20
- }
21
-
22
- function baseHome() {
23
- return process.env.HUAWEICLOUD_HOME || homedir();
24
- }
25
-
26
- export function globalCredentialsPath() {
27
- return join(baseHome(), '.config', 'huaweicloud', 'credentials.json');
28
- }
29
-
30
- export function obsConfigPath() {
31
- return join(baseHome(), '.obsutilconfig');
32
- }
33
-
34
- export function readGlobalCredentials() {
35
- const path = globalCredentialsPath();
36
- if (!existsSync(path)) return null;
37
- try {
38
- return JSON.parse(readFileSync(path, 'utf8'));
39
- } catch {
40
- return null;
41
- }
42
- }
43
-
44
- export function writeGlobalCredentials(credentials = {}) {
45
- const path = globalCredentialsPath();
46
- mkdirSync(dirname(path), { recursive: true });
47
- const payload = {
48
- ak: String(credentials.ak || ''),
49
- sk: String(credentials.sk || ''),
50
- securityToken: String(credentials.securityToken || ''),
51
- region: String(credentials.region || ''),
52
- };
53
- writeFileSync(path, JSON.stringify(payload, null, 2), { encoding: 'utf8', mode: 0o600 });
54
- ensurePrivateMode(path);
55
- return path;
56
- }
57
-
58
- export function writeObsConfig(credentials = {}) {
59
- const region = String(credentials.region || '');
60
- const ak = String(credentials.ak || '');
61
- const sk = String(credentials.sk || '');
62
- const securityToken = String(credentials.securityToken || '');
63
- if (!region || !ak || !sk) {
64
- throw new Error('region, ak, and sk are required to write OBS config');
65
- }
66
- const path = obsConfigPath();
67
- const endpoint = credentials.endpoint || `https://obs.${region}.myhuaweicloud.com`;
68
- // Flat key=value format (no [default] section) as written by KooCLI 7.x `hcloud OBS config`.
69
- const content = `endpoint=${endpoint}\nak=${ak}\nsk=${sk}${securityToken ? `\ntoken=${securityToken}` : ''}\n`;
70
- writeFileSync(path, content, { encoding: 'utf8', mode: 0o600 });
71
- ensurePrivateMode(path);
72
- return { path, endpoint };
73
- }
74
-
75
- export function resolveCredentials(options = {}) {
76
- let ak = process.env.HW_ACCESS_KEY;
77
- let sk = process.env.HW_SECRET_KEY;
78
- let securityToken = process.env.HW_SECURITY_TOKEN;
79
- let region = process.env.HW_REGION || process.env.HUAWEICLOUD_REGION || '';
80
-
81
- const stored = readGlobalCredentials();
82
- if (stored) {
83
- if (!ak && stored.ak) ak = stored.ak;
84
- if (!sk && stored.sk) sk = stored.sk;
85
- if (!securityToken && stored.securityToken) securityToken = stored.securityToken;
86
- if (!region && stored.region) region = stored.region;
87
- }
88
-
89
- if (!ak || !sk) {
90
- if (options.allowMissing) return null;
91
- throw new Error('Huawei Cloud credentials are not configured. Run "npx huaweicloud-devkit auth init" or set HW_ACCESS_KEY/HW_SECRET_KEY.');
92
- }
93
-
94
- return { ak, sk, securityToken, region };
95
- }
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+
5
+ // Verify a credential file ended up with 0600. On Windows-mounted drives inside WSL
6
+ // (drvfs/9p) chmod is silently ignored, so the file can be world-readable (0777).
7
+ // Native Windows has no POSIX modes (statSync always reports 0666), so skip the check there.
8
+ function ensurePrivateMode(path) {
9
+ if (process.platform === 'win32') return;
10
+ try { chmodSync(path, 0o600); } catch {}
11
+ try {
12
+ const mode = statSync(path).mode & 0o777;
13
+ if (mode !== 0o600) {
14
+ console.warn(`\x1b[33m[WARN]\x1b[0m Could not set 0600 on ${path} (current mode ${mode.toString(8)}). Credentials may be readable by other users.`);
15
+ console.warn(`\x1b[33m If running under WSL, move the credential home to the Linux filesystem:\x1b[0m`);
16
+ console.warn(`\x1b[33m export HUAWEICLOUD_HOME=$HOME (then re-run auth init)\x1b[0m`);
17
+ console.warn(`\x1b[33m Or skip file storage entirely with HW_ACCESS_KEY/HW_SECRET_KEY environment variables.\x1b[0m`);
18
+ }
19
+ } catch {}
20
+ }
21
+
22
+ function baseHome() {
23
+ return process.env.HUAWEICLOUD_HOME || homedir();
24
+ }
25
+
26
+ export function globalCredentialsPath() {
27
+ return join(baseHome(), '.config', 'huaweicloud', 'credentials.json');
28
+ }
29
+
30
+ export function obsConfigPath() {
31
+ return join(baseHome(), '.obsutilconfig');
32
+ }
33
+
34
+ export function readGlobalCredentials() {
35
+ const path = globalCredentialsPath();
36
+ if (!existsSync(path)) return null;
37
+ try {
38
+ return JSON.parse(readFileSync(path, 'utf8'));
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ export function writeGlobalCredentials(credentials = {}) {
45
+ const path = globalCredentialsPath();
46
+ mkdirSync(dirname(path), { recursive: true });
47
+ const payload = {
48
+ ak: String(credentials.ak || ''),
49
+ sk: String(credentials.sk || ''),
50
+ securityToken: String(credentials.securityToken || ''),
51
+ region: String(credentials.region || ''),
52
+ };
53
+ writeFileSync(path, JSON.stringify(payload, null, 2), { encoding: 'utf8', mode: 0o600 });
54
+ ensurePrivateMode(path);
55
+ return path;
56
+ }
57
+
58
+ export function writeObsConfig(credentials = {}) {
59
+ const region = String(credentials.region || '');
60
+ const ak = String(credentials.ak || '');
61
+ const sk = String(credentials.sk || '');
62
+ const securityToken = String(credentials.securityToken || '');
63
+ if (!region || !ak || !sk) {
64
+ throw new Error('region, ak, and sk are required to write OBS config');
65
+ }
66
+ const path = obsConfigPath();
67
+ const endpoint = credentials.endpoint || `https://obs.${region}.myhuaweicloud.com`;
68
+ // Flat key=value format (no [default] section) as written by KooCLI 7.x `hcloud OBS config`.
69
+ const content = `endpoint=${endpoint}\nak=${ak}\nsk=${sk}${securityToken ? `\ntoken=${securityToken}` : ''}\n`;
70
+ writeFileSync(path, content, { encoding: 'utf8', mode: 0o600 });
71
+ ensurePrivateMode(path);
72
+ return { path, endpoint };
73
+ }
74
+
75
+ export function resolveCredentials(options = {}) {
76
+ let ak = process.env.HW_ACCESS_KEY;
77
+ let sk = process.env.HW_SECRET_KEY;
78
+ let securityToken = process.env.HW_SECURITY_TOKEN;
79
+ let region = process.env.HW_REGION || process.env.HUAWEICLOUD_REGION || '';
80
+
81
+ const stored = readGlobalCredentials();
82
+ if (stored) {
83
+ if (!ak && stored.ak) ak = stored.ak;
84
+ if (!sk && stored.sk) sk = stored.sk;
85
+ if (!securityToken && stored.securityToken) securityToken = stored.securityToken;
86
+ if (!region && stored.region) region = stored.region;
87
+ }
88
+
89
+ if (!ak || !sk) {
90
+ if (options.allowMissing) return null;
91
+ throw new Error('Huawei Cloud credentials are not configured. Run "npx huaweicloud-devkit auth init" or set HW_ACCESS_KEY/HW_SECRET_KEY.');
92
+ }
93
+
94
+ return { ak, sk, securityToken, region };
95
+ }
@@ -1,63 +1,63 @@
1
- import { existsSync } from 'node:fs';
2
- import { spawnSync } from 'node:child_process';
3
- import { getAgentRegistrationStatuses } from './agent-registration.mjs';
4
- import { globalCredentialsPath, obsConfigPath, readGlobalCredentials, writeObsConfig } from './credentials.mjs';
5
-
6
- function hcloudInstalled() {
7
- const bin = process.env.HCLOUD_BIN || 'hcloud';
8
- try {
9
- const r = spawnSync(`"${bin}" version`, [], {
10
- shell: true,
11
- windowsHide: true,
12
- stdio: 'pipe',
13
- timeout: 5000,
14
- });
15
- const out = `${r.stdout || ''}${r.stderr || ''}`;
16
- return r.status === 0 && /KooCLI|Current.*version|当前KooCLI/i.test(out);
17
- } catch {
18
- return false;
19
- }
20
- }
21
-
22
- export function getAuthStatus(target = 'all') {
23
- const credentials = readGlobalCredentials();
24
- return {
25
- target,
26
- credentialsConfigured: Boolean(credentials?.ak && credentials?.sk),
27
- credentialsPath: globalCredentialsPath(),
28
- obsConfigured: existsSync(obsConfigPath()),
29
- obsConfigPath: obsConfigPath(),
30
- kooCliInstalled: hcloudInstalled(),
31
- agents: getAgentRegistrationStatuses(target).agents,
32
- };
33
- }
34
-
35
- export function syncAuth(target = 'all') {
36
- const credentials = readGlobalCredentials();
37
- if (!credentials?.ak || !credentials?.sk) {
38
- return {
39
- ok: false,
40
- error: 'Global credentials are not configured.',
41
- nextStep: 'Run "npx huaweicloud-devkit auth init" first.',
42
- };
43
- }
44
-
45
- let obs = null;
46
- try {
47
- obs = writeObsConfig(credentials);
48
- } catch (error) {
49
- return {
50
- ok: false,
51
- error: error.message,
52
- nextStep: 'Run "npx huaweicloud-devkit auth init" to refresh credentials and region.',
53
- };
54
- }
55
-
56
- return {
57
- ok: true,
58
- obs: { configured: true, path: obs.path, endpoint: obs.endpoint },
59
- credentialsConfigured: true,
60
- agents: getAgentRegistrationStatuses(target).agents,
61
- note: 'OBS credentials were synced from the global credential vault. Agent MCP registration is managed by "npx huaweicloud-devkit install --target <agent>".',
62
- };
63
- }
1
+ import { existsSync } from 'node:fs';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { getAgentRegistrationStatuses } from './agent-registration.mjs';
4
+ import { globalCredentialsPath, obsConfigPath, readGlobalCredentials, writeObsConfig } from './credentials.mjs';
5
+
6
+ function hcloudInstalled() {
7
+ const bin = process.env.HCLOUD_BIN || 'hcloud';
8
+ try {
9
+ const r = spawnSync(`"${bin}" version`, [], {
10
+ shell: true,
11
+ windowsHide: true,
12
+ stdio: 'pipe',
13
+ timeout: 5000,
14
+ });
15
+ const out = `${r.stdout || ''}${r.stderr || ''}`;
16
+ return r.status === 0 && /KooCLI|Current.*version|当前KooCLI/i.test(out);
17
+ } catch {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ export function getAuthStatus(target = 'all') {
23
+ const credentials = readGlobalCredentials();
24
+ return {
25
+ target,
26
+ credentialsConfigured: Boolean(credentials?.ak && credentials?.sk),
27
+ credentialsPath: globalCredentialsPath(),
28
+ obsConfigured: existsSync(obsConfigPath()),
29
+ obsConfigPath: obsConfigPath(),
30
+ kooCliInstalled: hcloudInstalled(),
31
+ agents: getAgentRegistrationStatuses(target).agents,
32
+ };
33
+ }
34
+
35
+ export function syncAuth(target = 'all') {
36
+ const credentials = readGlobalCredentials();
37
+ if (!credentials?.ak || !credentials?.sk) {
38
+ return {
39
+ ok: false,
40
+ error: 'Global credentials are not configured.',
41
+ nextStep: 'Run "npx huaweicloud-devkit auth init" first.',
42
+ };
43
+ }
44
+
45
+ let obs = null;
46
+ try {
47
+ obs = writeObsConfig(credentials);
48
+ } catch (error) {
49
+ return {
50
+ ok: false,
51
+ error: error.message,
52
+ nextStep: 'Run "npx huaweicloud-devkit auth init" to refresh credentials and region.',
53
+ };
54
+ }
55
+
56
+ return {
57
+ ok: true,
58
+ obs: { configured: true, path: obs.path, endpoint: obs.endpoint },
59
+ credentialsConfigured: true,
60
+ agents: getAgentRegistrationStatuses(target).agents,
61
+ note: 'OBS credentials were synced from the global credential vault. Agent MCP registration is managed by "npx huaweicloud-devkit install --target <agent>".',
62
+ };
63
+ }