huaweicloud-devkit 1.1.2-next.2 → 1.1.2-next.4
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 +22 -0
- package/README.zh-CN.md +22 -0
- package/integrations/hermes/skills-snapshot.json +175 -0
- package/package.json +3 -1
- package/plugins/huaweicloud-core/.claude-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.codex-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.cursor-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.hermes-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/.workbuddy-plugin/plugin.json +1 -1
- package/plugins/huaweicloud-core/hooks/hooks.json +2 -2
- package/plugins/huaweicloud-core/hooks/huaweicloud-safety.mjs +56 -0
- package/plugins/huaweicloud-core/openclaw.plugin.json +1 -1
- package/plugins/huaweicloud-core/skills/huawei-apig/SKILL.md +1 -1
- package/plugins/huaweicloud-core/skills/huawei-dew/SKILL.md +6 -7
- package/plugins/huaweicloud-core/skills/huawei-dew/references/csms-usage.md +7 -6
- package/plugins/huaweicloud-core/skills/huawei-dew/references/kms-usage.md +1 -1
- package/plugins/huaweicloud-core/skills/huawei-ecs/SKILL.md +1 -1
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/evs.md +3 -1
- package/plugins/huaweicloud-core/skills/huawei-ecs/references/troubleshooting.md +10 -10
- package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/create-function.md +2 -2
- package/plugins/huaweicloud-core/skills/huawei-functiongraph/references/deploy-workflow.md +1 -1
- package/plugins/huaweicloud-core/skills/huawei-getting-started/SKILL.md +15 -9
- package/plugins/huaweicloud-core/skills/huawei-iac/SKILL.md +1 -1
- package/plugins/huaweicloud-core/skills/huawei-iac/references/resource-catalog.md +1 -1
- package/plugins/huaweicloud-core/skills/huawei-iam/references/quick-ref.md +3 -3
- package/plugins/huaweicloud-core/skills/huawei-obs/SKILL.md +15 -15
- package/plugins/huaweicloud-core/skills/huawei-vpc/references/network.md +1 -1
- package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +18 -16
- package/plugins/huaweicloud-core/skills/huaweicloud-safety/SKILL.md +1 -1
- package/plugins/huaweicloud-core/src/auth/credentials.mjs +6 -2
- package/plugins/huaweicloud-core/src/auth/reconcile.mjs +30 -6
- package/plugins/huaweicloud-core/src/auth/service.mjs +16 -22
- package/plugins/huaweicloud-core/src/hcloud-cli.mjs +16 -10
- package/plugins/huaweicloud-core/src/hcloud-probe.mjs +154 -0
- package/plugins/huaweicloud-core/src/koocli-version.mjs +47 -0
- package/plugins/huaweicloud-core/src/safety-policy.mjs +17 -5
- package/plugins/huaweicloud-core/src/setup-cli.mjs +196 -134
- package/plugins/huaweicloud-core/src/tools.mjs +16 -17
|
@@ -18,7 +18,7 @@ import { createRequire } from 'node:module';
|
|
|
18
18
|
|
|
19
19
|
import { getAuthStatus, syncAuth } from './auth/service.mjs';
|
|
20
20
|
import { SUPPORTED_AGENT_TARGETS } from './auth/agent-registration.mjs';
|
|
21
|
-
import { resolveManagedProfile } from './auth/reconcile.mjs';
|
|
21
|
+
import { fingerprint, resolveManagedProfile } from './auth/reconcile.mjs';
|
|
22
22
|
import { redactSecrets } from './safety-policy.mjs';
|
|
23
23
|
import {
|
|
24
24
|
globalCredentialsPath,
|
|
@@ -36,6 +36,8 @@ import {
|
|
|
36
36
|
} from './proxy/proxy-config.mjs';
|
|
37
37
|
import { removeKooCli, removeObsConfig } from './sandbox/uninstall-cleanup.mjs';
|
|
38
38
|
import { queryDistTagsSync, determineTarget, semverCompare } from './update-check.mjs';
|
|
39
|
+
import { getKooCliVersion, compareVersion, kooCliDownloadBase, KOO_CLI_BASE } from './koocli-version.mjs';
|
|
40
|
+
import { findHcloudBin, hcloudProbeNextStep, probeHcloud } from './hcloud-probe.mjs';
|
|
39
41
|
|
|
40
42
|
const { DatabaseSync } = createRequire(import.meta.url)('node:sqlite');
|
|
41
43
|
|
|
@@ -413,23 +415,6 @@ function detectCodeartsSandbox() {
|
|
|
413
415
|
}
|
|
414
416
|
}
|
|
415
417
|
|
|
416
|
-
// Locate an existing hcloud executable (HCLOUD_BIN, ~/hcloud on Windows, ~/.local/bin elsewhere).
|
|
417
|
-
function findHcloudBin() {
|
|
418
|
-
if (process.env.HCLOUD_BIN && existsSync(process.env.HCLOUD_BIN)) return process.env.HCLOUD_BIN;
|
|
419
|
-
const isWin = platform() === 'win32';
|
|
420
|
-
const candidates = isWin
|
|
421
|
-
? [join(homedir(), 'hcloud', 'hcloud.exe')]
|
|
422
|
-
: [
|
|
423
|
-
join(homedir(), '.local', 'bin', 'hcloud'),
|
|
424
|
-
join(homedir(), 'hcloud', 'hcloud'),
|
|
425
|
-
join(homedir(), 'hcloud', 'hcloud.exe'),
|
|
426
|
-
];
|
|
427
|
-
for (const c of candidates) {
|
|
428
|
-
if (existsSync(c)) return c;
|
|
429
|
-
}
|
|
430
|
-
return null;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
418
|
function printSandboxWarning(reason) {
|
|
434
419
|
console.log(`\n\x1b[1m\x1b[31m⚠ 检测到码道沙箱模式 (bash_mode: sandbox)\x1b[0m`);
|
|
435
420
|
console.log(`\x1b[31m ${reason}\x1b[0m`);
|
|
@@ -623,27 +608,25 @@ function hasCodexCLI() {
|
|
|
623
608
|
return false;
|
|
624
609
|
}
|
|
625
610
|
|
|
626
|
-
function
|
|
627
|
-
const
|
|
628
|
-
if (!existsSync(bin)) return false;
|
|
629
|
-
try {
|
|
630
|
-
if (statSync(bin).size < 1024) return false;
|
|
631
|
-
} catch {
|
|
632
|
-
return false;
|
|
633
|
-
}
|
|
611
|
+
function getMarketplaceName() {
|
|
612
|
+
const marketplacePath = join(PACKAGE_ROOT, '.agents', 'plugins', 'marketplace.json');
|
|
634
613
|
try {
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
return false;
|
|
640
|
-
}
|
|
614
|
+
const manifest = JSON.parse(readFileSync(marketplacePath, 'utf8'));
|
|
615
|
+
if (manifest.name) return manifest.name;
|
|
616
|
+
} catch {}
|
|
617
|
+
return 'huaweicloud-devkit';
|
|
641
618
|
}
|
|
642
619
|
|
|
643
|
-
function
|
|
620
|
+
function getCodexPluginName() {
|
|
644
621
|
const marketplacePath = join(PACKAGE_ROOT, '.agents', 'plugins', 'marketplace.json');
|
|
645
622
|
try {
|
|
646
|
-
const
|
|
623
|
+
const marketplace = JSON.parse(readFileSync(marketplacePath, 'utf8'));
|
|
624
|
+
const pluginName = marketplace.plugins?.[0]?.name;
|
|
625
|
+
if (pluginName) return pluginName;
|
|
626
|
+
} catch {}
|
|
627
|
+
const codexManifestPath = join(PLUGIN_ROOT, '.codex-plugin', 'plugin.json');
|
|
628
|
+
try {
|
|
629
|
+
const manifest = JSON.parse(readFileSync(codexManifestPath, 'utf8'));
|
|
647
630
|
if (manifest.name) return manifest.name;
|
|
648
631
|
} catch {}
|
|
649
632
|
return 'huaweicloud-devkit';
|
|
@@ -651,7 +634,7 @@ function getMarketplaceName() {
|
|
|
651
634
|
|
|
652
635
|
function installCodex() {
|
|
653
636
|
const marketplaceRoot = PACKAGE_ROOT;
|
|
654
|
-
const pluginName =
|
|
637
|
+
const pluginName = getCodexPluginName();
|
|
655
638
|
const marketplaceName = getMarketplaceName();
|
|
656
639
|
|
|
657
640
|
console.log(` Registering Codex marketplace: ${marketplaceRoot}`);
|
|
@@ -667,6 +650,10 @@ function installCodex() {
|
|
|
667
650
|
console.log(` \x1b[33mUse: npx huaweicloud-devkit install --target codex-desktop\x1b[0m`);
|
|
668
651
|
return false;
|
|
669
652
|
}
|
|
653
|
+
if (r1.status !== 0) {
|
|
654
|
+
console.log(` \x1b[31mCodex marketplace registration failed.\x1b[0m`);
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
670
657
|
|
|
671
658
|
console.log(` Installing plugin: ${pluginName}@${marketplaceName}`);
|
|
672
659
|
const r2 = spawnSync(`codex plugin add "${pluginName}@${marketplaceName}"`, [], {
|
|
@@ -681,20 +668,26 @@ function installCodex() {
|
|
|
681
668
|
console.log(` \x1b[33mUse: npx huaweicloud-devkit install --target codex-desktop\x1b[0m`);
|
|
682
669
|
return false;
|
|
683
670
|
}
|
|
671
|
+
if (r2.status !== 0) {
|
|
672
|
+
console.log(` \x1b[31mCodex plugin installation failed.\x1b[0m`);
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
684
675
|
|
|
685
676
|
return true;
|
|
686
677
|
}
|
|
687
678
|
|
|
688
679
|
function uninstallCodex() {
|
|
689
|
-
const pluginName =
|
|
680
|
+
const pluginName = getCodexPluginName();
|
|
690
681
|
const marketplaceName = getMarketplaceName();
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
682
|
+
for (const name of new Set([pluginName, 'huaweicloud-core'])) {
|
|
683
|
+
console.log(` Removing Codex plugin: ${name}@${marketplaceName}`);
|
|
684
|
+
const r = spawnSync(`codex plugin remove "${name}@${marketplaceName}"`, [], {
|
|
685
|
+
shell: true,
|
|
686
|
+
windowsHide: true,
|
|
687
|
+
stdio: 'pipe',
|
|
688
|
+
});
|
|
689
|
+
console.log(` ${r.stdout ? r.stdout.toString().trim() : r.stderr.toString().trim()}`);
|
|
690
|
+
}
|
|
698
691
|
|
|
699
692
|
for (const name of new Set([marketplaceName, 'HuaweiCloud-Devkit'])) {
|
|
700
693
|
console.log(` Removing Codex marketplace: ${name}`);
|
|
@@ -710,7 +703,7 @@ function uninstallCodex() {
|
|
|
710
703
|
function codexStatus() {
|
|
711
704
|
const r = spawnSync('codex plugin list', [], { shell: true, windowsHide: true, stdio: 'pipe' });
|
|
712
705
|
const out = r.stdout ? r.stdout.toString() : '';
|
|
713
|
-
return out.includes('huaweicloud-core');
|
|
706
|
+
return out.includes(getCodexPluginName()) || out.includes('huaweicloud-core');
|
|
714
707
|
}
|
|
715
708
|
|
|
716
709
|
async function installOpenCode() {
|
|
@@ -3067,75 +3060,116 @@ function checkForUpdate() {
|
|
|
3067
3060
|
}
|
|
3068
3061
|
}
|
|
3069
3062
|
|
|
3063
|
+
function installMarkerDirForTarget(target) {
|
|
3064
|
+
if (target === 'codex') return null;
|
|
3065
|
+
if (target === 'dsh') return dshPluginsDir();
|
|
3066
|
+
if (target === 'codearts') return codeartsPluginsDir();
|
|
3067
|
+
if (target === 'codearts-work') return codeartsWorkPluginsDir();
|
|
3068
|
+
if (target === 'workbuddy') return workbuddyPluginsDir();
|
|
3069
|
+
if (target === 'officeace') return officeacePluginsDir();
|
|
3070
|
+
if (target === 'hermes') return hermesPluginsDir();
|
|
3071
|
+
if (target === 'openclaw') return openclawPluginsDir();
|
|
3072
|
+
if (target === 'atomcode') return atomcodePluginsDir();
|
|
3073
|
+
if (target === 'codex-desktop') return codexDesktopPluginsDir();
|
|
3074
|
+
if (target === 'opencode') return opencodePluginsDir();
|
|
3075
|
+
return null;
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
function writeInstallMarker(target) {
|
|
3079
|
+
const markerDir = installMarkerDirForTarget(target);
|
|
3080
|
+
if (!markerDir) return;
|
|
3081
|
+
mkdirSync(markerDir, { recursive: true });
|
|
3082
|
+
writeFileSync(join(markerDir, '.installed'), new Date().toISOString());
|
|
3083
|
+
}
|
|
3084
|
+
|
|
3070
3085
|
async function cmdInstall() {
|
|
3071
3086
|
const target = parseTarget();
|
|
3072
3087
|
console.log(BANNER);
|
|
3073
3088
|
console.log(`Installing HuaweiCloud DevKit${target !== 'opencode' ? ` for ${target}` : ''}...\n`);
|
|
3074
3089
|
checkNode();
|
|
3075
3090
|
checkForUpdate();
|
|
3091
|
+
const installFailures = [];
|
|
3092
|
+
|
|
3093
|
+
async function runInstallStep(stepTarget, title, fn) {
|
|
3094
|
+
console.log(title);
|
|
3095
|
+
try {
|
|
3096
|
+
const result = await fn();
|
|
3097
|
+
if (result === false) {
|
|
3098
|
+
installFailures.push(stepTarget);
|
|
3099
|
+
return false;
|
|
3100
|
+
}
|
|
3101
|
+
writeInstallMarker(stepTarget);
|
|
3102
|
+
return true;
|
|
3103
|
+
} catch (error) {
|
|
3104
|
+
installFailures.push(stepTarget);
|
|
3105
|
+
console.log(` \x1b[31m${stepTarget} install failed: ${error.message}\x1b[0m`);
|
|
3106
|
+
return false;
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3076
3109
|
|
|
3077
3110
|
if (target === 'opencode' || target === 'all') {
|
|
3078
|
-
|
|
3079
|
-
await installOpenCode();
|
|
3111
|
+
await runInstallStep('opencode', '[OpenCode]', installOpenCode);
|
|
3080
3112
|
}
|
|
3081
3113
|
if (target === 'codex-desktop' || target === 'all') {
|
|
3082
|
-
|
|
3083
|
-
await installCodexDesktop();
|
|
3114
|
+
await runInstallStep('codex-desktop', '\n[Codex Desktop]', installCodexDesktop);
|
|
3084
3115
|
}
|
|
3085
3116
|
if (target === 'codearts' || target === 'all') {
|
|
3086
|
-
|
|
3087
|
-
await installCodeArts();
|
|
3117
|
+
await runInstallStep('codearts', '\n[CodeArts]', installCodeArts);
|
|
3088
3118
|
}
|
|
3089
3119
|
if (target === 'codearts-work' || target === 'all') {
|
|
3090
|
-
|
|
3091
|
-
await installCodeArtsWork();
|
|
3120
|
+
await runInstallStep('codearts-work', '\n[CodeArts Work]', installCodeArtsWork);
|
|
3092
3121
|
}
|
|
3093
3122
|
if (target === 'workbuddy' || target === 'all') {
|
|
3094
|
-
|
|
3095
|
-
await installWorkBuddy();
|
|
3123
|
+
await runInstallStep('workbuddy', '\n[WorkBuddy]', installWorkBuddy);
|
|
3096
3124
|
}
|
|
3097
3125
|
if (target === 'dsh' || target === 'all') {
|
|
3098
|
-
|
|
3099
|
-
await installDsh();
|
|
3126
|
+
await runInstallStep('dsh', '\n[DSH]', installDsh);
|
|
3100
3127
|
}
|
|
3101
3128
|
if (target === 'officeace' || target === 'all') {
|
|
3102
|
-
|
|
3103
|
-
await installOfficeAce();
|
|
3129
|
+
await runInstallStep('officeace', '\n[OfficeAce]', installOfficeAce);
|
|
3104
3130
|
}
|
|
3105
3131
|
if (target === 'hermes' || target === 'all') {
|
|
3106
|
-
|
|
3107
|
-
await installHermes();
|
|
3132
|
+
await runInstallStep('hermes', '\n[Hermes Agent]', installHermes);
|
|
3108
3133
|
}
|
|
3109
3134
|
if (target === 'openclaw' || target === 'all') {
|
|
3110
|
-
|
|
3111
|
-
await installOpenClaw();
|
|
3135
|
+
await runInstallStep('openclaw', '\n[OpenClaw]', installOpenClaw);
|
|
3112
3136
|
}
|
|
3113
3137
|
if (target === 'atomcode' || target === 'all') {
|
|
3114
|
-
|
|
3115
|
-
await installAtomCode();
|
|
3138
|
+
await runInstallStep('atomcode', '\n[AtomCode]', installAtomCode);
|
|
3116
3139
|
}
|
|
3117
3140
|
if (target === 'codex' || target === 'all') {
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3141
|
+
await runInstallStep('codex', '\n[Codex]', () => {
|
|
3142
|
+
if (!hasCodexCLI()) {
|
|
3143
|
+
if (target === 'codex') {
|
|
3144
|
+
console.log(` \x1b[31mCodex CLI not found.\x1b[0m`);
|
|
3145
|
+
if (process.platform === 'win32') {
|
|
3146
|
+
console.log(` \x1b[33mTip: Codex Desktop on Windows installs codex.exe under WindowsApps,\x1b[0m`);
|
|
3147
|
+
console.log(` \x1b[33m which may fail with "Access is denied". Try instead:\x1b[0m`);
|
|
3148
|
+
console.log(` \x1b[33m npx huaweicloud-devkit install --target codex-desktop\x1b[0m`);
|
|
3149
|
+
}
|
|
3150
|
+
console.log(` \x1b[31mOr install Codex CLI: https://github.com/openai/codex-cli\x1b[0m`);
|
|
3151
|
+
return false;
|
|
3152
|
+
}
|
|
3153
|
+
console.log(` \x1b[33mCodex CLI not found. Skipping Codex.\x1b[0m`);
|
|
3122
3154
|
if (process.platform === 'win32') {
|
|
3123
|
-
console.log(
|
|
3124
|
-
|
|
3125
|
-
console.log(
|
|
3155
|
+
console.log(' \x1b[33mTip: try --target codex-desktop for Codex Desktop on Windows\x1b[0m');
|
|
3156
|
+
} else {
|
|
3157
|
+
console.log(' Install Codex CLI to enable: npx huaweicloud-devkit install --target codex');
|
|
3126
3158
|
}
|
|
3127
|
-
|
|
3128
|
-
process.exit(1);
|
|
3129
|
-
}
|
|
3130
|
-
console.log(` \x1b[33mCodex CLI not found. Skipping Codex.\x1b[0m`);
|
|
3131
|
-
if (process.platform === 'win32') {
|
|
3132
|
-
console.log(' \x1b[33mTip: try --target codex-desktop for Codex Desktop on Windows\x1b[0m');
|
|
3133
|
-
} else {
|
|
3134
|
-
console.log(' Install Codex CLI to enable: npx huaweicloud-devkit install --target codex');
|
|
3159
|
+
return true;
|
|
3135
3160
|
}
|
|
3136
|
-
|
|
3137
|
-
|
|
3161
|
+
return installCodex();
|
|
3162
|
+
});
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
if (installFailures.length > 0) {
|
|
3166
|
+
console.log(`\n\x1b[31mInstallation failed for: ${installFailures.join(', ')}\x1b[0m`);
|
|
3167
|
+
if (target === 'all') {
|
|
3168
|
+
console.log(
|
|
3169
|
+
'\x1b[33mSome targets may have been installed before the failure. Re-run status/doctor per target.\x1b[0m',
|
|
3170
|
+
);
|
|
3138
3171
|
}
|
|
3172
|
+
process.exit(1);
|
|
3139
3173
|
}
|
|
3140
3174
|
|
|
3141
3175
|
console.log(`\n\x1b[32mInstallation complete!\x1b[0m`);
|
|
@@ -3190,10 +3224,15 @@ async function cmdInstall() {
|
|
|
3190
3224
|
console.log(`\x1b[1m\x1b[33m╚══════════════════════════════════════════════════════╝\x1b[0m`);
|
|
3191
3225
|
}
|
|
3192
3226
|
|
|
3193
|
-
const
|
|
3194
|
-
if (!
|
|
3195
|
-
|
|
3196
|
-
|
|
3227
|
+
const hcloudProbe = probeHcloud();
|
|
3228
|
+
if (!hcloudProbe.ok) {
|
|
3229
|
+
if (hcloudProbe.status === 'sandbox_home_failure') {
|
|
3230
|
+
console.log(`\n\x1b[33mKooCLI (hcloud) detected, but cannot run in this sandbox.`);
|
|
3231
|
+
console.log(` ${hcloudProbeNextStep(hcloudProbe)}\x1b[0m`);
|
|
3232
|
+
} else {
|
|
3233
|
+
console.log(`\n\x1b[33mKooCLI (hcloud) is not ready.`);
|
|
3234
|
+
console.log(` ${hcloudProbeNextStep(hcloudProbe)}\x1b[0m`);
|
|
3235
|
+
}
|
|
3197
3236
|
} else {
|
|
3198
3237
|
console.log(`\nKooCLI (hcloud) detected.`);
|
|
3199
3238
|
}
|
|
@@ -3212,27 +3251,6 @@ async function cmdInstall() {
|
|
|
3212
3251
|
}
|
|
3213
3252
|
console.log(` 4. 运行自检:npx huaweicloud-devkit doctor`);
|
|
3214
3253
|
|
|
3215
|
-
// Write install marker for doctor to detect
|
|
3216
|
-
const markerDir =
|
|
3217
|
-
target === 'dsh'
|
|
3218
|
-
? dshPluginsDir()
|
|
3219
|
-
: target === 'codearts'
|
|
3220
|
-
? codeartsPluginsDir()
|
|
3221
|
-
: target === 'codearts-work'
|
|
3222
|
-
? codeartsWorkPluginsDir()
|
|
3223
|
-
: target === 'workbuddy'
|
|
3224
|
-
? workbuddyPluginsDir()
|
|
3225
|
-
: target === 'officeace'
|
|
3226
|
-
? officeacePluginsDir()
|
|
3227
|
-
: target === 'openclaw'
|
|
3228
|
-
? codexDesktopPluginsDir()
|
|
3229
|
-
: target === 'atomcode'
|
|
3230
|
-
? atomcodePluginsDir()
|
|
3231
|
-
: target === 'codex-desktop'
|
|
3232
|
-
? codexDesktopPluginsDir()
|
|
3233
|
-
: opencodePluginsDir();
|
|
3234
|
-
mkdirSync(markerDir, { recursive: true });
|
|
3235
|
-
writeFileSync(join(markerDir, '.installed'), new Date().toISOString());
|
|
3236
3254
|
if (target === 'opencode' || target === 'all') {
|
|
3237
3255
|
console.log('Or describe your Huawei Cloud task in OpenCode');
|
|
3238
3256
|
}
|
|
@@ -3243,7 +3261,7 @@ async function cmdInstall() {
|
|
|
3243
3261
|
console.log('Or describe your Huawei Cloud task in CodeArts Work');
|
|
3244
3262
|
}
|
|
3245
3263
|
if (target === 'codex' || target === 'all') {
|
|
3246
|
-
console.log('Or mention @huaweicloud-
|
|
3264
|
+
console.log('Or mention @huaweicloud-devkit in Codex');
|
|
3247
3265
|
}
|
|
3248
3266
|
if (target === 'workbuddy' || target === 'all') {
|
|
3249
3267
|
console.log('Or describe your Huawei Cloud task in WorkBuddy');
|
|
@@ -3546,6 +3564,21 @@ async function cmdDoctor() {
|
|
|
3546
3564
|
existsSync(join(atomcodePluginDir, 'safety', 'policy.json'));
|
|
3547
3565
|
check('Safety policy installed', safetyOk, 'Run: npx huaweicloud-devkit install');
|
|
3548
3566
|
|
|
3567
|
+
const hookConfigPath = join(PLUGIN_ROOT, 'hooks', 'hooks.json');
|
|
3568
|
+
const hookNodePath = join(PLUGIN_ROOT, 'hooks', 'huaweicloud-safety.mjs');
|
|
3569
|
+
let hookConfigUsesNode = false;
|
|
3570
|
+
let hookConfigUsesPython = false;
|
|
3571
|
+
try {
|
|
3572
|
+
const hookConfigText = readFileSync(hookConfigPath, 'utf8');
|
|
3573
|
+
hookConfigUsesNode = hookConfigText.includes('huaweicloud-safety.mjs') && /\bnode\b/.test(hookConfigText);
|
|
3574
|
+
hookConfigUsesPython = /\bpython3?\b/.test(hookConfigText);
|
|
3575
|
+
} catch {}
|
|
3576
|
+
check(
|
|
3577
|
+
'Safety hook runtime (Node)',
|
|
3578
|
+
existsSync(hookNodePath) && hookConfigUsesNode && !hookConfigUsesPython,
|
|
3579
|
+
'hooks/hooks.json should invoke node hooks/huaweicloud-safety.mjs, not python3',
|
|
3580
|
+
);
|
|
3581
|
+
|
|
3549
3582
|
// MCP config — check OpenCode, Codex Desktop, CodeArts, WorkBuddy, and DSH
|
|
3550
3583
|
let mcpConfigured = false;
|
|
3551
3584
|
let mcpCfgTarget = '';
|
|
@@ -3657,28 +3690,47 @@ async function cmdDoctor() {
|
|
|
3657
3690
|
}
|
|
3658
3691
|
|
|
3659
3692
|
// hcloud CLI
|
|
3660
|
-
const
|
|
3661
|
-
const
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3693
|
+
const hcloudProbe = probeHcloud();
|
|
3694
|
+
const hcloudBin = hcloudProbe.executable;
|
|
3695
|
+
const hcloudOk = hcloudProbe.ok;
|
|
3696
|
+
check('hcloud CLI installed', hcloudProbe.installed, hcloudProbeNextStep(hcloudProbe));
|
|
3697
|
+
if (hcloudProbe.status === 'sandbox_home_failure') {
|
|
3698
|
+
warn++;
|
|
3699
|
+
console.log(` \x1b[33m[WARN]\x1b[0m hcloud cannot resolve the Windows user home in this agent sandbox.`);
|
|
3700
|
+
console.log(` ${hcloudProbeNextStep(hcloudProbe)}`);
|
|
3701
|
+
} else if (hcloudProbe.status === 'privacy_pending') {
|
|
3702
|
+
warn++;
|
|
3703
|
+
console.log(` \x1b[33m[WARN]\x1b[0m KooCLI privacy agreement is pending.`);
|
|
3704
|
+
console.log(` ${hcloudProbeNextStep(hcloudProbe)}`);
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
const kooCliTarget = getKooCliVersion();
|
|
3708
|
+
if (hcloudOk && kooCliTarget) {
|
|
3709
|
+
const installed = hcloudProbe.installedVersion;
|
|
3710
|
+
if (installed && compareVersion(installed, kooCliTarget) !== 0) {
|
|
3711
|
+
warn++;
|
|
3712
|
+
console.log(
|
|
3713
|
+
` \x1b[33m[WARN]\x1b[0m KooCLI version mismatch: installed ${installed}, this plugin is paired with ${kooCliTarget}.`,
|
|
3714
|
+
);
|
|
3715
|
+
console.log(
|
|
3716
|
+
` Reinstall the pinned version: curl -LO "${kooCliDownloadBase()}/huaweicloud-cli-linux-amd64.tar.gz" (or your platform's package), or run \`npx huaweicloud-devkit install-hcloud\`.`,
|
|
3717
|
+
);
|
|
3718
|
+
}
|
|
3719
|
+
}
|
|
3670
3720
|
|
|
3671
3721
|
// CodeArts sandbox mode warning
|
|
3672
3722
|
const sandboxMode = detectCodeartsSandbox();
|
|
3673
3723
|
if (sandboxMode === 'sandbox') {
|
|
3674
|
-
console.log(` \x1b[33m[WARN]\x1b[0m
|
|
3675
|
-
console.log(` KooCLI
|
|
3676
|
-
console.log(
|
|
3724
|
+
console.log(` \x1b[33m[WARN]\x1b[0m 检测到码道沙箱模式 (bash_mode: sandbox)`);
|
|
3725
|
+
console.log(` KooCLI 可能无法写入 ~/.hcloud/ 配置目录,并卡在隐私协议确认。`);
|
|
3726
|
+
console.log(
|
|
3727
|
+
` 修复:在码道设置中关闭沙箱模式后重试 (设置 → 对话流 → 智能体 终端命令运行模式 → 自动运行),或改用码道外的终端。`,
|
|
3728
|
+
);
|
|
3677
3729
|
warn++;
|
|
3678
3730
|
}
|
|
3679
3731
|
|
|
3680
3732
|
if (hcloudOk) {
|
|
3681
|
-
const ver =
|
|
3733
|
+
const ver = hcloudProbe.installedVersion || 'unknown';
|
|
3682
3734
|
console.log(` Version: ${ver}`);
|
|
3683
3735
|
|
|
3684
3736
|
// Check auth
|
|
@@ -4016,7 +4068,9 @@ async function cmdInstallHcloud() {
|
|
|
4016
4068
|
|
|
4017
4069
|
const os = platform();
|
|
4018
4070
|
const arch = process.arch;
|
|
4019
|
-
const baseUrl =
|
|
4071
|
+
const baseUrl = kooCliDownloadBase();
|
|
4072
|
+
const kooCliVersion = getKooCliVersion();
|
|
4073
|
+
const latestUrl = `${KOO_CLI_BASE}/latest`;
|
|
4020
4074
|
const installDir = os === 'win32' ? join(homedir(), 'hcloud') : join(homedir(), '.local', 'bin');
|
|
4021
4075
|
|
|
4022
4076
|
if (os === 'win32') {
|
|
@@ -4113,28 +4167,30 @@ async function cmdInstallHcloud() {
|
|
|
4113
4167
|
}
|
|
4114
4168
|
}
|
|
4115
4169
|
} else if (os === 'linux') {
|
|
4116
|
-
console.log('[Linux]
|
|
4117
|
-
console.log(
|
|
4118
|
-
' curl -sSL https://cn-north-4-hdn-koocli.obs.cn-north-4.myhuaweicloud.com/cli/latest/hcloud_install.sh -o ./hcloud_install.sh && bash ./hcloud_install.sh -y',
|
|
4119
|
-
);
|
|
4120
|
-
console.log(`\nOr manual: ${arch === 'arm64' ? 'ARM64' : 'AMD64'}`);
|
|
4170
|
+
console.log('[Linux] Auto-install (pinned to KooCLI <version>):'.replace('<version>', kooCliVersion || ''));
|
|
4121
4171
|
const pkg = arch === 'arm64' ? 'linux-arm64' : 'linux-amd64';
|
|
4122
4172
|
console.log(` curl -LO "${baseUrl}/huaweicloud-cli-${pkg}.tar.gz"`);
|
|
4123
4173
|
console.log(` tar -zxvf huaweicloud-cli-${pkg}.tar.gz`);
|
|
4124
4174
|
console.log(` mv hcloud ~/.local/bin/`);
|
|
4125
4175
|
console.log(` hcloud version`);
|
|
4126
|
-
console.log(`\
|
|
4127
|
-
}
|
|
4128
|
-
console.log('[macOS] One-liner install:');
|
|
4176
|
+
console.log(`\n Or one-liner (installs LATEST, may differ from pinned ${kooCliVersion || ''}):`);
|
|
4177
|
+
console.log(` curl -sSL ${latestUrl}/hcloud_install.sh -o ./hcloud_install.sh && bash ./hcloud_install.sh -y`);
|
|
4129
4178
|
console.log(
|
|
4130
|
-
|
|
4179
|
+
` \x1b[33m⚠️ The one-liner installs the latest KooCLI. If \`hcloud version\` != ${kooCliVersion}, doctor/check_cli will warn — use the pinned download above instead.\x1b[0m`,
|
|
4131
4180
|
);
|
|
4132
|
-
console.log(`\
|
|
4181
|
+
console.log(`\nFull guide: https://support.huaweicloud.com/qs-hcli/hcli_02_003_02.html`);
|
|
4182
|
+
} else if (os === 'darwin') {
|
|
4183
|
+
console.log('[macOS] Auto-install (pinned to KooCLI <version>):'.replace('<version>', kooCliVersion || ''));
|
|
4133
4184
|
const pkg = arch === 'arm64' ? 'mac-arm64' : 'mac-amd64';
|
|
4134
4185
|
console.log(` curl -LO "${baseUrl}/huaweicloud-cli-${pkg}.tar.gz"`);
|
|
4135
4186
|
console.log(` tar -zxvf huaweicloud-cli-${pkg}.tar.gz`);
|
|
4136
4187
|
console.log(` mv hcloud /usr/local/bin/`);
|
|
4137
4188
|
console.log(` hcloud version`);
|
|
4189
|
+
console.log(`\n Or one-liner (installs LATEST, may differ from pinned ${kooCliVersion || ''}):`);
|
|
4190
|
+
console.log(` curl -sSL ${latestUrl}/hcloud_install.sh -o ./hcloud_install.sh && bash ./hcloud_install.sh -y`);
|
|
4191
|
+
console.log(
|
|
4192
|
+
` \x1b[33m⚠️ The one-liner installs the latest KooCLI. If \`hcloud version\` != ${kooCliVersion}, doctor/check_cli will warn — use the pinned download above instead.\x1b[0m`,
|
|
4193
|
+
);
|
|
4138
4194
|
console.log(`\nFull guide: https://support.huaweicloud.com/qs-hcli/hcli_02_003_03.html`);
|
|
4139
4195
|
}
|
|
4140
4196
|
|
|
@@ -4346,12 +4402,18 @@ async function cmdAuthReconcile() {
|
|
|
4346
4402
|
console.log(`OBS sync failed: ${error.message}`);
|
|
4347
4403
|
}
|
|
4348
4404
|
const profile = resolveManagedProfile();
|
|
4405
|
+
let hcloudSynced = false;
|
|
4349
4406
|
if (profile) {
|
|
4350
4407
|
const r = runHcloudConfigure(profile, credentials.ak, credentials.sk, credentials.region);
|
|
4408
|
+
hcloudSynced = r.ok;
|
|
4351
4409
|
console.log(` KooCLI ${r.ok ? 'synced' : 'sync failed'}: profile=${profile} ${r.error || ''}`);
|
|
4352
4410
|
}
|
|
4353
|
-
|
|
4354
|
-
|
|
4411
|
+
if (hcloudSynced) {
|
|
4412
|
+
writeLastSync({ kooCliProfile: profile, s1Fingerprint: fingerprint(credentials.ak, credentials.sk) });
|
|
4413
|
+
console.log('Done. .last_sync refreshed.');
|
|
4414
|
+
} else {
|
|
4415
|
+
console.log('Done. .last_sync was not refreshed because KooCLI sync did not complete.');
|
|
4416
|
+
}
|
|
4355
4417
|
}
|
|
4356
4418
|
|
|
4357
4419
|
async function cmdAuthSync() {
|
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
resolveSkipFilePath,
|
|
58
58
|
upgradePackage,
|
|
59
59
|
} from './update-check.mjs';
|
|
60
|
+
import { hcloudProbeNextStep, probeHcloud } from './hcloud-probe.mjs';
|
|
60
61
|
|
|
61
62
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
62
63
|
const SKILLS_ROOT_DEV = join(__dirname, '..', 'skills');
|
|
@@ -174,7 +175,8 @@ const SKILLS_ROOT = resolveSkillsRoot();
|
|
|
174
175
|
export const TOOL_DEFINITIONS = [
|
|
175
176
|
{
|
|
176
177
|
name: 'huaweicloud_check_cli',
|
|
177
|
-
description:
|
|
178
|
+
description:
|
|
179
|
+
'Check whether Huawei Cloud KooCLI hcloud is installed and whether its version matches the plugin paired version. Returns redacted output.',
|
|
178
180
|
inputSchema: {
|
|
179
181
|
type: 'object',
|
|
180
182
|
properties: {},
|
|
@@ -982,7 +984,9 @@ function persistCredentials(ak, sk, securityToken, region) {
|
|
|
982
984
|
} else {
|
|
983
985
|
hcloud = runHcloudConfigure(profile, ak, sk, region);
|
|
984
986
|
}
|
|
985
|
-
|
|
987
|
+
if (hcloud.ok) {
|
|
988
|
+
writeLastSync({ kooCliProfile: profile, s1Fingerprint: fingerprint(ak, sk) });
|
|
989
|
+
}
|
|
986
990
|
return {
|
|
987
991
|
status: 'ok',
|
|
988
992
|
scope: 'persist',
|
|
@@ -1380,22 +1384,17 @@ function hookResult(result) {
|
|
|
1380
1384
|
}
|
|
1381
1385
|
|
|
1382
1386
|
export async function runVersionCheck(options = {}) {
|
|
1383
|
-
const result =
|
|
1384
|
-
...options,
|
|
1385
|
-
maxRetries: options.maxRetries ?? 0,
|
|
1386
|
-
});
|
|
1387
|
-
const errorText = result.error || result.stderr || '';
|
|
1388
|
-
const isSpawnError = /ENOENT|SPAWN_ERROR/i.test(errorText) || result.code === 'SPAWN_ERROR';
|
|
1387
|
+
const result = probeHcloud(options);
|
|
1389
1388
|
return {
|
|
1390
|
-
installed: result.
|
|
1391
|
-
authenticated: result.ok && !/配置文件中不存在配置项|USE_ERROR.*配置/i.test(result.
|
|
1392
|
-
errorCode:
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1389
|
+
installed: result.installed,
|
|
1390
|
+
authenticated: result.ok && !/配置文件中不存在配置项|USE_ERROR.*配置/i.test(result.output || ''),
|
|
1391
|
+
errorCode: result.errorCode,
|
|
1392
|
+
status: result.status,
|
|
1393
|
+
output: result.output,
|
|
1394
|
+
kooCliVersion: result.requiredVersion || undefined,
|
|
1395
|
+
installedVersion: result.installedVersion || undefined,
|
|
1396
|
+
versionMismatch: Boolean(result.versionMismatch),
|
|
1397
|
+
nextStep: hcloudProbeNextStep(result),
|
|
1399
1398
|
authHint:
|
|
1400
1399
|
'If hcloud is installed but commands fail with "配置文件中不存在配置项", run `npx huaweicloud-devkit auth init` outside agent chat to configure credentials.',
|
|
1401
1400
|
};
|