dsh-memo-ilife 0.2.0 → 0.2.1
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 +36 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +38 -1
- package/dist/bridge.js.map +1 -1
- package/dist/client.js +393 -29
- package/dist/client.js.map +1 -1
- package/dist/contract.d.ts +35 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +23 -0
- package/dist/contract.js.map +1 -1
- package/dist/dsh-ctx.d.ts +16 -0
- package/dist/dsh-ctx.d.ts.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -12
- package/dist/index.js.map +1 -1
- package/dist/settings.d.ts +42 -8
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +112 -7
- package/dist/settings.js.map +1 -1
- package/dist/slot.d.ts +2 -2
- package/dist/slot.js +2 -2
- package/package.json +3 -3
package/dist/bridge.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConfigSurfaceReply } from './contract.js';
|
|
1
2
|
export declare const SKILL_PACKAGE: "skill-memo-ilife";
|
|
2
3
|
export declare const SKILL_CLI: "packages/skill-memo-ilife/dist/cli/cmd_read.js";
|
|
3
4
|
export declare const HOST_CALL_METHOD: "ilife.memo.read";
|
|
@@ -28,4 +29,39 @@ export declare function resolveNodeBin(execPath?: string): {
|
|
|
28
29
|
};
|
|
29
30
|
/** 同步取数:spawn 技能 cmd_read,返回 envelope data(缺失阻断)。 */
|
|
30
31
|
export declare function readViaCli(key: string, params?: Record<string, unknown>): unknown;
|
|
32
|
+
/** 设置页的三个配置 key。
|
|
33
|
+
*
|
|
34
|
+
* **唯一定义地是技能侧** `packages/skill-memo-ilife/src/cli/config.ts` 的 `CONFIG_KEYS`
|
|
35
|
+
* (那里写了「插件侧镜像同值」);本处只是镜像,值改一处要两处一起改,
|
|
36
|
+
* 对齐由 `test/config-surface-696.test.mjs` 的源码文本锁死。
|
|
37
|
+
*
|
|
38
|
+
* 为什么走 CLI 而不在插件里读盘:单品插件的冻结边界是「只读消费技能 dist/CLI,纯 CLI 单轨」
|
|
39
|
+
* (`test/plugin-p10-boundaries.test.mjs`:单品不 import `base-*`、不 import `skill-*`,
|
|
40
|
+
* 必须经 host.call 与 spawn 到 cmd_read)。配置文件的读写实现住技能的 `src/config.ts`,
|
|
41
|
+
* 插件只经这三个 key 取用——同一份实现不抄第二处。
|
|
42
|
+
*
|
|
43
|
+
* 这三个 key **不是唤醒词命令**:技能侧 `cmd_read.ts` 在库目录预检与形状表之前就把它们拦下,
|
|
44
|
+
* 不进 HELP、也不出现在用户的命令面上。
|
|
45
|
+
*/
|
|
46
|
+
export declare const CONFIG_READ_KEY: "memo.config.read";
|
|
47
|
+
export declare const CONFIG_WRITE_KEY: "memo.config.write";
|
|
48
|
+
export declare const CONFIG_RESET_KEY: "memo.config.reset";
|
|
49
|
+
/** #706 配置体检:只读一条,回一份报告(判据由技能侧出,本包只透传,不重写一个字)。 */
|
|
50
|
+
export declare const CONFIG_CHECK_KEY: "memo.config.check";
|
|
51
|
+
/** 设置页整面:文件在哪、数据在哪、当前值、是不是这次新建的(取自技能 `memo.config.read`)。 */
|
|
52
|
+
export declare function readConfigSurface(): ConfigSurfaceReply;
|
|
53
|
+
/** 保存一份配置(技能侧按键覆盖,组里没给的子项保留现值;写出去的是完整一份)。 */
|
|
54
|
+
export declare function writeConfigValues(values: Record<string, unknown>): {
|
|
55
|
+
path: string;
|
|
56
|
+
values: Record<string, unknown>;
|
|
57
|
+
};
|
|
58
|
+
/** 重置为默认(技能侧先另存 `<配置目录>/memo.yaml.bak`)。 */
|
|
59
|
+
export declare function resetConfigToDefaults(): {
|
|
60
|
+
path: string;
|
|
61
|
+
backupPath: string | null;
|
|
62
|
+
};
|
|
63
|
+
/** 配置体检(#706):只读一份报告,面板侧**不校验也不重写**——形状的唯一真相在技能侧
|
|
64
|
+
* `packages/skill-memo/src/health.ts`,认形状是面板的事
|
|
65
|
+
* (`packages/plugin-manager/src/health-contract.ts`)。 */
|
|
66
|
+
export declare function readConfigHealth(): unknown;
|
|
31
67
|
//# 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,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,eAAO,MAAM,aAAa,EAAG,kBAA2B,CAAC;AACzD,eAAO,MAAM,SAAS,EAAG,gDAAyD,CAAC;AACnF,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,aAAa,GAAG,cAAc,GAAG,UAAU,GAAG,cAAc,CAAC;gBAChE,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM;CAK5D;AAMD,4CAA4C;AAC5C,eAAO,MAAM,aAAa,EAAG,sBAA+B,CAAC;AAe7D,wBAAgB,OAAO,IAAI,MAAM,CAEhC;AAED,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAOpD;AAED,uDAAuD;AACvD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAEzF;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;kFACkF;AAClF,eAAO,MAAM,gBAAgB,EAAG,KAAe,CAAC;AAEhD;oFACoF;AACpF,wBAAgB,cAAc,CAAC,QAAQ,GAAE,MAAyB,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAGvI;AAED,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,OAAO,CAwBrF;AAED;;;;;;;;;;;;;GAaG;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,kBAAkB,CAEtD;AAED,6CAA6C;AAC7C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAEpH;AAED,4CAA4C;AAC5C,wBAAgB,qBAAqB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAEnF;AAED;;0DAE0D;AAC1D,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
|
package/dist/bridge.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** dsh-memo-ilife 取数桥(P10 脚手架:纯 CLI
|
|
1
|
+
/** dsh-memo-ilife 取数桥(P10 脚手架:纯 CLI 单轨;#696 起兼设置页的配置读写口)。
|
|
2
2
|
*
|
|
3
3
|
* 面板与跨技能只经 host.call 触发本桥,本桥只经 spawn 调技能包唯一出口
|
|
4
4
|
* packages/skill-memo-ilife/dist/cli/cmd_read.js(argv+JSON+exit,stdout 纯 envelope JSON 一行)。
|
|
@@ -101,4 +101,41 @@ export function readViaCli(key, params = {}) {
|
|
|
101
101
|
throw new SkillBridgeError('fetch-failed', '缺失阻断取数,不返空:' + key);
|
|
102
102
|
return env.data;
|
|
103
103
|
}
|
|
104
|
+
/** 设置页的三个配置 key。
|
|
105
|
+
*
|
|
106
|
+
* **唯一定义地是技能侧** `packages/skill-memo-ilife/src/cli/config.ts` 的 `CONFIG_KEYS`
|
|
107
|
+
* (那里写了「插件侧镜像同值」);本处只是镜像,值改一处要两处一起改,
|
|
108
|
+
* 对齐由 `test/config-surface-696.test.mjs` 的源码文本锁死。
|
|
109
|
+
*
|
|
110
|
+
* 为什么走 CLI 而不在插件里读盘:单品插件的冻结边界是「只读消费技能 dist/CLI,纯 CLI 单轨」
|
|
111
|
+
* (`test/plugin-p10-boundaries.test.mjs`:单品不 import `base-*`、不 import `skill-*`,
|
|
112
|
+
* 必须经 host.call 与 spawn 到 cmd_read)。配置文件的读写实现住技能的 `src/config.ts`,
|
|
113
|
+
* 插件只经这三个 key 取用——同一份实现不抄第二处。
|
|
114
|
+
*
|
|
115
|
+
* 这三个 key **不是唤醒词命令**:技能侧 `cmd_read.ts` 在库目录预检与形状表之前就把它们拦下,
|
|
116
|
+
* 不进 HELP、也不出现在用户的命令面上。
|
|
117
|
+
*/
|
|
118
|
+
export const CONFIG_READ_KEY = 'memo.config.read';
|
|
119
|
+
export const CONFIG_WRITE_KEY = 'memo.config.write';
|
|
120
|
+
export const CONFIG_RESET_KEY = 'memo.config.reset';
|
|
121
|
+
/** #706 配置体检:只读一条,回一份报告(判据由技能侧出,本包只透传,不重写一个字)。 */
|
|
122
|
+
export const CONFIG_CHECK_KEY = 'memo.config.check';
|
|
123
|
+
/** 设置页整面:文件在哪、数据在哪、当前值、是不是这次新建的(取自技能 `memo.config.read`)。 */
|
|
124
|
+
export function readConfigSurface() {
|
|
125
|
+
return readViaCli(CONFIG_READ_KEY, {});
|
|
126
|
+
}
|
|
127
|
+
/** 保存一份配置(技能侧按键覆盖,组里没给的子项保留现值;写出去的是完整一份)。 */
|
|
128
|
+
export function writeConfigValues(values) {
|
|
129
|
+
return readViaCli(CONFIG_WRITE_KEY, { values });
|
|
130
|
+
}
|
|
131
|
+
/** 重置为默认(技能侧先另存 `<配置目录>/memo.yaml.bak`)。 */
|
|
132
|
+
export function resetConfigToDefaults() {
|
|
133
|
+
return readViaCli(CONFIG_RESET_KEY, {});
|
|
134
|
+
}
|
|
135
|
+
/** 配置体检(#706):只读一份报告,面板侧**不校验也不重写**——形状的唯一真相在技能侧
|
|
136
|
+
* `packages/skill-memo/src/health.ts`,认形状是面板的事
|
|
137
|
+
* (`packages/plugin-manager/src/health-contract.ts`)。 */
|
|
138
|
+
export function readConfigHealth() {
|
|
139
|
+
return readViaCli(CONFIG_CHECK_KEY, {});
|
|
140
|
+
}
|
|
104
141
|
//# 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;;;;;;;GAOG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -34,9 +34,18 @@ window.__ModuleLoader__.load({
|
|
|
34
34
|
* browser 安全:零 node 导入。host 适配器(注册 RPC 通道)与 client
|
|
35
35
|
* 适配器(调用 RPC)共用同一份定义;单测与 loader 回路以此为准。
|
|
36
36
|
* 通道命名遵守宿主约束:单段且不等于 /api(见 cookbook「RPC 通道」)。
|
|
37
|
+
*
|
|
38
|
+
* #696:本包**已有**这条通道(取数端点 `read` 与 `/api/ilife-memo` 路由早在板上),设置页要读改配置,
|
|
39
|
+
* 于是只在既有通道上加三个配置端点(`config.get`/`config.save`/`config.reset`);取数那条一行未动。
|
|
37
40
|
*/
|
|
38
41
|
const RPC_CHANNEL = "/ilife-memo";
|
|
39
42
|
const RPC_ENDPOINT_READ = "read";
|
|
43
|
+
/** #696 配置端点:读设置页整面、保存一份取值、重置为默认。同走既有那条通道,靠端点名分发。
|
|
44
|
+
*
|
|
45
|
+
* 与既有的取数端点 `read` 同住 `/ilife-memo`:本包**不另起第二条通道**,只在既有通道上加面。 */
|
|
46
|
+
const RPC_ENDPOINT_CONFIG_GET = "config.get";
|
|
47
|
+
const RPC_ENDPOINT_CONFIG_SAVE = "config.save";
|
|
48
|
+
const RPC_ENDPOINT_CONFIG_RESET = "config.reset";
|
|
40
49
|
/** 面板默认读键:memo.search 无参直读,空库安全(items []、total 0)。 */
|
|
41
50
|
const DEFAULT_READ_KEY = "memo.search";
|
|
42
51
|
/** 信封守卫:供 client 拆包前校验(port 拥有信封定义,守卫住 port)。 */
|
|
@@ -52,16 +61,101 @@ window.__ModuleLoader__.load({
|
|
|
52
61
|
const SKILL_PACKAGE = "skill-memo-ilife";
|
|
53
62
|
/** 版本行唯一来源(面板展示用;smoke 断言与两处 package.json 一致,防漂移)。
|
|
54
63
|
* 发版 bump 时同步改这里(与 package.json 同值)。 */
|
|
55
|
-
const PLUGIN_VERSION = "0.2.
|
|
56
|
-
const SKILL_VERSION = "0.2.
|
|
64
|
+
const PLUGIN_VERSION = "0.2.1";
|
|
65
|
+
const SKILL_VERSION = "0.2.1";
|
|
57
66
|
//#endregion
|
|
58
67
|
//#region src/settings.ts
|
|
59
|
-
/**
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
/** 常用项:改了就影响「库与产物落在哪」,放页面上。 */
|
|
69
|
+
const COMMON = [
|
|
70
|
+
{
|
|
71
|
+
key: "db.dir",
|
|
72
|
+
title: "数据目录",
|
|
73
|
+
tier: "common",
|
|
74
|
+
control: "text",
|
|
75
|
+
hint: "库文件与产物的根目录。留空=按默认落点(配置目录下的 data/),也就是改造前那个位置。"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: "db.name",
|
|
79
|
+
title: "库文件名",
|
|
80
|
+
tier: "common",
|
|
81
|
+
control: "text",
|
|
82
|
+
hint: "数据目录下的数据库文件名。留空=按默认落点(memo.db);改它等于换一个备忘录库,老笔记留在旧文件里不会跟过来。"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
key: "html.dir",
|
|
86
|
+
title: "HTML 产物目录名",
|
|
87
|
+
tier: "common",
|
|
88
|
+
control: "text",
|
|
89
|
+
hint: "数据目录下放 HELP 页面的子目录名,只有一段。留空=按默认落点(memo_html);改它之后新产物落新地方,旧的留在原处。"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
key: "media.dir",
|
|
93
|
+
title: "附件目录",
|
|
94
|
+
tier: "common",
|
|
95
|
+
control: "text",
|
|
96
|
+
hint: "附件的根目录:技能会把它解析成绝对路径并要求目录真的在(附件路径按真包含判定)。留空=按默认落点(相对进程工作目录的 media)。"
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
/** 高级项:默认收起。改错了多半只是自己撞上麻烦,不确定就别动。 */
|
|
100
|
+
const ADVANCED = [
|
|
101
|
+
{
|
|
102
|
+
key: "files.help",
|
|
103
|
+
title: "产物文件名主体 · HELP",
|
|
104
|
+
tier: "advanced",
|
|
105
|
+
control: "text",
|
|
106
|
+
hint: "HELP 文件的文件名主体,后面自动跟时间戳。改它之后旧的 HELP 产物不再被复用。"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
key: "files.lookup",
|
|
110
|
+
title: "产物文件名主体 · 速查表",
|
|
111
|
+
tier: "advanced",
|
|
112
|
+
control: "text",
|
|
113
|
+
hint: "速查表文件的文件名主体。改它之后新产物落新名字,旧的留在原处。"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
key: "lark.cliPath",
|
|
117
|
+
title: "飞书 CLI 路径",
|
|
118
|
+
tier: "advanced",
|
|
119
|
+
control: "text",
|
|
120
|
+
hint: "飞书 CLI 的可执行文件路径。留空=按默认落点(自动探测:Windows npm 全局目录 → PATH 里的 where/which → 固定安装位置)。"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
key: "lark.qrDir",
|
|
124
|
+
title: "飞书授权二维码落点",
|
|
125
|
+
tier: "advanced",
|
|
126
|
+
control: "text",
|
|
127
|
+
hint: "飞书授权二维码 PNG 的落点目录,缺就现建。留空=按默认落点(系统临时目录下的 memo_feishu_qr)。"
|
|
128
|
+
}
|
|
129
|
+
];
|
|
130
|
+
/** 设置页的行表,顺序即页面顺序。 */
|
|
131
|
+
const CONFIG_ITEMS = [...COMMON, ...ADVANCED];
|
|
132
|
+
/** 常用项行数(页面上直接画出来的那些)。 */
|
|
133
|
+
const COMMON_ITEM_COUNT = COMMON.length;
|
|
134
|
+
/** 高级组标题与副文案。 */
|
|
135
|
+
const ADVANCED_GROUP_TITLE = "高级";
|
|
136
|
+
const ADVANCED_GROUP_NOTE = "不常改。留空=按默认落点(改造前那个位置),不确定就别动。";
|
|
137
|
+
/** 按 `a.b` 路径从配置取值里读(缺层或类型不符一律回 undefined)。 */
|
|
138
|
+
function readPath(values, key) {
|
|
139
|
+
const parts = key.split(".");
|
|
140
|
+
let cur = values;
|
|
141
|
+
for (const part of parts) {
|
|
142
|
+
if (typeof cur !== "object" || cur === null || Array.isArray(cur)) return void 0;
|
|
143
|
+
cur = cur[part];
|
|
144
|
+
}
|
|
145
|
+
return cur;
|
|
146
|
+
}
|
|
147
|
+
/** 按 `a.b` 路径把值写进配置取值(中间层缺就建一层空组;已存在非组即覆盖成组)。 */
|
|
148
|
+
function writePath(values, key, value) {
|
|
149
|
+
const parts = key.split(".");
|
|
150
|
+
let cur = values;
|
|
151
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
152
|
+
const part = parts[i];
|
|
153
|
+
const next = cur[part];
|
|
154
|
+
if (typeof next !== "object" || next === null || Array.isArray(next)) cur[part] = {};
|
|
155
|
+
cur = cur[part];
|
|
156
|
+
}
|
|
157
|
+
cur[parts[parts.length - 1]] = value;
|
|
158
|
+
}
|
|
65
159
|
//#endregion
|
|
66
160
|
//#region src/client.ts
|
|
67
161
|
/** dsh-memo-ilife client 适配器(六边形:port=contract+dsh-ctx 镜像,adapter=本文件)。
|
|
@@ -70,6 +164,9 @@ window.__ModuleLoader__.load({
|
|
|
70
164
|
* 本文件传递闭包:禁 node、禁 DOM 直写(document/window/process)。
|
|
71
165
|
* 注册两处(grill 定案,新术语见 CONTEXT.md):
|
|
72
166
|
* (a) 技能设置页 → 爱生活页签槽(总管声明的 children,各技能自研自家配置页);
|
|
167
|
+
* #696 起这一页从「只读设置行」换成**真配置页**:行表来自 settings.ts,取值与保存经宿主三个端点
|
|
168
|
+
* (`config.get`/`config.save`/`config.reset`),宿主再 spawn 技能 CLI 的 `memo.config.*` 三个 key。
|
|
169
|
+
* 本页只配置、不干活:没有查数、记一条之类的入口(那些在 (b) 的功能页)。
|
|
73
170
|
* (b) 技能功能页 → sidebar槽(better-sidebar 服务,非 DSH slot;软依赖,
|
|
74
171
|
* 缺席即跳过,不断链。DSH右侧槽 + sidebar.footer.action 彻底出局,已删)。
|
|
75
172
|
* 有界重试例外依据(唯一允许的定时器):注册重试非数据轮询,照抄
|
|
@@ -107,13 +204,79 @@ window.__ModuleLoader__.load({
|
|
|
107
204
|
},
|
|
108
205
|
error: {
|
|
109
206
|
color: "var(--dsw-alias-state-error-primary, #ff6b6b)",
|
|
110
|
-
fontSize: 13
|
|
207
|
+
fontSize: 13,
|
|
208
|
+
whiteSpace: "pre-wrap"
|
|
209
|
+
},
|
|
210
|
+
okText: {
|
|
211
|
+
color: "var(--dsw-alias-state-success-primary, #12805c)",
|
|
212
|
+
fontSize: 12.5
|
|
111
213
|
},
|
|
112
214
|
rows: {
|
|
113
215
|
marginTop: 8,
|
|
114
216
|
borderTop: "1px solid var(--dsw-alias-border, rgba(128,128,128,.25))",
|
|
115
217
|
paddingTop: 8
|
|
116
218
|
},
|
|
219
|
+
row: { marginTop: 10 },
|
|
220
|
+
label: {
|
|
221
|
+
fontSize: 12.5,
|
|
222
|
+
fontWeight: 600
|
|
223
|
+
},
|
|
224
|
+
hint: {
|
|
225
|
+
color: "var(--dsw-alias-label-tertiary, #8a8a8a)",
|
|
226
|
+
fontSize: 11.5,
|
|
227
|
+
margin: "1px 0 4px"
|
|
228
|
+
},
|
|
229
|
+
input: {
|
|
230
|
+
width: "100%",
|
|
231
|
+
boxSizing: "border-box",
|
|
232
|
+
padding: "4px 8px",
|
|
233
|
+
borderRadius: 6,
|
|
234
|
+
border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.45))",
|
|
235
|
+
background: "var(--dsw-alias-bg-base, transparent)",
|
|
236
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
237
|
+
font: "12.5px/1.5 ui-monospace,Consolas,monospace"
|
|
238
|
+
},
|
|
239
|
+
info: {
|
|
240
|
+
margin: "6px 0 0",
|
|
241
|
+
font: "12px/1.5 ui-monospace,Consolas,monospace",
|
|
242
|
+
color: "var(--dsw-alias-label-secondary, #9a9a9a)",
|
|
243
|
+
wordBreak: "break-all"
|
|
244
|
+
},
|
|
245
|
+
bar: {
|
|
246
|
+
marginTop: 14,
|
|
247
|
+
display: "flex",
|
|
248
|
+
gap: 8,
|
|
249
|
+
alignItems: "center",
|
|
250
|
+
flexWrap: "wrap"
|
|
251
|
+
},
|
|
252
|
+
btn: {
|
|
253
|
+
padding: "5px 14px",
|
|
254
|
+
borderRadius: 7,
|
|
255
|
+
border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.45))",
|
|
256
|
+
background: "var(--dsw-alias-bg-base, transparent)",
|
|
257
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
258
|
+
fontSize: 12.5,
|
|
259
|
+
cursor: "pointer"
|
|
260
|
+
},
|
|
261
|
+
btnPrimary: {
|
|
262
|
+
padding: "5px 14px",
|
|
263
|
+
borderRadius: 7,
|
|
264
|
+
border: "1px solid var(--dsw-alias-brand-primary, #2f6fed)",
|
|
265
|
+
background: "var(--dsw-alias-brand-primary, #2f6fed)",
|
|
266
|
+
color: "#fff",
|
|
267
|
+
fontSize: 12.5,
|
|
268
|
+
cursor: "pointer"
|
|
269
|
+
},
|
|
270
|
+
adv: {
|
|
271
|
+
marginTop: 12,
|
|
272
|
+
paddingTop: 8,
|
|
273
|
+
borderTop: "1px solid var(--dsw-alias-border, rgba(128,128,128,.25))"
|
|
274
|
+
},
|
|
275
|
+
advSummary: {
|
|
276
|
+
cursor: "pointer",
|
|
277
|
+
fontSize: 12.5,
|
|
278
|
+
fontWeight: 600
|
|
279
|
+
},
|
|
117
280
|
version: {
|
|
118
281
|
marginTop: 8,
|
|
119
282
|
paddingTop: 8,
|
|
@@ -247,39 +410,233 @@ window.__ModuleLoader__.load({
|
|
|
247
410
|
if (state.kind === "data") return react.createElement("div", { style: S.card }, react.createElement("div", { style: S.title }, SLOT_TITLE), react.createElement("div", { style: S.total }, `total ${state.total}`), react.createElement(VersionLine, null));
|
|
248
411
|
return react.createElement("div", { style: S.card }, react.createElement("div", { style: state.kind === "absent" ? S.muted : S.error }, state.message), react.createElement(VersionLine, null));
|
|
249
412
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
413
|
+
/** 配置面报错 → 人话指引。
|
|
414
|
+
*
|
|
415
|
+
* 报文由技能侧给出:base-link-core 的 `ConfigError` 已带行号与文件名,技能 `cli/config.ts` 原样交出来,
|
|
416
|
+
* 插件 bridge 原样带上(`fetch-failed:出口非 0(1):<那一句>`)。所以这里**不重写报文**,
|
|
417
|
+
* 只按报错类补一句「接下来怎么办」——免得两处各写一套人话。
|
|
418
|
+
*/
|
|
419
|
+
function humanizeConfigFailure(code, message) {
|
|
420
|
+
const text = message.trim().length > 0 ? message.trim() : `(${code},宿主未给报文)`;
|
|
421
|
+
if (/解析|YAML|parse/i.test(text)) return `${text}\n改回「键: 值」的写法,或点「重置为默认」重来一份(重置会先留一份 .bak)。`;
|
|
422
|
+
if (/不认识|未知键|UNKNOWN_KEY/i.test(text)) return `${text}\n本页只认表里这些项;多余的行删掉,或点「重置为默认」。`;
|
|
423
|
+
if (/类型|TYPE_MISMATCH/i.test(text)) return `${text}\n按本页给的形状填(文本填文本),或点「重置为默认」。`;
|
|
424
|
+
if (/缺席|missing-cli/i.test(text)) return `${text}\n技能出口没找着:先确认技能包已构建(packages/skill-memo-ilife/dist/cli/cmd_read.js)。`;
|
|
425
|
+
return `${text}\n改不动就点「重置为默认」(会先留一份 .bak),或照报文里的路径手工改配置文件。`;
|
|
426
|
+
}
|
|
427
|
+
/** 一次配置 RPC(同通道过三个端点;永不抛,失败落字)。 */
|
|
428
|
+
async function configRpc(call, method, payload) {
|
|
429
|
+
if (typeof call !== "function") return {
|
|
430
|
+
ok: false,
|
|
431
|
+
message: "宿主连接缺席:connection.rpc.call 不可用"
|
|
432
|
+
};
|
|
433
|
+
let raw;
|
|
434
|
+
try {
|
|
435
|
+
raw = await withTimeout(call("/api", RPC_CHANNEL.slice(1), {
|
|
436
|
+
method,
|
|
437
|
+
payload
|
|
438
|
+
}, AbortSignal.timeout(READ_TIMEOUT_MS)), READ_TIMEOUT_MS);
|
|
439
|
+
} catch (e) {
|
|
440
|
+
if (e instanceof Error && (e.name === "AbortError" || e.name === "TimeoutError")) return {
|
|
441
|
+
ok: false,
|
|
442
|
+
message: `配置请求超时(${Math.round(READ_TIMEOUT_MS / 1e3)}s):宿主未回`
|
|
443
|
+
};
|
|
444
|
+
return {
|
|
445
|
+
ok: false,
|
|
446
|
+
message: `配置失败:${e instanceof Error ? e.message : String(e)}`
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
if (!isRpcResult(raw)) return {
|
|
450
|
+
ok: false,
|
|
451
|
+
message: "回执信封异常(非 ok 信封)"
|
|
452
|
+
};
|
|
453
|
+
const res = raw;
|
|
454
|
+
if (!res.ok) return {
|
|
455
|
+
ok: false,
|
|
456
|
+
message: humanizeConfigFailure(res.error?.code ?? "unknown", res.error?.message ?? "")
|
|
457
|
+
};
|
|
458
|
+
return {
|
|
459
|
+
ok: true,
|
|
460
|
+
surface: res.value
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
/** 读设置页整面。 */
|
|
464
|
+
function fetchConfigSurface(call) {
|
|
465
|
+
return configRpc(call, RPC_ENDPOINT_CONFIG_GET, {});
|
|
466
|
+
}
|
|
467
|
+
/** 保存一份取值(写回执只有 {path, values},头部那两行要的是读整面,故由组件写后重读)。 */
|
|
468
|
+
function saveConfigSurface(call, values) {
|
|
469
|
+
return configRpc(call, RPC_ENDPOINT_CONFIG_SAVE, { values });
|
|
470
|
+
}
|
|
471
|
+
/** 重置为默认(技能侧先落 .bak;同样由组件重读一份整面)。 */
|
|
472
|
+
function resetConfigSurface(call) {
|
|
473
|
+
return configRpc(call, RPC_ENDPOINT_CONFIG_RESET, {});
|
|
474
|
+
}
|
|
475
|
+
/** 把配置取值铺成「行键 → 输入框文本」(页面表单态;值缺项即空串,不返空留白)。 */
|
|
476
|
+
function toDraft(values) {
|
|
477
|
+
const draft = {};
|
|
478
|
+
for (const item of CONFIG_ITEMS) {
|
|
479
|
+
const v = readPath(values, item.key);
|
|
480
|
+
draft[item.key] = v === void 0 || v === null ? "" : String(v);
|
|
481
|
+
}
|
|
482
|
+
return draft;
|
|
483
|
+
}
|
|
484
|
+
/** 表单态 → 配置取值(按控件种类还原类型;空串对文本项照收,语义由「按默认落点」承担)。 */
|
|
485
|
+
function fromDraft(draft) {
|
|
486
|
+
const values = {};
|
|
487
|
+
for (const item of CONFIG_ITEMS) {
|
|
488
|
+
const raw = draft[item.key] ?? "";
|
|
489
|
+
if (item.control === "number") {
|
|
490
|
+
const n = Number(raw);
|
|
491
|
+
writePath(values, item.key, Number.isFinite(n) ? n : 0);
|
|
492
|
+
} else if (item.control === "switch") writePath(values, item.key, raw === "true");
|
|
493
|
+
else writePath(values, item.key, raw);
|
|
494
|
+
}
|
|
495
|
+
return values;
|
|
255
496
|
}
|
|
256
|
-
/**
|
|
497
|
+
/** 一行输入(三种控件对齐受限 YAML 子集:文本/数字/布尔;本包 8 行都是文本)。 */
|
|
498
|
+
function Row(props) {
|
|
499
|
+
const { item } = props;
|
|
500
|
+
const control = item.control === "switch" ? react.createElement("input", {
|
|
501
|
+
type: "checkbox",
|
|
502
|
+
checked: props.value === "true",
|
|
503
|
+
disabled: props.disabled,
|
|
504
|
+
onChange: (e) => props.onChange(item.key, e.target.checked ? "true" : "false")
|
|
505
|
+
}) : react.createElement("input", {
|
|
506
|
+
style: S.input,
|
|
507
|
+
type: item.control === "number" ? "number" : "text",
|
|
508
|
+
value: props.value,
|
|
509
|
+
disabled: props.disabled,
|
|
510
|
+
spellCheck: false,
|
|
511
|
+
onChange: (e) => props.onChange(item.key, e.target.value)
|
|
512
|
+
});
|
|
513
|
+
return react.createElement("div", { style: S.row }, react.createElement("div", { style: S.label }, item.title), react.createElement("div", { style: S.hint }, item.hint), control);
|
|
514
|
+
}
|
|
515
|
+
/** 技能设置页:承载备忘录自己的全部可配置项(只配置,不干活)。
|
|
516
|
+
*
|
|
517
|
+
* 三态:loading(一次 RPC 内)/ready(真表单)/failed(人话报错 + 指引,不返空、不转圈)。
|
|
518
|
+
* 保存与重置之后都**重新读一份整面**再提示(写回执不带 dataDir/created,头部那两行要的是读整面)。 */
|
|
257
519
|
function MemoConfig(props) {
|
|
258
520
|
const [state, setState] = react.useState({ kind: "loading" });
|
|
521
|
+
const [draft, setDraft] = react.useState({});
|
|
522
|
+
const [busy, setBusy] = react.useState(false);
|
|
523
|
+
const [notice, setNotice] = react.useState(null);
|
|
524
|
+
const [error, setError] = react.useState(null);
|
|
525
|
+
const apply = react.useCallback((surface) => {
|
|
526
|
+
setState({
|
|
527
|
+
kind: "ready",
|
|
528
|
+
surface
|
|
529
|
+
});
|
|
530
|
+
setDraft(toDraft(surface.values));
|
|
531
|
+
}, []);
|
|
532
|
+
const load = react.useCallback(async () => {
|
|
533
|
+
setNotice(null);
|
|
534
|
+
setError(null);
|
|
535
|
+
const r = await fetchConfigSurface(props.getCall());
|
|
536
|
+
if (r.ok) apply(r.surface);
|
|
537
|
+
else setState({
|
|
538
|
+
kind: "failed",
|
|
539
|
+
message: r.message
|
|
540
|
+
});
|
|
541
|
+
}, [apply, props.getCall]);
|
|
259
542
|
react.useEffect(() => {
|
|
260
543
|
let alive = true;
|
|
261
544
|
(async () => {
|
|
262
|
-
const r = await
|
|
545
|
+
const r = await fetchConfigSurface(props.getCall());
|
|
263
546
|
if (!alive) return;
|
|
264
|
-
if (r.ok)
|
|
265
|
-
kind: "data",
|
|
266
|
-
total: r.text
|
|
267
|
-
});
|
|
268
|
-
else if (r.absent) setState({
|
|
269
|
-
kind: "absent",
|
|
270
|
-
message: r.message
|
|
271
|
-
});
|
|
547
|
+
if (r.ok) apply(r.surface);
|
|
272
548
|
else setState({
|
|
273
|
-
kind: "
|
|
549
|
+
kind: "failed",
|
|
274
550
|
message: r.message
|
|
275
551
|
});
|
|
276
552
|
})();
|
|
277
553
|
return () => {
|
|
278
554
|
alive = false;
|
|
279
555
|
};
|
|
280
|
-
}, [props.getCall]);
|
|
281
|
-
const
|
|
282
|
-
|
|
556
|
+
}, [apply, props.getCall]);
|
|
557
|
+
const onChange = react.useCallback((key, next) => {
|
|
558
|
+
setDraft((prev) => ({
|
|
559
|
+
...prev,
|
|
560
|
+
[key]: next
|
|
561
|
+
}));
|
|
562
|
+
setNotice(null);
|
|
563
|
+
setError(null);
|
|
564
|
+
}, []);
|
|
565
|
+
const surface = state.kind === "ready" ? state.surface : null;
|
|
566
|
+
const dirty = surface !== null && CONFIG_ITEMS.some((i) => (draft[i.key] ?? "") !== (toDraft(surface.values)[i.key] ?? ""));
|
|
567
|
+
/** 写完(保存/重置)之后重新读一份整面,读到了才敢提示「已完成」。 */
|
|
568
|
+
const writeThenReload = react.useCallback(async (done) => {
|
|
569
|
+
setBusy(true);
|
|
570
|
+
setNotice(null);
|
|
571
|
+
setError(null);
|
|
572
|
+
const r = await fetchConfigSurface(props.getCall());
|
|
573
|
+
if (r.ok) {
|
|
574
|
+
apply(r.surface);
|
|
575
|
+
setNotice(done);
|
|
576
|
+
} else setState({
|
|
577
|
+
kind: "failed",
|
|
578
|
+
message: r.message
|
|
579
|
+
});
|
|
580
|
+
setBusy(false);
|
|
581
|
+
}, [apply, props.getCall]);
|
|
582
|
+
const onSave = react.useCallback(async () => {
|
|
583
|
+
setBusy(true);
|
|
584
|
+
setNotice(null);
|
|
585
|
+
setError(null);
|
|
586
|
+
const r = await saveConfigSurface(props.getCall(), fromDraft(draft));
|
|
587
|
+
setBusy(false);
|
|
588
|
+
if (r.ok) await writeThenReload("已保存,立即生效(不用重启宿主)");
|
|
589
|
+
else setError(r.message);
|
|
590
|
+
}, [
|
|
591
|
+
draft,
|
|
592
|
+
props.getCall,
|
|
593
|
+
writeThenReload
|
|
594
|
+
]);
|
|
595
|
+
const onReset = react.useCallback(async () => {
|
|
596
|
+
setBusy(true);
|
|
597
|
+
setNotice(null);
|
|
598
|
+
setError(null);
|
|
599
|
+
const r = await resetConfigSurface(props.getCall());
|
|
600
|
+
setBusy(false);
|
|
601
|
+
if (r.ok) await writeThenReload("已重置为默认(原配置已另存一份 .bak)");
|
|
602
|
+
else setError(r.message);
|
|
603
|
+
}, [props.getCall, writeThenReload]);
|
|
604
|
+
const head = react.createElement("div", null, react.createElement("div", { style: S.title }, `${SLOT_TITLE} · 配置`), surface !== null ? react.createElement("div", null, react.createElement("div", { style: S.info }, `配置文件 ${surface.path}`), react.createElement("div", { style: S.info }, `数据目录 ${surface.dataDir}`), surface.created ? react.createElement("div", { style: S.muted }, "(这份配置是刚按默认值建出来的)") : null) : null);
|
|
605
|
+
if (state.kind === "loading") return react.createElement("div", { style: S.card }, head, react.createElement("div", { style: S.muted }, "配置读取中…"), react.createElement(VersionLine, null));
|
|
606
|
+
if (state.kind === "failed") return react.createElement("div", { style: S.card }, react.createElement("div", { style: S.title }, `${SLOT_TITLE} · 配置`), react.createElement("div", { style: S.error }, state.message), react.createElement("div", { style: S.bar }, react.createElement("button", {
|
|
607
|
+
style: S.btn,
|
|
608
|
+
type: "button",
|
|
609
|
+
onClick: () => void load()
|
|
610
|
+
}, "重试"), react.createElement("button", {
|
|
611
|
+
style: S.btn,
|
|
612
|
+
type: "button",
|
|
613
|
+
onClick: () => void onReset()
|
|
614
|
+
}, "重置为默认")), react.createElement(VersionLine, null));
|
|
615
|
+
const common = CONFIG_ITEMS.slice(0, COMMON_ITEM_COUNT);
|
|
616
|
+
const advanced = CONFIG_ITEMS.slice(COMMON_ITEM_COUNT);
|
|
617
|
+
const renderRow = (item) => react.createElement(Row, {
|
|
618
|
+
key: item.key,
|
|
619
|
+
item,
|
|
620
|
+
value: draft[item.key] ?? "",
|
|
621
|
+
disabled: busy,
|
|
622
|
+
onChange
|
|
623
|
+
});
|
|
624
|
+
return react.createElement("div", { style: S.card }, head, react.createElement("div", { style: S.rows }, common.map(renderRow)), react.createElement("details", { style: S.adv }, react.createElement("summary", { style: S.advSummary }, ADVANCED_GROUP_TITLE), react.createElement("div", { style: S.muted }, ADVANCED_GROUP_NOTE), advanced.map(renderRow)), react.createElement("div", { style: S.bar }, react.createElement("button", {
|
|
625
|
+
style: dirty ? S.btnPrimary : S.btn,
|
|
626
|
+
type: "button",
|
|
627
|
+
disabled: busy || !dirty,
|
|
628
|
+
onClick: () => void onSave()
|
|
629
|
+
}, busy ? "处理中…" : "保存"), react.createElement("button", {
|
|
630
|
+
style: S.btn,
|
|
631
|
+
type: "button",
|
|
632
|
+
disabled: busy,
|
|
633
|
+
onClick: () => void onReset()
|
|
634
|
+
}, "重置为默认"), react.createElement("button", {
|
|
635
|
+
style: S.btn,
|
|
636
|
+
type: "button",
|
|
637
|
+
disabled: busy,
|
|
638
|
+
onClick: () => void load()
|
|
639
|
+
}, "重新读取")), notice !== null ? react.createElement("div", { style: S.okText }, notice) : null, error !== null ? react.createElement("div", { style: S.error }, error) : null, react.createElement("div", { style: S.muted }, `${PLUGIN} 设置页住单品包;本页只配置,不干活。`), react.createElement(VersionLine, null));
|
|
283
640
|
}
|
|
284
641
|
function apply(ctx) {
|
|
285
642
|
const getCall = () => ctx.connection?.rpc?.call ?? null;
|
|
@@ -287,7 +644,8 @@ window.__ModuleLoader__.load({
|
|
|
287
644
|
name: "ilife.config-tab",
|
|
288
645
|
id: "dsh-memo-ilife",
|
|
289
646
|
order: 70,
|
|
290
|
-
label: () => SLOT_TITLE
|
|
647
|
+
label: () => SLOT_TITLE,
|
|
648
|
+
channel: RPC_CHANNEL
|
|
291
649
|
}, () => react.createElement(MemoConfig, { getCall })));
|
|
292
650
|
const ensureWorkTab = () => {
|
|
293
651
|
try {
|
|
@@ -324,7 +682,13 @@ window.__ModuleLoader__.load({
|
|
|
324
682
|
}
|
|
325
683
|
//#endregion
|
|
326
684
|
exports.apply = apply;
|
|
685
|
+
exports.fetchConfigSurface = fetchConfigSurface;
|
|
686
|
+
exports.fromDraft = fromDraft;
|
|
687
|
+
exports.humanizeConfigFailure = humanizeConfigFailure;
|
|
327
688
|
exports.inject = inject;
|
|
689
|
+
exports.resetConfigSurface = resetConfigSurface;
|
|
690
|
+
exports.saveConfigSurface = saveConfigSurface;
|
|
691
|
+
exports.toDraft = toDraft;
|
|
328
692
|
return module.exports;
|
|
329
693
|
}
|
|
330
694
|
});
|