huaweicloud-devkit 1.1.2-next.7 → 1.1.2-next.8
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/package.json +1 -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/openclaw.plugin.json +1 -1
- package/plugins/huaweicloud-core/skills/huawei-sandbox/SKILL.md +7 -1
- package/plugins/huaweicloud-core/skills/huaweicloud-core/SKILL.md +1 -1
- package/plugins/huaweicloud-core/src/sandbox/hdkitservice-api.mjs +2 -0
- package/plugins/huaweicloud-core/src/setup-cli.mjs +175 -91
- package/plugins/huaweicloud-core/src/telemetry/agent-registry.mjs +2 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
3
|
"mcpName": "io.github.huaweicloud/huaweicloud-devkit",
|
|
4
|
-
"version": "1.1.2-next.
|
|
4
|
+
"version": "1.1.2-next.8",
|
|
5
5
|
"kooCliVersion": "7.2.12",
|
|
6
6
|
"description": "Agent toolkit that helps coding agents use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities safely and accurately.",
|
|
7
7
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"mcpServers": "./.mcp.json",
|
|
18
18
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
19
19
|
"skills": "./skills/",
|
|
20
|
-
"version": "1.1.2-next.
|
|
20
|
+
"version": "1.1.2-next.8",
|
|
21
21
|
"author": {
|
|
22
22
|
"name": "HuaweiCloud Mate",
|
|
23
23
|
"url": "https://github.com/huaweicloud"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"mcpServers": "./.mcp.json",
|
|
21
21
|
"description": "Agent toolkit that helps coding agents use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities safely and accurately.",
|
|
22
22
|
"skills": "./skills/",
|
|
23
|
-
"version": "1.1.2-next.
|
|
23
|
+
"version": "1.1.2-next.8",
|
|
24
24
|
"author": {
|
|
25
25
|
"name": "HuaweiCloud Mate",
|
|
26
26
|
"url": "https://github.com/huaweicloud"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"mcpServers": "./.mcp.json",
|
|
18
18
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
19
19
|
"skills": "./skills/",
|
|
20
|
-
"version": "1.1.2-next.
|
|
20
|
+
"version": "1.1.2-next.8",
|
|
21
21
|
"author": {
|
|
22
22
|
"name": "HuaweiCloud Mate",
|
|
23
23
|
"url": "https://github.com/huaweicloud"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.1.2-next.
|
|
3
|
+
"version": "1.1.2-next.8",
|
|
4
4
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "HuaweiCloud Mate",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
|
-
"version": "1.1.2-next.
|
|
3
|
+
"version": "1.1.2-next.8",
|
|
4
4
|
"description": "Guide coding agents to use Huawei Cloud Skills, KooCLI, APIs, SDKs, and future MCP capabilities with safer execution and less context.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "HuaweiCloud Mate",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "huaweicloud-devkit",
|
|
3
3
|
"id": "huaweicloud-devkit",
|
|
4
4
|
"displayName": "HuaweiCloud DevKit",
|
|
5
|
-
"version": "1.1.2-next.
|
|
5
|
+
"version": "1.1.2-next.8",
|
|
6
6
|
"family": "bundle-plugin",
|
|
7
7
|
"bundleFormat": "codex",
|
|
8
8
|
"description": "Guide coding agents to use Huawei Cloud safely — KooCLI, APIs, SDKs, 28 MCP tools, skills, and safety guardrails.",
|
|
@@ -112,7 +112,13 @@ Setup is a **plugin-side preflight** — the developer should be asked a questio
|
|
|
112
112
|
sudo nginx -s reload 2>/dev/null || true
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
7. **Inject credentials** (optional): `huaweicloud_sandbox_credentials` — enables cloud API access from sandbox.
|
|
115
|
+
7. **Inject credentials** (optional): `huaweicloud_sandbox_credentials` — enables cloud API access from sandbox. Pass `session_id` **or** `dev_stage_id` (at least one; both come from `sandbox_connect`, and `dev_stage_id` may be omitted to reuse the most recent connect). The tool validates the AK/SK against IAM first — an invalid SK is rejected here instead of failing later with `APIGW.0301` during exec. Example:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{ "dev_stage_id": "<dev_stage_id from connect>" }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
After injection, credentials are also written to `/tmp/hw_creds.sh` for shell access (includes `HW_PROJECT_ID` when resolvable):
|
|
116
122
|
|
|
117
123
|
```bash
|
|
118
124
|
# Source credentials in any sandbox shell before using hcloud/devbridge:
|
|
@@ -12,7 +12,7 @@ Huawei Cloud comprises 200+ services. This skill is the entry point for ANY acti
|
|
|
12
12
|
|
|
13
13
|
## 会话启动
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
首次操作前先调用 `huaweicloud_check_update` 检查插件版本;若未先行检查,插件会在使用中收到服务端升级提示。
|
|
16
16
|
|
|
17
17
|
1. 如果 `updateAvailable == true` 且 `dismissed == false`,先询问用户是否升级
|
|
18
18
|
2. 用户同意 → 调用 `huaweicloud_upgrade`,完成后提示重启会话
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getCredentials } from './hwlink-api.mjs';
|
|
2
2
|
import { getProxyDispatcher } from '../proxy/proxy-agent.mjs';
|
|
3
3
|
import { cacheUserHash } from '../telemetry/telemetry.mjs';
|
|
4
|
+
import { readInstalledVersion } from '../update-check.mjs';
|
|
4
5
|
|
|
5
6
|
function getHdkitBaseUrl() {
|
|
6
7
|
return process.env.HDKITSERVICE_ENDPOINT || 'https://devkit.huaweicloud.com/rest/developer/server/hdkitservice/';
|
|
@@ -19,6 +20,7 @@ async function hdkitRequest(method, path, body, timeoutMs = 300000) {
|
|
|
19
20
|
'Content-Type': 'application/json',
|
|
20
21
|
'X-HW-AK': ak,
|
|
21
22
|
'X-HW-SK': sk,
|
|
23
|
+
'X-HW-Client-Version': readInstalledVersion() || '0.0.0',
|
|
22
24
|
};
|
|
23
25
|
if (securitytoken) {
|
|
24
26
|
headers['X-HW-Security-Token'] = securitytoken;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from 'node:fs';
|
|
11
11
|
import { join, dirname, resolve } from 'node:path';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
|
-
import { homedir, platform } from 'node:os';
|
|
13
|
+
import { homedir, platform, tmpdir } from 'node:os';
|
|
14
14
|
import { createInterface } from 'node:readline';
|
|
15
15
|
import { spawnSync } from 'node:child_process';
|
|
16
16
|
import { randomUUID } from 'node:crypto';
|
|
@@ -3404,72 +3404,89 @@ async function promptGlobalCleanup() {
|
|
|
3404
3404
|
}
|
|
3405
3405
|
}
|
|
3406
3406
|
|
|
3407
|
+
function openclawStatus() {
|
|
3408
|
+
const cdPluginDir = openclawPluginsDir();
|
|
3409
|
+
const cdSkillsDir = openclawSkillsDir();
|
|
3410
|
+
console.log(
|
|
3411
|
+
` MCP Server: ${existsSync(join(cdPluginDir, 'src', 'mcp-server.mjs')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`,
|
|
3412
|
+
);
|
|
3413
|
+
console.log(
|
|
3414
|
+
` Safety Policy: ${existsSync(join(cdPluginDir, 'safety', 'policy.json')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`,
|
|
3415
|
+
);
|
|
3416
|
+
let cdSkillCount = 0;
|
|
3417
|
+
if (existsSync(cdSkillsDir)) {
|
|
3418
|
+
cdSkillCount = readdirSync(cdSkillsDir, { withFileTypes: true }).filter(
|
|
3419
|
+
(d) => d.isDirectory() && d.name.startsWith('huawei'),
|
|
3420
|
+
).length;
|
|
3421
|
+
}
|
|
3422
|
+
console.log(
|
|
3423
|
+
` Skills: ${cdSkillCount > 0 ? `\x1b[32m${cdSkillCount} installed\x1b[0m` : '\x1b[31mNot installed\x1b[0m'}`,
|
|
3424
|
+
);
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
function codexSectionStatus() {
|
|
3428
|
+
if (!hasCodexCLI()) {
|
|
3429
|
+
console.log(' \x1b[33mCodex CLI not found.\x1b[0m');
|
|
3430
|
+
} else {
|
|
3431
|
+
console.log(` Plugin: ${codexStatus() ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`);
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3407
3435
|
async function cmdStatus() {
|
|
3408
|
-
const
|
|
3436
|
+
const scope = parseTarget();
|
|
3409
3437
|
console.log(BANNER);
|
|
3410
3438
|
console.log(`HuaweiCloud DevKit Status\n`);
|
|
3411
3439
|
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
console.log('\n[Hermes Agent]');
|
|
3438
|
-
hermesStatus();
|
|
3439
|
-
}
|
|
3440
|
-
if (target === 'openclaw' || target === 'all') {
|
|
3441
|
-
console.log('\n[OpenClaw]');
|
|
3442
|
-
const cdPluginDir = openclawPluginsDir();
|
|
3443
|
-
const cdSkillsDir = openclawSkillsDir();
|
|
3444
|
-
console.log(
|
|
3445
|
-
` MCP Server: ${existsSync(join(cdPluginDir, 'src', 'mcp-server.mjs')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`,
|
|
3446
|
-
);
|
|
3447
|
-
console.log(
|
|
3448
|
-
` Safety Policy: ${existsSync(join(cdPluginDir, 'safety', 'policy.json')) ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`,
|
|
3449
|
-
);
|
|
3450
|
-
let cdSkillCount = 0;
|
|
3451
|
-
if (existsSync(cdSkillsDir)) {
|
|
3452
|
-
cdSkillCount = readdirSync(cdSkillsDir, { withFileTypes: true }).filter(
|
|
3453
|
-
(d) => d.isDirectory() && d.name.startsWith('huawei'),
|
|
3454
|
-
).length;
|
|
3455
|
-
}
|
|
3456
|
-
console.log(
|
|
3457
|
-
` Skills: ${cdSkillCount > 0 ? `\x1b[32m${cdSkillCount} installed\x1b[0m` : '\x1b[31mNot installed\x1b[0m'}`,
|
|
3458
|
-
);
|
|
3459
|
-
}
|
|
3460
|
-
if (target === 'atomcode' || target === 'all') {
|
|
3461
|
-
console.log('\n[AtomCode]');
|
|
3462
|
-
atomcodeStatus();
|
|
3463
|
-
}
|
|
3464
|
-
if (target === 'codex' || target === 'all') {
|
|
3465
|
-
console.log('\n[Codex]');
|
|
3466
|
-
if (!hasCodexCLI()) {
|
|
3467
|
-
console.log(' \x1b[33mCodex CLI not found.\x1b[0m');
|
|
3468
|
-
} else {
|
|
3469
|
-
console.log(` Plugin: ${codexStatus() ? '\x1b[32mInstalled\x1b[0m' : '\x1b[31mNot installed\x1b[0m'}`);
|
|
3440
|
+
const sections = [
|
|
3441
|
+
{ name: 'OpenCode', run: opencodeStatus, on: (target) => target === 'opencode' || target === 'all' },
|
|
3442
|
+
{ name: 'CodeArts', run: codeartsStatus, on: (target) => target === 'codearts' || target === 'all' },
|
|
3443
|
+
{ name: 'CodeArts Work', run: codeartsWorkStatus, on: (target) => target === 'codearts-work' || target === 'all' },
|
|
3444
|
+
{ name: 'WorkBuddy', run: workbuddyStatus, on: (target) => target === 'workbuddy' || target === 'all' },
|
|
3445
|
+
{ name: 'DSH', run: dshStatus, on: (target) => target === 'dsh' || target === 'all' },
|
|
3446
|
+
{ name: 'OfficeAce', run: officeaceStatus, on: (target) => target === 'officeace' || target === 'all' },
|
|
3447
|
+
{ name: 'Hermes Agent', run: hermesStatus, on: (target) => target === 'hermes' || target === 'all' },
|
|
3448
|
+
{ name: 'OpenClaw', run: openclawStatus, on: (target) => target === 'openclaw' || target === 'all' },
|
|
3449
|
+
{ name: 'AtomCode', run: atomcodeStatus, on: (target) => target === 'atomcode' || target === 'all' },
|
|
3450
|
+
{ name: 'Codex', run: codexSectionStatus, on: (target) => target === 'codex' || target === 'all' },
|
|
3451
|
+
];
|
|
3452
|
+
|
|
3453
|
+
// Capture each section's output so results can be grouped by install state
|
|
3454
|
+
// (installed first) instead of the fixed agent order.
|
|
3455
|
+
const originalLog = console.log;
|
|
3456
|
+
const results = [];
|
|
3457
|
+
for (const section of sections) {
|
|
3458
|
+
if (!section.on(scope)) continue;
|
|
3459
|
+
const lines = [];
|
|
3460
|
+
console.log = (...args) => lines.push(args.map((a) => String(a)).join(' '));
|
|
3461
|
+
try {
|
|
3462
|
+
section.run();
|
|
3463
|
+
} finally {
|
|
3464
|
+
console.log = originalLog;
|
|
3470
3465
|
}
|
|
3466
|
+
const plain = lines.join('\n');
|
|
3467
|
+
const hasInstalled = /Installed/.test(plain);
|
|
3468
|
+
const hasMissing = /Not installed|not found/i.test(plain);
|
|
3469
|
+
const state = hasInstalled && hasMissing ? 'partial' : hasInstalled ? 'installed' : hasMissing ? 'not' : 'unknown';
|
|
3470
|
+
results.push({ name: section.name, lines, state });
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3473
|
+
const stateOrder = { installed: 0, partial: 1, unknown: 2, not: 3 };
|
|
3474
|
+
results.sort((a, b) => stateOrder[a.state] - stateOrder[b.state]);
|
|
3475
|
+
|
|
3476
|
+
const namesIn = (state) => results.filter((r) => r.state === state).map((r) => r.name);
|
|
3477
|
+
const summaryParts = [];
|
|
3478
|
+
if (namesIn('installed').length) summaryParts.push(`已安装: ${namesIn('installed').join(', ')}`);
|
|
3479
|
+
if (namesIn('partial').length) summaryParts.push(`部分安装: ${namesIn('partial').join(', ')}`);
|
|
3480
|
+
if (namesIn('not').length) summaryParts.push(`未安装: ${namesIn('not').join(', ')}`);
|
|
3481
|
+
if (summaryParts.length) console.log(` ${summaryParts.join(' | ')}\n`);
|
|
3482
|
+
|
|
3483
|
+
for (const result of results) {
|
|
3484
|
+
console.log(`[${result.name}]`);
|
|
3485
|
+
for (const line of result.lines) console.log(line);
|
|
3486
|
+
console.log('');
|
|
3471
3487
|
}
|
|
3472
|
-
|
|
3488
|
+
|
|
3489
|
+
console.log('Environment:');
|
|
3473
3490
|
console.log(` Node.js: ${process.version}`);
|
|
3474
3491
|
console.log(` Platform: ${platform()}`);
|
|
3475
3492
|
}
|
|
@@ -3812,6 +3829,7 @@ async function cmdDoctor() {
|
|
|
3812
3829
|
{ path: join(codeartsPluginsDir(), '.installed'), name: 'CodeArts' },
|
|
3813
3830
|
{ path: join(codeartsWorkPluginsDir(), '.installed'), name: 'CodeArts Work' },
|
|
3814
3831
|
{ path: join(dshPluginsDir(), '.installed'), name: 'DSH' },
|
|
3832
|
+
{ path: join(hermesPluginsDir(), '.installed'), name: 'Hermes Agent' },
|
|
3815
3833
|
{ path: join(officeacePluginsDir(), '.installed'), name: 'OfficeAce' },
|
|
3816
3834
|
{ path: join(atomcodePluginsDir(), '.installed'), name: 'AtomCode' },
|
|
3817
3835
|
];
|
|
@@ -4033,10 +4051,6 @@ async function cmdUpdate() {
|
|
|
4033
4051
|
console.log(`\x1b[33mMCP 工具在重启各 agent 会话后才生效。\x1b[0m`);
|
|
4034
4052
|
return;
|
|
4035
4053
|
}
|
|
4036
|
-
|
|
4037
|
-
await cmdUninstall();
|
|
4038
|
-
console.log('');
|
|
4039
|
-
await cmdInstall();
|
|
4040
4054
|
}
|
|
4041
4055
|
|
|
4042
4056
|
async function cmdReinstall() {
|
|
@@ -4167,32 +4181,102 @@ async function cmdInstallHcloud() {
|
|
|
4167
4181
|
printSandboxWarning('沙箱模式拦截了 KooCLI 自动安装(无法创建/写入安装目录)。');
|
|
4168
4182
|
}
|
|
4169
4183
|
}
|
|
4170
|
-
} else if (os === 'linux') {
|
|
4171
|
-
|
|
4172
|
-
const pkg =
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
);
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4184
|
+
} else if (os === 'linux' || os === 'darwin') {
|
|
4185
|
+
const label = os === 'linux' ? 'Linux' : 'macOS';
|
|
4186
|
+
const pkg =
|
|
4187
|
+
os === 'linux'
|
|
4188
|
+
? arch === 'arm64'
|
|
4189
|
+
? 'linux-arm64'
|
|
4190
|
+
: 'linux-amd64'
|
|
4191
|
+
: arch === 'arm64'
|
|
4192
|
+
? 'mac-arm64'
|
|
4193
|
+
: 'mac-amd64';
|
|
4194
|
+
const url = `${baseUrl}/huaweicloud-cli-${pkg}.tar.gz`;
|
|
4195
|
+
const binDir = os === 'linux' ? join(homedir(), '.local', 'bin') : '/usr/local/bin';
|
|
4196
|
+
const binPath = join(binDir, 'hcloud');
|
|
4197
|
+
|
|
4198
|
+
const printManual = () => {
|
|
4199
|
+
console.log(`\n[${label}] Manual install (pinned to KooCLI ${kooCliVersion || ''}):`);
|
|
4200
|
+
console.log(` curl -LO "${url}"`);
|
|
4201
|
+
console.log(` tar -zxvf huaweicloud-cli-${pkg}.tar.gz`);
|
|
4202
|
+
console.log(` mv hcloud ${binDir}/`);
|
|
4203
|
+
console.log(` hcloud version`);
|
|
4204
|
+
console.log(`\n Or one-liner (installs LATEST, may differ from pinned ${kooCliVersion || ''}):`);
|
|
4205
|
+
console.log(` curl -sSL ${latestUrl}/hcloud_install.sh -o ./hcloud_install.sh && bash ./hcloud_install.sh -y`);
|
|
4206
|
+
console.log(
|
|
4207
|
+
` \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`,
|
|
4208
|
+
);
|
|
4209
|
+
console.log(
|
|
4210
|
+
`\nFull guide: https://support.huaweicloud.com/qs-hcli/hcli_02_003_0${os === 'linux' ? '2' : '3'}.html`,
|
|
4211
|
+
);
|
|
4212
|
+
};
|
|
4213
|
+
|
|
4214
|
+
if (detectCodeartsSandbox() === 'sandbox') {
|
|
4215
|
+
printSandboxWarning('沙箱模式拦截了 KooCLI 自动安装(无法创建/写入安装目录)。');
|
|
4216
|
+
printManual();
|
|
4217
|
+
} else {
|
|
4218
|
+
console.log(`[${label}] Auto-installing to ${binDir}...`);
|
|
4219
|
+
try {
|
|
4220
|
+
const tmpTar = join(tmpdir(), `huaweicloud-cli-${pkg}.tar.gz`);
|
|
4221
|
+
console.log(` Downloading ${url}...`);
|
|
4222
|
+
const dl = spawnSync('curl', ['-fL', url, '-o', tmpTar], { stdio: 'inherit', timeout: 180000 });
|
|
4223
|
+
if (dl.status !== 0) throw new Error(`下载失败 (curl exit ${dl.status})`);
|
|
4224
|
+
|
|
4225
|
+
console.log(' Extracting...');
|
|
4226
|
+
const ex = spawnSync('tar', ['-xzf', tmpTar, '-C', tmpdir()], { stdio: 'inherit', timeout: 60000 });
|
|
4227
|
+
if (ex.status !== 0) throw new Error(`解压失败 (tar exit ${ex.status})`);
|
|
4228
|
+
rmSync(tmpTar, { force: true });
|
|
4229
|
+
const extracted = join(tmpdir(), 'hcloud');
|
|
4230
|
+
if (!existsSync(extracted)) throw new Error('hcloud 二进制未生成,可能已被安全软件拦截');
|
|
4231
|
+
|
|
4232
|
+
try {
|
|
4233
|
+
mkdirSync(binDir, { recursive: true });
|
|
4234
|
+
} catch {}
|
|
4235
|
+
console.log(' Installing...');
|
|
4236
|
+
let mv = spawnSync('mv', [extracted, binPath], { stdio: 'inherit', timeout: 30000 });
|
|
4237
|
+
if (mv.status !== 0) {
|
|
4238
|
+
console.log(' 目标目录需要权限,尝试 sudo mv...');
|
|
4239
|
+
mv = spawnSync('sudo', ['mv', extracted, binPath], { stdio: 'inherit', timeout: 30000 });
|
|
4240
|
+
if (mv.status !== 0) throw new Error(`安装失败 (mv exit ${mv.status})`);
|
|
4241
|
+
}
|
|
4242
|
+
|
|
4243
|
+
console.log(`\n\x1b[32mInstall complete.\x1b[0m`);
|
|
4244
|
+
console.log(` Verify: ${binPath} version`);
|
|
4245
|
+
|
|
4246
|
+
// Ask user before accepting the privacy agreement — never auto-accept.
|
|
4247
|
+
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
4248
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
4249
|
+
const agree = await new Promise((resolve) => {
|
|
4250
|
+
rl.question('\n KooCLI requires accepting its privacy agreement. Do you accept? (y/N) ', (answer) => {
|
|
4251
|
+
rl.close();
|
|
4252
|
+
resolve(/^\s*y\s*$/i.test(answer));
|
|
4253
|
+
});
|
|
4254
|
+
});
|
|
4255
|
+
if (agree) {
|
|
4256
|
+
const r = spawnSync(binPath, ['version'], {
|
|
4257
|
+
input: 'y\n',
|
|
4258
|
+
encoding: 'utf8',
|
|
4259
|
+
timeout: 15000,
|
|
4260
|
+
});
|
|
4261
|
+
console.log(
|
|
4262
|
+
r.status === 0
|
|
4263
|
+
? ' \x1b[32mPrivacy agreement accepted. KooCLI ready.\x1b[0m'
|
|
4264
|
+
: ' \x1b[33m无法写入配置目录。请在终端运行: hcloud version 并按提示操作\x1b[0m',
|
|
4265
|
+
);
|
|
4266
|
+
} else {
|
|
4267
|
+
console.log(' \x1b[33m请手动接受隐私协议:在终端运行 hcloud version 并按提示操作\x1b[0m');
|
|
4268
|
+
}
|
|
4269
|
+
} else {
|
|
4270
|
+
console.log(' \x1b[33m非交互会话:请稍后在终端运行 hcloud version 并按提示接受隐私协议\x1b[0m');
|
|
4271
|
+
}
|
|
4272
|
+
} catch (error) {
|
|
4273
|
+
console.log(`\n\x1b[33mAuto-install failed: ${error.message}\x1b[0m`);
|
|
4274
|
+
printManual();
|
|
4275
|
+
if (detectCodeartsSandbox() === 'sandbox') {
|
|
4276
|
+
printSandboxWarning('沙箱模式拦截了 KooCLI 自动安装(无法创建/写入安装目录)。');
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4196
4280
|
}
|
|
4197
4281
|
|
|
4198
4282
|
console.log('\nAfter install, set HCLOUD_BIN if hcloud is not on PATH.');
|
|
@@ -68,7 +68,7 @@ export const AGENTS = [
|
|
|
68
68
|
id: 'officeace',
|
|
69
69
|
pathPatterns: ['/.office-claw/', '/.officeace/'],
|
|
70
70
|
envVars: ['OFFICEACE_SESSION_ID', 'OFFICE_CLAW_CONFIG_ROOT'],
|
|
71
|
-
clientNames: ['office-claw-mcp-connector-probe'],
|
|
71
|
+
clientNames: ['office-claw-mcp-connector-probe', 'officeace-agent'],
|
|
72
72
|
version: { type: 'officeace' },
|
|
73
73
|
},
|
|
74
74
|
{
|
|
@@ -94,6 +94,7 @@ export const AGENTS = [
|
|
|
94
94
|
id: 'cursor',
|
|
95
95
|
pathPatterns: ['/.cursor/', '/cursor/'],
|
|
96
96
|
envVars: ['CURSOR_SESSION_ID', 'CURSOR_GIT_WORKDIR'],
|
|
97
|
+
clientNames: ['cursor-vscode'],
|
|
97
98
|
version: null,
|
|
98
99
|
},
|
|
99
100
|
{
|