dsh-home-ilife 0.3.83 → 0.3.85
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/dist/bridge.d.ts +29 -26
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +31 -81
- package/dist/bridge.js.map +1 -1
- package/dist/client.js +27 -8
- package/dist/client.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/bridge.d.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/** dsh-home-ilife 取数桥(P10 脚手架:纯 CLI 单轨)。
|
|
2
|
+
*
|
|
3
|
+
* #696 起兼设置页的配置读写口。
|
|
4
|
+
*
|
|
5
|
+
* 本文件只剩「本家的规格 + 契约收窄」:机械动作(定位已装技能包、异步 spawn、超时杀进程、
|
|
6
|
+
* 信封校验、错误码映射)收进总管共用件 `dsh-life-pack` 根入口的 skill-cli 共用件——六家只有那一份实现。
|
|
7
|
+
* 边界不变:面板与跨技能只经 host.call 触发本桥,本桥只经 spawn 调技能包唯一出口
|
|
8
|
+
* packages/skill-home/dist/cli/cmd_read.js(argv+JSON+exit,stdout 纯 envelope JSON 一行);
|
|
9
|
+
* 本文件不 import 任何技能实现(只读消费其 dist/CLI);缺失阻断不返空:
|
|
10
|
+
* CLI 缺席/非 0/非 JSON/回执 key 不符一律抛错,绝不返回空数组冒充正常。
|
|
11
|
+
* 技能包不动(只读);combos.yaml 不动。
|
|
12
|
+
*/
|
|
13
|
+
import { resolveNodeBin, SPAWN_TIMEOUT_MS } from 'dsh-life-pack';
|
|
14
|
+
import type { SkillCliErrorCode } from 'dsh-life-pack';
|
|
1
15
|
import type { ConfigSurfaceReply } from './contract.js';
|
|
2
16
|
export declare const SKILL_PACKAGE: "skill-home";
|
|
3
17
|
export declare const SKILL_CLI: "packages/skill-home/dist/cli/cmd_read.js";
|
|
@@ -5,40 +19,30 @@ export declare const HOST_CALL_METHOD: "ilife.home.read";
|
|
|
5
19
|
export declare const MANAGER_PACKAGE: "dsh-life-pack";
|
|
6
20
|
export declare const MANAGER_MISSING_HINT = "\u603B\u7BA1\u7F3A\u5E2D\uFF0C\u8BF7\u8865\u88C5\uFF1Adsh plugin add dsh-life-pack dsh-home-ilife\uFF08\u4E0D\u8BB8\u5355\u5378\u603B\u7BA1\uFF09";
|
|
7
21
|
export declare class SkillBridgeError extends Error {
|
|
8
|
-
readonly code:
|
|
9
|
-
constructor(code:
|
|
22
|
+
readonly code: SkillCliErrorCode;
|
|
23
|
+
constructor(code: SkillCliErrorCode, message: string);
|
|
10
24
|
}
|
|
11
25
|
/** 包内 CLI 相对路径(相对技能包根,与 SKILL_CLI 尾段一致)。 */
|
|
12
26
|
export declare const SKILL_CLI_REL: "dist/cli/cmd_read.js";
|
|
13
27
|
export declare function cliPath(): string;
|
|
14
28
|
export declare function assertCliPresent(path?: string): void;
|
|
15
29
|
/** host.call 侧处理函数:由 host 注册到 connection RPC,供面板调用。 */
|
|
16
|
-
export declare function handleHostCall(key: string, params?: Record<string, unknown>): unknown
|
|
30
|
+
export declare function handleHostCall(key: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
17
31
|
/** 面板侧请求函数:只经 host.call,不直调技能实现。 */
|
|
18
32
|
export declare function requestViaHost(host: {
|
|
19
33
|
call(method: string, args: unknown): Promise<unknown>;
|
|
20
34
|
}, key: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
21
|
-
/** spawn
|
|
22
|
-
|
|
23
|
-
export
|
|
24
|
-
/** node 可执行体解析(纯函数,execPath 可注入单测)。
|
|
25
|
-
* execPath 是 node 即直用;否则(Electron 宿主)沿用该二进制但加官方 ELECTRON_RUN_AS_NODE 语义当 node 用。
|
|
26
|
-
* #696:本文件原先是 `spawnSync(process.execPath, …)` 且不传 env —— 桌面宿主里那会起一个 GUI 子进程,
|
|
27
|
-
* 配置读写与取数都拿不到回执。照卡路里/记账/大厨三家补齐。 */
|
|
28
|
-
export declare function resolveNodeBin(execPath?: string): {
|
|
29
|
-
readonly bin: string;
|
|
30
|
-
readonly extraEnv: Record<string, string>;
|
|
31
|
-
};
|
|
32
|
-
/** 同步取数:spawn 技能 cmd_read,返回 envelope data(缺失阻断)。 */
|
|
33
|
-
export declare function readViaCli(key: string, params?: Record<string, unknown>): unknown;
|
|
35
|
+
/** 异步取数:spawn 技能 cmd_read,返回 envelope data(缺失阻断)。 */
|
|
36
|
+
export declare function readViaCli(key: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
37
|
+
export { resolveNodeBin, SPAWN_TIMEOUT_MS };
|
|
34
38
|
/** 设置页的三个配置 key。
|
|
35
39
|
*
|
|
36
40
|
* **唯一定义地是技能侧** `packages/skill-home/src/cli/config.ts` 的 `CONFIG_KEYS`
|
|
37
41
|
* (那里写了「插件侧镜像同值」);本处只是镜像,值改一处要两处一起改,
|
|
38
|
-
* 对齐由 `test/config-surface
|
|
42
|
+
* 对齐由 `test/config-surface-*.test.mjs` 锁死。
|
|
39
43
|
*
|
|
40
44
|
* 为什么走 CLI 而不在插件里读盘:单品插件的冻结边界是「只读消费技能 dist/CLI,纯 CLI 单轨」
|
|
41
|
-
* (`test/plugin-p10-boundaries.test.mjs`:单品不 import `base
|
|
45
|
+
* (`test/plugin-p10-boundaries.test.mjs`:单品不 import `base-`、不 import `skill-`,
|
|
42
46
|
* 必须经 host.call 与 spawn 到 cmd_read)。配置文件的读写实现住技能的 `src/config.ts`,
|
|
43
47
|
* 插件只经这三个 key 取用——同一份实现不抄第二处。
|
|
44
48
|
*/
|
|
@@ -48,19 +52,18 @@ export declare const CONFIG_RESET_KEY: "home.config.reset";
|
|
|
48
52
|
/** #706 配置体检:只读一条,回一份报告(判据由技能侧出,本包只透传,不重写一个字)。 */
|
|
49
53
|
export declare const CONFIG_CHECK_KEY: "home.config.check";
|
|
50
54
|
/** 设置页整面:文件在哪、数据在哪、当前值、是不是这次新建的(取自技能 `home.config.read`)。 */
|
|
51
|
-
export declare function readConfigSurface(): ConfigSurfaceReply
|
|
55
|
+
export declare function readConfigSurface(): Promise<ConfigSurfaceReply>;
|
|
52
56
|
/** 保存一份配置(技能侧按键覆盖,组里没给的子项保留现值;写出去的是完整一份)。 */
|
|
53
|
-
export declare function writeConfigValues(values: Record<string, unknown>): {
|
|
57
|
+
export declare function writeConfigValues(values: Record<string, unknown>): Promise<{
|
|
54
58
|
path: string;
|
|
55
59
|
values: Record<string, unknown>;
|
|
56
|
-
}
|
|
60
|
+
}>;
|
|
57
61
|
/** 重置为默认(技能侧先另存 `<配置目录>/home.yaml.bak`)。 */
|
|
58
|
-
export declare function resetConfigToDefaults(): {
|
|
62
|
+
export declare function resetConfigToDefaults(): Promise<{
|
|
59
63
|
path: string;
|
|
60
64
|
backupPath: string | null;
|
|
61
|
-
}
|
|
65
|
+
}>;
|
|
62
66
|
/** 配置体检(#706):只读一份报告,面板侧**不校验也不重写**——形状的唯一真相在技能侧
|
|
63
|
-
* `packages/skill-home/src/health.ts
|
|
64
|
-
|
|
65
|
-
export declare function readConfigHealth(): unknown;
|
|
67
|
+
* `packages/skill-home/src/health.ts`,认形状是面板的事(`packages/plugin-manager/src/health-contract.ts`)。 */
|
|
68
|
+
export declare function readConfigHealth(): Promise<unknown>;
|
|
66
69
|
//# sourceMappingURL=bridge.d.ts.map
|
package/dist/bridge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAwB,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,eAAO,MAAM,aAAa,EAAG,YAAqB,CAAC;AACnD,eAAO,MAAM,SAAS,EAAG,0CAAmD,CAAC;AAC7E,eAAO,MAAM,gBAAgB,EAAG,iBAA0B,CAAC;AAC3D,eAAO,MAAM,eAAe,EAAG,eAAwB,CAAC;AAExD,eAAO,MAAM,oBAAoB,sJAC+B,CAAC;AAEjE,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;gBACrB,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM;CAKrD;AAED,4CAA4C;AAC5C,eAAO,MAAM,aAAa,EAAG,sBAA+B,CAAC;AAY7D,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElG;AAED,oCAAoC;AACpC,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAEnK;AAED,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE9F;AAED,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,EAAG,kBAA2B,CAAC;AAC3D,eAAO,MAAM,gBAAgB,EAAG,mBAA4B,CAAC;AAC7D,eAAO,MAAM,gBAAgB,EAAG,mBAA4B,CAAC;AAC7D,kDAAkD;AAClD,eAAO,MAAM,gBAAgB,EAAG,mBAA4B,CAAC;AAE7D,6DAA6D;AAC7D,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAE/D;AAED,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAE7H;AAED,4CAA4C;AAC5C,wBAAgB,qBAAqB,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAE5F;AAED;sGACsG;AACtG,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAEnD"}
|
package/dist/bridge.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
/** dsh-home-ilife 取数桥(P10 脚手架:纯 CLI
|
|
1
|
+
/** dsh-home-ilife 取数桥(P10 脚手架:纯 CLI 单轨)。
|
|
2
2
|
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* #696 起兼设置页的配置读写口。
|
|
4
|
+
*
|
|
5
|
+
* 本文件只剩「本家的规格 + 契约收窄」:机械动作(定位已装技能包、异步 spawn、超时杀进程、
|
|
6
|
+
* 信封校验、错误码映射)收进总管共用件 `dsh-life-pack` 根入口的 skill-cli 共用件——六家只有那一份实现。
|
|
7
|
+
* 边界不变:面板与跨技能只经 host.call 触发本桥,本桥只经 spawn 调技能包唯一出口
|
|
8
|
+
* packages/skill-home/dist/cli/cmd_read.js(argv+JSON+exit,stdout 纯 envelope JSON 一行);
|
|
5
9
|
* 本文件不 import 任何技能实现(只读消费其 dist/CLI);缺失阻断不返空:
|
|
6
10
|
* CLI 缺席/非 0/非 JSON/回执 key 不符一律抛错,绝不返回空数组冒充正常。
|
|
7
11
|
* 技能包不动(只读);combos.yaml 不动。
|
|
8
12
|
*/
|
|
9
|
-
import {
|
|
10
|
-
import { accessSync, constants } from 'node:fs';
|
|
11
|
-
import { createRequire } from 'node:module';
|
|
12
|
-
import { join, dirname } from 'node:path';
|
|
13
|
-
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { createSkillCliBridge, resolveNodeBin, SPAWN_TIMEOUT_MS } from 'dsh-life-pack';
|
|
14
14
|
export const SKILL_PACKAGE = 'skill-home';
|
|
15
15
|
export const SKILL_CLI = 'packages/skill-home/dist/cli/cmd_read.js';
|
|
16
16
|
export const HOST_CALL_METHOD = 'ilife.home.read';
|
|
@@ -24,93 +24,44 @@ export class SkillBridgeError extends Error {
|
|
|
24
24
|
this.code = code;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
function repoRoot() {
|
|
28
|
-
return join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
|
|
29
|
-
}
|
|
30
27
|
/** 包内 CLI 相对路径(相对技能包根,与 SKILL_CLI 尾段一致)。 */
|
|
31
28
|
export const SKILL_CLI_REL = 'dist/cli/cmd_read.js';
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
catch {
|
|
42
|
-
return join(repoRoot(), SKILL_CLI);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
29
|
+
/** 本家的桥:规格只此一份(出口在哪、错误类是谁)。 */
|
|
30
|
+
const bridge = createSkillCliBridge({
|
|
31
|
+
skillPackage: SKILL_PACKAGE,
|
|
32
|
+
repoRelativeCli: SKILL_CLI,
|
|
33
|
+
packageRelativeCli: SKILL_CLI_REL,
|
|
34
|
+
moduleUrl: import.meta.url,
|
|
35
|
+
hostCallMethod: HOST_CALL_METHOD,
|
|
36
|
+
makeError: (code, message) => new SkillBridgeError(code, message),
|
|
37
|
+
});
|
|
45
38
|
export function cliPath() {
|
|
46
|
-
return
|
|
39
|
+
return bridge.cliPath();
|
|
47
40
|
}
|
|
48
41
|
export function assertCliPresent(path) {
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
accessSync(p, constants.R_OK);
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
throw new SkillBridgeError('missing-cli', '技能出口缺失(先构建对应包):' + p);
|
|
55
|
-
}
|
|
42
|
+
bridge.assertCliPresent(path);
|
|
56
43
|
}
|
|
57
44
|
/** host.call 侧处理函数:由 host 注册到 connection RPC,供面板调用。 */
|
|
58
45
|
export function handleHostCall(key, params = {}) {
|
|
59
|
-
return
|
|
46
|
+
return bridge.handleHostCall(key, params);
|
|
60
47
|
}
|
|
61
48
|
/** 面板侧请求函数:只经 host.call,不直调技能实现。 */
|
|
62
49
|
export function requestViaHost(host, key, params = {}) {
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
/** spawn 超时毫秒:子进程超期未退即杀掉,转 fetch-failed,绝不无限挂起。
|
|
66
|
-
* #48 真机根因:Desktop 宿主的 process.execPath 是 Electron 二进制,直 spawn 会起 GUI 子进程永不退出。 */
|
|
67
|
-
export const SPAWN_TIMEOUT_MS = 20_000;
|
|
68
|
-
/** node 可执行体解析(纯函数,execPath 可注入单测)。
|
|
69
|
-
* execPath 是 node 即直用;否则(Electron 宿主)沿用该二进制但加官方 ELECTRON_RUN_AS_NODE 语义当 node 用。
|
|
70
|
-
* #696:本文件原先是 `spawnSync(process.execPath, …)` 且不传 env —— 桌面宿主里那会起一个 GUI 子进程,
|
|
71
|
-
* 配置读写与取数都拿不到回执。照卡路里/记账/大厨三家补齐。 */
|
|
72
|
-
export function resolveNodeBin(execPath = process.execPath) {
|
|
73
|
-
if (/(^|[\\/])node(\.exe)?$/i.test(execPath))
|
|
74
|
-
return { bin: execPath, extraEnv: {} };
|
|
75
|
-
return { bin: execPath, extraEnv: { ELECTRON_RUN_AS_NODE: '1' } };
|
|
50
|
+
return bridge.requestViaHost(host, key, params);
|
|
76
51
|
}
|
|
77
|
-
/**
|
|
52
|
+
/** 异步取数:spawn 技能 cmd_read,返回 envelope data(缺失阻断)。 */
|
|
78
53
|
export function readViaCli(key, params = {}) {
|
|
79
|
-
|
|
80
|
-
assertCliPresent(bin);
|
|
81
|
-
const { bin: node, extraEnv } = resolveNodeBin();
|
|
82
|
-
const r = spawnSync(node, [bin, key, '--params', JSON.stringify(params)], { encoding: 'utf8', timeout: SPAWN_TIMEOUT_MS, env: { ...process.env, ...extraEnv } });
|
|
83
|
-
if (r.error) {
|
|
84
|
-
if (r.error?.code === 'ETIMEDOUT') {
|
|
85
|
-
throw new SkillBridgeError('fetch-failed', '出口超 ' + String(SPAWN_TIMEOUT_MS / 1000) + 's 未退,已杀掉(宿主非 node 时见 resolveNodeBin)');
|
|
86
|
-
}
|
|
87
|
-
throw new SkillBridgeError('fetch-failed', '出口 spawn 失败:' + r.error.message);
|
|
88
|
-
}
|
|
89
|
-
if (r.status !== 0) {
|
|
90
|
-
const tail = String(r.stderr ?? '').trim().split('\n').pop() ?? '';
|
|
91
|
-
throw new SkillBridgeError('fetch-failed', '出口非 0(' + String(r.status) + '):' + tail);
|
|
92
|
-
}
|
|
93
|
-
let env;
|
|
94
|
-
try {
|
|
95
|
-
env = JSON.parse(String(r.stdout));
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
throw new SkillBridgeError('bad-json', '出口非 JSON');
|
|
99
|
-
}
|
|
100
|
-
if (!env || env.key !== key)
|
|
101
|
-
throw new SkillBridgeError('key-mismatch', '出口回执 key 不符');
|
|
102
|
-
if (env.data === null || env.data === undefined)
|
|
103
|
-
throw new SkillBridgeError('fetch-failed', '缺失阻断取数,不返空:' + key);
|
|
104
|
-
return env.data;
|
|
54
|
+
return bridge.readViaCli(key, params);
|
|
105
55
|
}
|
|
56
|
+
export { resolveNodeBin, SPAWN_TIMEOUT_MS };
|
|
106
57
|
/** 设置页的三个配置 key。
|
|
107
58
|
*
|
|
108
59
|
* **唯一定义地是技能侧** `packages/skill-home/src/cli/config.ts` 的 `CONFIG_KEYS`
|
|
109
60
|
* (那里写了「插件侧镜像同值」);本处只是镜像,值改一处要两处一起改,
|
|
110
|
-
* 对齐由 `test/config-surface
|
|
61
|
+
* 对齐由 `test/config-surface-*.test.mjs` 锁死。
|
|
111
62
|
*
|
|
112
63
|
* 为什么走 CLI 而不在插件里读盘:单品插件的冻结边界是「只读消费技能 dist/CLI,纯 CLI 单轨」
|
|
113
|
-
* (`test/plugin-p10-boundaries.test.mjs`:单品不 import `base
|
|
64
|
+
* (`test/plugin-p10-boundaries.test.mjs`:单品不 import `base-`、不 import `skill-`,
|
|
114
65
|
* 必须经 host.call 与 spawn 到 cmd_read)。配置文件的读写实现住技能的 `src/config.ts`,
|
|
115
66
|
* 插件只经这三个 key 取用——同一份实现不抄第二处。
|
|
116
67
|
*/
|
|
@@ -121,20 +72,19 @@ export const CONFIG_RESET_KEY = 'home.config.reset';
|
|
|
121
72
|
export const CONFIG_CHECK_KEY = 'home.config.check';
|
|
122
73
|
/** 设置页整面:文件在哪、数据在哪、当前值、是不是这次新建的(取自技能 `home.config.read`)。 */
|
|
123
74
|
export function readConfigSurface() {
|
|
124
|
-
return readViaCli(CONFIG_READ_KEY
|
|
75
|
+
return bridge.readViaCli(CONFIG_READ_KEY);
|
|
125
76
|
}
|
|
126
77
|
/** 保存一份配置(技能侧按键覆盖,组里没给的子项保留现值;写出去的是完整一份)。 */
|
|
127
78
|
export function writeConfigValues(values) {
|
|
128
|
-
return readViaCli(CONFIG_WRITE_KEY, { values });
|
|
79
|
+
return bridge.readViaCli(CONFIG_WRITE_KEY, { values });
|
|
129
80
|
}
|
|
130
81
|
/** 重置为默认(技能侧先另存 `<配置目录>/home.yaml.bak`)。 */
|
|
131
82
|
export function resetConfigToDefaults() {
|
|
132
|
-
return readViaCli(CONFIG_RESET_KEY
|
|
83
|
+
return bridge.readViaCli(CONFIG_RESET_KEY);
|
|
133
84
|
}
|
|
134
85
|
/** 配置体检(#706):只读一份报告,面板侧**不校验也不重写**——形状的唯一真相在技能侧
|
|
135
|
-
* `packages/skill-home/src/health.ts
|
|
136
|
-
* (`packages/plugin-manager/src/health-contract.ts`)。 */
|
|
86
|
+
* `packages/skill-home/src/health.ts`,认形状是面板的事(`packages/plugin-manager/src/health-contract.ts`)。 */
|
|
137
87
|
export function readConfigHealth() {
|
|
138
|
-
return readViaCli(CONFIG_CHECK_KEY
|
|
88
|
+
return bridge.readViaCli(CONFIG_CHECK_KEY);
|
|
139
89
|
}
|
|
140
90
|
//# sourceMappingURL=bridge.js.map
|
package/dist/bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAIvF,MAAM,CAAC,MAAM,aAAa,GAAG,YAAqB,CAAC;AACnD,MAAM,CAAC,MAAM,SAAS,GAAG,0CAAmD,CAAC;AAC7E,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAA0B,CAAC;AAC3D,MAAM,CAAC,MAAM,eAAe,GAAG,eAAwB,CAAC;AAExD,MAAM,CAAC,MAAM,oBAAoB,GAC/B,8DAA8D,CAAC;AAEjE,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAoB;IACjC,YAAY,IAAuB,EAAE,OAAe;QAClD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,4CAA4C;AAC5C,MAAM,CAAC,MAAM,aAAa,GAAG,sBAA+B,CAAC;AAE7D,+BAA+B;AAC/B,MAAM,MAAM,GAAG,oBAAoB,CAAC;IAClC,YAAY,EAAE,aAAa;IAC3B,eAAe,EAAE,SAAS;IAC1B,kBAAkB,EAAE,aAAa;IACjC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG;IAC1B,cAAc,EAAE,gBAAgB;IAChC,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC;CAClE,CAAC,CAAC;AAEH,MAAM,UAAU,OAAO;IACrB,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAa;IAC5C,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,SAAkC,EAAE;IAC9E,OAAO,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,cAAc,CAAC,IAA+D,EAAE,GAAW,EAAE,SAAkC,EAAE;IAC/I,OAAO,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,SAAkC,EAAE;IAC1E,OAAO,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,kBAA2B,CAAC;AAC3D,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAA4B,CAAC;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAA4B,CAAC;AAC7D,kDAAkD;AAClD,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAA4B,CAAC;AAE7D,6DAA6D;AAC7D,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,UAAU,CAAC,eAAe,CAAgC,CAAC;AAC3E,CAAC;AAED,6CAA6C;AAC7C,MAAM,UAAU,iBAAiB,CAAC,MAA+B;IAC/D,OAAO,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE,EAAE,MAAM,EAAE,CAA+D,CAAC;AACvH,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAyD,CAAC;AACrG,CAAC;AAED;sGACsG;AACtG,MAAM,UAAU,gBAAgB;IAC9B,OAAO,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AAC7C,CAAC"}
|
package/dist/client.js
CHANGED
|
@@ -39,8 +39,21 @@ window.__ModuleLoader__.load({
|
|
|
39
39
|
* 维护者裁定**整条删除、删后不另找地方说**——理由:三家高级项全是只读行、不参与保存、根本没有"留空",
|
|
40
40
|
* 而"留空会怎样"这条口径本就逐行住在每条的 `hint` 里(见本件 `ConfigItem.hint` 的契约)。 */
|
|
41
41
|
const ADVANCED_GROUP_TITLE = "高级";
|
|
42
|
-
/**
|
|
43
|
-
|
|
42
|
+
/** 面板读整面(config.get)的请求超时毫秒:界面永不无限转圈。
|
|
43
|
+
*
|
|
44
|
+
* 只作用于**面板首帧读整面**这一条路;宿主侧 `skill-cli/contract.ts` 的 SPAWN_TIMEOUT_MS(20s)
|
|
45
|
+
* 是 CLI spawn 进程自身的上限,两者不是同一个数、也不再「同级」——别拿这条去推断宿主侧时限。
|
|
46
|
+
*
|
|
47
|
+
* #1302:20s → 6s。机器级抖动下单次 CLI spawn 实测会到 10.3s/10.4s,20s 让一次慢例先空等 20s
|
|
48
|
+
* 才进重试;6s 落在验收带 5–8s 内(正常读回 <1s,不会误伤)。各插件包里另外那几条单次读时限
|
|
49
|
+
* (体检、版本、取数)是别的读路,按票面「本次不做」保持原值。 */
|
|
50
|
+
const READ_TIMEOUT_MS = 6e3;
|
|
51
|
+
/** 保存/重置(config.save/config.reset)的请求超时毫秒:#1302 只收**读整面**这一条路,写路保持 20s。
|
|
52
|
+
*
|
|
53
|
+
* 为什么不能跟着读一起收:写路不重试、不进预算(见上面 CONFIG_READ_RETRY_MS),而宿主侧 spawn 一个
|
|
54
|
+
* CLI 进程最多给 20s(`skill-cli/contract.ts` 的 SPAWN_TIMEOUT_MS);慢例 spawn 实测到 10.3s,
|
|
55
|
+
* 若写路也 6s,界面会先判失败而宿主可能已经写成功——把一次成功的保存说成失败。 */
|
|
56
|
+
const WRITE_TIMEOUT_MS = 2e4;
|
|
44
57
|
/** 快路径首帧有界重试表(#1142,照 #982 更新目标表同值:瞬时未就绪不再整面失败)。
|
|
45
58
|
*
|
|
46
59
|
* 有界、调用方负责卸载清理(见 `config-panel.ts` 的取数),不是无界轮询;仅读整面用,保存/重置永不自动重试。 */
|
|
@@ -207,8 +220,11 @@ window.__ModuleLoader__.load({
|
|
|
207
220
|
}, ms);
|
|
208
221
|
});
|
|
209
222
|
}
|
|
210
|
-
/** 一次配置电话(走调用方给的那条通道,靠端点名分发;永不抛,失败落字,文案自带通道与下一步)。
|
|
211
|
-
|
|
223
|
+
/** 一次配置电话(走调用方给的那条通道,靠端点名分发;永不抛,失败落字,文案自带通道与下一步)。
|
|
224
|
+
*
|
|
225
|
+
* `timeoutMs` 由调用方按读路/写路给(#1302:读整面 6s 收口,保存/重置保持 20s);
|
|
226
|
+
* 超时文案里的秒数也从它算,别在这里写死常量。 */
|
|
227
|
+
async function configRpcOnce(call, channel, method, payload, timeoutMs = READ_TIMEOUT_MS) {
|
|
212
228
|
if (typeof call !== "function") return {
|
|
213
229
|
ok: false,
|
|
214
230
|
message: `宿主连接缺席:connection.rpc.call 不可用(通道 ${channel}),稍后重试`
|
|
@@ -217,7 +233,7 @@ window.__ModuleLoader__.load({
|
|
|
217
233
|
const raw = await withDeadline(call("/api", channel.replace(/^\//, ""), {
|
|
218
234
|
method,
|
|
219
235
|
payload
|
|
220
|
-
}, AbortSignal.timeout(
|
|
236
|
+
}, AbortSignal.timeout(timeoutMs)), timeoutMs);
|
|
221
237
|
if (!isRpcResult(raw)) return {
|
|
222
238
|
ok: false,
|
|
223
239
|
message: `回执信封异常(通道 ${channel}),点重试重新读取`
|
|
@@ -233,7 +249,7 @@ window.__ModuleLoader__.load({
|
|
|
233
249
|
} catch (e) {
|
|
234
250
|
if (e instanceof Error && (e.name === "AbortError" || e.name === "TimeoutError")) return {
|
|
235
251
|
ok: false,
|
|
236
|
-
message: `配置请求超时(${Math.round(
|
|
252
|
+
message: `配置请求超时(${Math.round(timeoutMs / 1e3)}s,通道 ${channel}):宿主未回,点重试重新读取`
|
|
237
253
|
};
|
|
238
254
|
return {
|
|
239
255
|
ok: false,
|
|
@@ -246,10 +262,13 @@ window.__ModuleLoader__.load({
|
|
|
246
262
|
const delays = retry?.delays ?? [];
|
|
247
263
|
const sleepFn = retry?.sleep ?? retrySleep;
|
|
248
264
|
const alive = retry?.isAlive ?? (() => true);
|
|
265
|
+
const now = retry?.now ?? Date.now;
|
|
266
|
+
const deadline = now() + (retry?.budgetMs ?? 15e3);
|
|
249
267
|
let last = await configRpcOnce(call, channel, RPC_ENDPOINT_CONFIG_GET, {});
|
|
250
268
|
for (let i = 0; i < delays.length && !last.ok; i += 1) {
|
|
251
269
|
if (!alive()) return last;
|
|
252
270
|
const wait = delays[i] ?? 0;
|
|
271
|
+
if (now() + wait + 6e3 > deadline) break;
|
|
253
272
|
if (wait > 0) await sleepFn(wait);
|
|
254
273
|
if (!alive()) return last;
|
|
255
274
|
last = await configRpcOnce(call, channel, RPC_ENDPOINT_CONFIG_GET, {});
|
|
@@ -258,11 +277,11 @@ window.__ModuleLoader__.load({
|
|
|
258
277
|
}
|
|
259
278
|
/** 保存一份取值(回执只有 `{path, values}`,**不是**整面:写完要重新读一份整面;永不自动重试)。 */
|
|
260
279
|
function saveConfigSurface(call, channel, values) {
|
|
261
|
-
return configRpcOnce(call, channel, RPC_ENDPOINT_CONFIG_SAVE, { values });
|
|
280
|
+
return configRpcOnce(call, channel, RPC_ENDPOINT_CONFIG_SAVE, { values }, WRITE_TIMEOUT_MS);
|
|
262
281
|
}
|
|
263
282
|
/** 重置为默认(技能侧先落一份备份;回执同样不是整面,写完要重新读一份整面;永不自动重试)。 */
|
|
264
283
|
function resetConfigSurface(call, channel) {
|
|
265
|
-
return configRpcOnce(call, channel, RPC_ENDPOINT_CONFIG_RESET, {});
|
|
284
|
+
return configRpcOnce(call, channel, RPC_ENDPOINT_CONFIG_RESET, {}, WRITE_TIMEOUT_MS);
|
|
266
285
|
}
|
|
267
286
|
//#endregion
|
|
268
287
|
//#region ../plugin-manager/src/directory-browser-contract.ts
|