huaweicloud-devkit 1.1.4-next.1 → 1.1.4-next.3
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-billing/SKILL.md +8 -8
- package/plugins/huaweicloud-core/skills/huaweicloud-cli-and-auth/SKILL.md +2 -2
- package/plugins/huaweicloud-core/src/hcloud-cli.mjs +5 -73
- package/plugins/huaweicloud-core/src/mcp-protocol.mjs +14 -6
- package/plugins/huaweicloud-core/src/mcp-server-remote.mjs +2 -1
- package/plugins/huaweicloud-core/src/mcp-server.mjs +1 -1
- package/plugins/huaweicloud-core/src/tools.mjs +11 -9
- package/plugins/huaweicloud-core/src/update-check.mjs +25 -8
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.4-next.
|
|
4
|
+
"version": "1.1.4-next.3",
|
|
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.4-next.
|
|
20
|
+
"version": "1.1.4-next.3",
|
|
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.4-next.
|
|
23
|
+
"version": "1.1.4-next.3",
|
|
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.4-next.
|
|
20
|
+
"version": "1.1.4-next.3",
|
|
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.4-next.
|
|
3
|
+
"version": "1.1.4-next.3",
|
|
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.4-next.
|
|
3
|
+
"version": "1.1.4-next.3",
|
|
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.4-next.
|
|
5
|
+
"version": "1.1.4-next.3",
|
|
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.",
|
|
@@ -16,14 +16,14 @@ Domain expertise for billing queries (BSS). Covers cost tracking, bill details,
|
|
|
16
16
|
|
|
17
17
|
## Critical Warnings
|
|
18
18
|
|
|
19
|
-
| Trap | Why
|
|
20
|
-
| ----------------------------------------- |
|
|
21
|
-
| Bills delayed ~24h | Yesterday's costs may not appear until the next day
|
|
22
|
-
| BSS Admin role needed | IAM user must have BSS Administrator or Finance role
|
|
23
|
-
| Currency conversion varies | Cross-region costs use daily exchange rates
|
|
24
|
-
| Region fixed to cn-north-1 | BSS operations only support `--cli-region=cn-north-1` in KooCLI. This is a KooCLI metadata limitation — the billing data itself covers all regions.
|
|
25
|
-
| English catalog missing BSS | `Unsupported service: BSS` under the default `en` language is a KooCLI catalog gap, not a missing service. devkit
|
|
26
|
-
| `缺少必填参数 cli-domain-id` / APIGW.0301 | Invalid credentials — KooCLI can't resolve the account-id
|
|
19
|
+
| Trap | Why |
|
|
20
|
+
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
21
|
+
| Bills delayed ~24h | Yesterday's costs may not appear until the next day |
|
|
22
|
+
| BSS Admin role needed | IAM user must have BSS Administrator or Finance role |
|
|
23
|
+
| Currency conversion varies | Cross-region costs use daily exchange rates |
|
|
24
|
+
| Region fixed to cn-north-1 | BSS operations only support `--cli-region=cn-north-1` in KooCLI. This is a KooCLI metadata limitation — the billing data itself covers all regions. |
|
|
25
|
+
| English catalog missing BSS | `Unsupported service: BSS` under the default `en` language is a KooCLI catalog gap, not a missing service. devkit detects it and advises the supported fix `hcloud configure set --cli-lang=cn` (switch is global-only; KooCLI has no per-command `--cli-lang` flag). Running with Chinese mode from the start (see Prerequisites) avoids the issue entirely. |
|
|
26
|
+
| `缺少必填参数 cli-domain-id` / APIGW.0301 | Invalid credentials — KooCLI can't resolve the account-id | Re-run `npx huaweicloud-devkit auth init` |
|
|
27
27
|
|
|
28
28
|
## Common Workflows
|
|
29
29
|
|
|
@@ -109,8 +109,8 @@ If a command needs an `adminPass` or other password field, do not leave plaintex
|
|
|
109
109
|
## Language / Service Catalog Trap
|
|
110
110
|
|
|
111
111
|
- KooCLI loads the service list from a per-language catalog: `~/.hcloud/metaRepo/services_{cn,en}.json`. The **English catalog is incomplete** (149 services vs 220 in Chinese; ~70 services — BSS, DevStar, CloudTable, FRS, ASM, ... — are missing). A command against a service that only exists in the Chinese catalog fails with a misleading `Unsupported service: X`.
|
|
112
|
-
-
|
|
113
|
-
-
|
|
112
|
+
- KooCLI has **no per-command `--cli-lang` flag** — appending `--cli-lang=cn` is rejected as `不正确的参数:cli-lang`. The language switch is **global only**: `hcloud configure set --cli-lang=cn` (changes ALL CLI output language).
|
|
113
|
+
- `huaweicloud-devkit` detects `Unsupported service: X` and, when the cause is the en-catalog gap, returns an actionable hint to run `hcloud configure set --cli-lang=cn` (or to check the service name / refresh metadata for genuinely unknown services). It never mutates your command.
|
|
114
114
|
- Distinguish from **region** metadata limits (e.g., BSS only supports `cn-north-1`): a region error is NOT solved by switching language.
|
|
115
115
|
|
|
116
116
|
## Output Formatting
|
|
@@ -196,24 +196,6 @@ function obsWriteHint(args) {
|
|
|
196
196
|
return 'OBS write operations are obsutil-style and always write-class. Before executing, present the full resource manifest (bucket/object list) to the user for ONE batch approval, then run each command through plan → approve (see huawei-iac skill, Provisioning Rules).';
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
const OBS_SUBCOMMANDS = new Set([
|
|
200
|
-
'help',
|
|
201
|
-
'ls',
|
|
202
|
-
'mb',
|
|
203
|
-
'cp',
|
|
204
|
-
'mv',
|
|
205
|
-
'rm',
|
|
206
|
-
'chattri',
|
|
207
|
-
'config',
|
|
208
|
-
'cors',
|
|
209
|
-
'lifecycle',
|
|
210
|
-
'policy',
|
|
211
|
-
'share',
|
|
212
|
-
'sync',
|
|
213
|
-
'url',
|
|
214
|
-
'sign',
|
|
215
|
-
]);
|
|
216
|
-
|
|
217
199
|
const CATALOG_TTL_MS = 5 * 60 * 1000;
|
|
218
200
|
let _catalogCache = { dir: null, t: 0, cn: new Set(), en: new Set() };
|
|
219
201
|
|
|
@@ -252,19 +234,9 @@ export function classifyUnsupported(service, metaDir) {
|
|
|
252
234
|
}
|
|
253
235
|
// One or both catalog files are missing locally — we cannot distinguish
|
|
254
236
|
// "service missing from the en catalog" from "en catalog not downloaded".
|
|
255
|
-
// Only the reactive fallback may attempt --cli-lang=cn for this case.
|
|
256
237
|
return 'unknown';
|
|
257
238
|
}
|
|
258
239
|
|
|
259
|
-
export function shouldInjectLang(args, metaDir) {
|
|
260
|
-
const arr = Array.isArray(args) ? args.map(String) : [];
|
|
261
|
-
if (arr.some((a) => /^--cli-lang=/.test(a))) return false;
|
|
262
|
-
const s = (arr[0] || '').toUpperCase();
|
|
263
|
-
if (!s) return false;
|
|
264
|
-
if (s === 'OBS' && OBS_SUBCOMMANDS.has((arr[1] || '').toLowerCase())) return false;
|
|
265
|
-
return classifyUnsupported(s, metaDir) === 'lang-missing';
|
|
266
|
-
}
|
|
267
|
-
|
|
268
240
|
export function planHcloudCommand(args, options = {}) {
|
|
269
241
|
const normalizedArgs = Array.isArray(args) ? args.map(String) : [];
|
|
270
242
|
const classification = classifyHcloudArgs(normalizedArgs, options);
|
|
@@ -301,7 +273,8 @@ const UNSUPPORTED_SERVICE_RE = /Unsupported service:\s*([A-Za-z0-9_-]+)/i;
|
|
|
301
273
|
function appendLangHint(result, service, metaDir) {
|
|
302
274
|
const cause = classifyUnsupported(service, metaDir);
|
|
303
275
|
if (cause === 'lang-missing' || cause === 'unknown') {
|
|
304
|
-
const nextStep =
|
|
276
|
+
const nextStep =
|
|
277
|
+
'KooCLI switches language only via global config: hcloud configure set --cli-lang=cn (changes CLI output language; BSS requires Chinese mode).';
|
|
305
278
|
return {
|
|
306
279
|
...result,
|
|
307
280
|
langCause: cause,
|
|
@@ -318,16 +291,6 @@ function appendLangHint(result, service, metaDir) {
|
|
|
318
291
|
};
|
|
319
292
|
}
|
|
320
293
|
|
|
321
|
-
function isObsUtilStyle(args) {
|
|
322
|
-
const s = String(args[0] || '').toUpperCase();
|
|
323
|
-
return s === 'OBS' && OBS_SUBCOMMANDS.has(String(args[1] || '').toLowerCase());
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function canRetryLang(service, metaDir) {
|
|
327
|
-
const cause = classifyUnsupported(service, metaDir);
|
|
328
|
-
return cause === 'lang-missing' || cause === 'unknown';
|
|
329
|
-
}
|
|
330
|
-
|
|
331
294
|
export async function runHcloud(args, options = {}) {
|
|
332
295
|
const normalizedArgs = Array.isArray(args) ? args.map(String) : [];
|
|
333
296
|
const plan = {
|
|
@@ -337,44 +300,13 @@ export async function runHcloud(args, options = {}) {
|
|
|
337
300
|
assertAllowed(plan.classification);
|
|
338
301
|
|
|
339
302
|
const metaDir = options.metaDir;
|
|
340
|
-
const langGiven = normalizedArgs.some((a) => /^--cli-lang=/.test(a));
|
|
341
|
-
const injectedArgs =
|
|
342
|
-
!langGiven && shouldInjectLang(normalizedArgs, metaDir) ? [...normalizedArgs, '--cli-lang=cn'] : null;
|
|
343
|
-
|
|
344
|
-
if (injectedArgs) {
|
|
345
|
-
const result = await runHcloudOnceWithRetries(
|
|
346
|
-
{
|
|
347
|
-
...plan,
|
|
348
|
-
rawArgs: injectedArgs,
|
|
349
|
-
},
|
|
350
|
-
options,
|
|
351
|
-
);
|
|
352
|
-
const tagged = {
|
|
353
|
-
...result,
|
|
354
|
-
autoRetried: true,
|
|
355
|
-
injection: 'proactive',
|
|
356
|
-
injectedLang: 'cn',
|
|
357
|
-
};
|
|
358
|
-
if (tagged.ok) return tagged;
|
|
359
|
-
const match = `${result.stderr || ''}\n${result.stdout || ''}`.match(UNSUPPORTED_SERVICE_RE);
|
|
360
|
-
return match ? appendLangHint(tagged, match[1], metaDir) : tagged;
|
|
361
|
-
}
|
|
362
303
|
|
|
304
|
+
// KooCLI only switches language globally (`hcloud configure set --cli-lang=cn`); there is no
|
|
305
|
+
// per-command `--cli-lang` flag (it is rejected as "不正确的参数:cli-lang"). So we never mutate
|
|
306
|
+
// the command — we run it as-is and annotate `Unsupported service` with an actionable cause.
|
|
363
307
|
const result = await runHcloudOnceWithRetries(plan, options);
|
|
364
308
|
const text = `${result.stderr || ''}\n${result.stdout || ''}`;
|
|
365
309
|
const match = text.match(UNSUPPORTED_SERVICE_RE);
|
|
366
|
-
if (match && !langGiven && !result.ok && canRetryLang(match[1], metaDir) && !isObsUtilStyle(normalizedArgs)) {
|
|
367
|
-
const retry = await runHcloudOnceWithRetries(
|
|
368
|
-
{
|
|
369
|
-
...plan,
|
|
370
|
-
rawArgs: [...normalizedArgs, '--cli-lang=cn'],
|
|
371
|
-
},
|
|
372
|
-
options,
|
|
373
|
-
);
|
|
374
|
-
return retry.ok
|
|
375
|
-
? { ...retry, autoRetried: true, reactiveFallback: true, injection: 'reactive', injectedLang: 'cn' }
|
|
376
|
-
: appendLangHint(retry, match[1], metaDir);
|
|
377
|
-
}
|
|
378
310
|
if (match && !result.ok) {
|
|
379
311
|
return appendLangHint(result, match[1], metaDir);
|
|
380
312
|
}
|
|
@@ -22,21 +22,29 @@ for (const base of [pluginRoot, packageRoot]) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// 会话内首个非 check/upgrade 工具调用附加 _updateInfo,只消费一次。
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
// 按会话隔离:同进程内不同会话(A/B)各自首次提示;stdio 用固定 'stdin'。
|
|
26
|
+
const consumedBySession = new Map();
|
|
27
|
+
export function _decorateResult(sessionId, name, result) {
|
|
28
|
+
if (consumedBySession.get(sessionId)) return result;
|
|
28
29
|
try {
|
|
29
30
|
const hint = peekCachedUpdateInfo();
|
|
30
31
|
if (!hint) return result;
|
|
31
32
|
const decorated = applyUpdateHint(result, name, hint);
|
|
32
|
-
if (decorated !== result)
|
|
33
|
+
if (decorated !== result) consumedBySession.set(sessionId, true);
|
|
33
34
|
return decorated;
|
|
34
35
|
} catch {
|
|
35
36
|
return result; // 兜底装饰失败绝不影响工具调用
|
|
36
37
|
}
|
|
37
38
|
}
|
|
39
|
+
export function _resetHintConsumption() {
|
|
40
|
+
consumedBySession.clear();
|
|
41
|
+
}
|
|
42
|
+
export function _isHintConsumed(sessionId) {
|
|
43
|
+
return Boolean(consumedBySession.get(sessionId));
|
|
44
|
+
}
|
|
38
45
|
|
|
39
|
-
export async function dispatch(method, params) {
|
|
46
|
+
export async function dispatch(method, params, opts = {}) {
|
|
47
|
+
const sessionId = opts?.sessionId || 'default';
|
|
40
48
|
if (method === 'initialize') {
|
|
41
49
|
const ci = params.clientInfo || {};
|
|
42
50
|
|
|
@@ -68,7 +76,7 @@ export async function dispatch(method, params) {
|
|
|
68
76
|
|
|
69
77
|
if (method === 'tools/call') {
|
|
70
78
|
const result = await callTool(params.name, params.arguments || {});
|
|
71
|
-
const decorated =
|
|
79
|
+
const decorated = _decorateResult(sessionId, params.name, result);
|
|
72
80
|
return {
|
|
73
81
|
content: [
|
|
74
82
|
{
|
|
@@ -50,7 +50,8 @@ export async function startRemoteServer({ port = DEFAULT_PORT, host = DEFAULT_HO
|
|
|
50
50
|
|
|
51
51
|
let response;
|
|
52
52
|
try {
|
|
53
|
-
const
|
|
53
|
+
const sessionId = (req.headers['mcp-session-id'] || '').trim() || 'default';
|
|
54
|
+
const result = await dispatch(message.method, message.params || {}, { sessionId });
|
|
54
55
|
response = { jsonrpc: '2.0', id: message.id, result };
|
|
55
56
|
if (message.method === 'initialize') {
|
|
56
57
|
res.setHeader('MCP-Protocol-Version', result.protocolVersion || '2024-11-05');
|
|
@@ -159,7 +159,7 @@ function runStdioServer() {
|
|
|
159
159
|
return;
|
|
160
160
|
}
|
|
161
161
|
try {
|
|
162
|
-
const result = await dispatch(message.method, message.params || {});
|
|
162
|
+
const result = await dispatch(message.method, message.params || {}, { sessionId: 'stdin' });
|
|
163
163
|
writeMessage({ jsonrpc: '2.0', id: message.id, result });
|
|
164
164
|
} catch (error) {
|
|
165
165
|
writeMessage({
|
|
@@ -1049,7 +1049,7 @@ function normalizeNumericArgs(args) {
|
|
|
1049
1049
|
return out;
|
|
1050
1050
|
}
|
|
1051
1051
|
|
|
1052
|
-
export async function callTool(name, rawArgs = {}) {
|
|
1052
|
+
export async function callTool(name, rawArgs = {}, opts = {}) {
|
|
1053
1053
|
const args = normalizeNumericArgs(rawArgs);
|
|
1054
1054
|
const toolValue = toolInvokeValue(name, args);
|
|
1055
1055
|
trackToolInvoke(name, toolValue);
|
|
@@ -1448,33 +1448,35 @@ export async function callTool(name, rawArgs = {}) {
|
|
|
1448
1448
|
case 'huaweicloud_voucher_claim':
|
|
1449
1449
|
return await hdkitVoucherClaim(args.domain_id);
|
|
1450
1450
|
case 'huaweicloud_check_update':
|
|
1451
|
-
return await handleCheckUpdate(args);
|
|
1451
|
+
return await handleCheckUpdate(args, { sessionId: opts?.sessionId });
|
|
1452
1452
|
case 'huaweicloud_upgrade':
|
|
1453
|
-
return await handleUpgrade(args);
|
|
1453
|
+
return await handleUpgrade(args, { sessionId: opts?.sessionId });
|
|
1454
1454
|
default:
|
|
1455
1455
|
throw new Error(`Unknown tool: ${name}`);
|
|
1456
1456
|
}
|
|
1457
1457
|
}
|
|
1458
1458
|
|
|
1459
|
-
async function handleCheckUpdate(args = {}) {
|
|
1459
|
+
async function handleCheckUpdate(args = {}, opts = {}) {
|
|
1460
|
+
const sessionId = opts?.sessionId || null;
|
|
1460
1461
|
const current = readInstalledVersion() || '0.0.0';
|
|
1461
1462
|
if (args.dismiss === true) {
|
|
1462
|
-
const distTags = await getUpdateDistTags(current);
|
|
1463
|
+
const distTags = await getUpdateDistTags(current, { sessionId });
|
|
1463
1464
|
const target = determineTarget(current, distTags);
|
|
1464
1465
|
const dismissedVersion =
|
|
1465
1466
|
typeof args.dismissVersion === 'string' && args.dismissVersion ? args.dismissVersion : target || current;
|
|
1466
|
-
const state = writeSkipState(resolveSkipFilePath(), dismissedVersion);
|
|
1467
|
+
const state = writeSkipState(resolveSkipFilePath(sessionId), dismissedVersion);
|
|
1467
1468
|
invalidateUpdateCache();
|
|
1468
1469
|
return judgeUpdate(current, distTags, state);
|
|
1469
1470
|
}
|
|
1470
|
-
return getCachedUpdateInfo(current);
|
|
1471
|
+
return getCachedUpdateInfo(current, { sessionId });
|
|
1471
1472
|
}
|
|
1472
1473
|
|
|
1473
|
-
async function handleUpgrade(args = {}) {
|
|
1474
|
+
async function handleUpgrade(args = {}, opts = {}) {
|
|
1475
|
+
const sessionId = opts?.sessionId || null;
|
|
1474
1476
|
const target = typeof args.target === 'string' && args.target ? args.target : 'all';
|
|
1475
1477
|
const version = typeof args.version === 'string' && args.version ? args.version : 'latest';
|
|
1476
1478
|
const current = readInstalledVersion() || '0.0.0';
|
|
1477
|
-
const info = await getCachedUpdateInfo(current);
|
|
1479
|
+
const info = await getCachedUpdateInfo(current, { sessionId });
|
|
1478
1480
|
if (info && info.result === 'up_to_date') {
|
|
1479
1481
|
return {
|
|
1480
1482
|
success: false,
|
|
@@ -152,12 +152,26 @@ export function fallbackSkipFilePath() {
|
|
|
152
152
|
return join(base, '.config', 'huaweicloud', 'devkit-skip.json');
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
// 会话化 skip 文件:remote 多会话按 sessionId 拆分,stdio/默认保持原文件(向后兼容)。
|
|
156
|
+
function sanitizeSessionId(sessionId) {
|
|
157
|
+
return String(sessionId || '').replace(/[^0-9a-zA-Z-]/g, '_');
|
|
158
|
+
}
|
|
159
|
+
|
|
155
160
|
// A1 定稿: 标准 agent 用插件目录副本(有 package.json); codex 等无副本时回退共享文件
|
|
156
|
-
export function resolveSkipFilePath() {
|
|
161
|
+
export function resolveSkipFilePath(sessionId = null) {
|
|
162
|
+
let base;
|
|
157
163
|
try {
|
|
158
|
-
if (existsSync(join(dirname(skipFilePath()), 'package.json')))
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
if (existsSync(join(dirname(skipFilePath()), 'package.json'))) {
|
|
165
|
+
base = skipFilePath();
|
|
166
|
+
} else {
|
|
167
|
+
base = fallbackSkipFilePath();
|
|
168
|
+
}
|
|
169
|
+
} catch {
|
|
170
|
+
base = fallbackSkipFilePath();
|
|
171
|
+
}
|
|
172
|
+
// stdio / 默认 / 无 session → 原文件(保持向后兼容)
|
|
173
|
+
if (!sessionId || sessionId === 'default' || sessionId === 'stdin') return base;
|
|
174
|
+
return `${base}.${sanitizeSessionId(sessionId)}`;
|
|
161
175
|
}
|
|
162
176
|
|
|
163
177
|
export function readSkipState(file) {
|
|
@@ -293,12 +307,15 @@ function cacheValid(now = Date.now()) {
|
|
|
293
307
|
return Boolean(cachedDistTags) && now - cachedAt <= TTL_MS;
|
|
294
308
|
}
|
|
295
309
|
|
|
296
|
-
export async function getCachedUpdateInfo(
|
|
310
|
+
export async function getCachedUpdateInfo(
|
|
311
|
+
current,
|
|
312
|
+
{ doQuery = queryDistTags, now = Date.now(), sessionId = null } = {},
|
|
313
|
+
) {
|
|
297
314
|
if (process.env.HUAWEICLOUD_DEVKIT_SKIP_UPDATE === '1') {
|
|
298
315
|
lastHint = judgeUpdate(current, null, undefined, now);
|
|
299
316
|
return lastHint;
|
|
300
317
|
}
|
|
301
|
-
const skipState = readSkipState(resolveSkipFilePath());
|
|
318
|
+
const skipState = readSkipState(resolveSkipFilePath(sessionId));
|
|
302
319
|
if (!cacheValid(now)) {
|
|
303
320
|
if (!cachedDistTags && now - failedAt < FAIL_THROTTLE_MS) {
|
|
304
321
|
lastHint = judgeUpdate(current, null, skipState, now);
|
|
@@ -331,8 +348,8 @@ export function peekCachedUpdateInfo() {
|
|
|
331
348
|
return lastHint && lastHint.updateAvailable && lastHint.targetVersion ? lastHint : null;
|
|
332
349
|
}
|
|
333
350
|
|
|
334
|
-
export async function getUpdateDistTags(current) {
|
|
335
|
-
const result = await getCachedUpdateInfo(current);
|
|
351
|
+
export async function getUpdateDistTags(current, { sessionId = null } = {}) {
|
|
352
|
+
const result = await getCachedUpdateInfo(current, { sessionId });
|
|
336
353
|
if (!result) return null;
|
|
337
354
|
return { latest: result.latestStable ?? null, next: result.latestNext ?? null };
|
|
338
355
|
}
|