dsh-galatea 0.4.0 → 0.4.2
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/index.js +57 -7
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -74,7 +74,7 @@ export const Config = z.object({
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
/** 需要宿主注入的服务。 */
|
|
77
|
-
export const inject = ['systemPrompt', 'tools', 'agents'];
|
|
77
|
+
export const inject = ['systemPrompt', 'tools', 'agents', 'timer'];
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* volatile 字段是**引用**,普通字段是**值**。
|
|
@@ -114,12 +114,52 @@ function liveConfig(raw) {
|
|
|
114
114
|
*/
|
|
115
115
|
export function apply(ctx, config) {
|
|
116
116
|
const raw = config ?? {};
|
|
117
|
-
|
|
117
|
+
// volatile 字段在 apply 里拿到的是引用(`{ get() }`),不是值。
|
|
118
|
+
//
|
|
119
|
+
// 直接读 `raw.x` 会拿到对象 —— `Number(对象)` 是 NaN,`if (NaN > 0)` 不成立,
|
|
120
|
+
// 于是那个开关永远不会生效,而且**没有任何地方会报错**。
|
|
121
|
+
//
|
|
122
|
+
// 0.4.0 的自动心跳就是这么死的:同一个文件里六个字段走了 pick(),
|
|
123
|
+
// 第七个(autoBeatMinutes)忘了,于是它从来没有被打开过。
|
|
124
|
+
//
|
|
125
|
+
// 与其要求每个调用点都记得 pick(),不如在这里一次性解引用:
|
|
126
|
+
// 之后所有地方只看普通值,「忘了 pick」这种错误就不可能再发生。
|
|
127
|
+
const cfg = {};
|
|
128
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
129
|
+
cfg[k] = v && typeof v.get === 'function' ? v.get() : v;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 解引用之后再自检一次:还有对象就说明这个字段的形状跟以为的不一样。
|
|
133
|
+
// 不能说"大概没配"就把它当默认值用掉 —— 那正是 0.4.0 的死法。
|
|
134
|
+
for (const [k, v] of Object.entries(cfg)) {
|
|
135
|
+
if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
|
|
136
|
+
console.warn(`[galatea] 设置项 ${k} 解引用后仍然是对象,这项配置可能没生效`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── 能力自检 ────────────────────────────────────────────
|
|
141
|
+
// inject 里声明了、但 ctx 上其实没有的,一次报全。
|
|
142
|
+
// 为什么需要这一段:今天这一类的错已经犯到第六次,其中两次是 inject ——
|
|
143
|
+
// 声明漏了,代码走进 else 分支,只有一行 console.warn,
|
|
144
|
+
// 而真机上用户看不到 console.warn,于是表现为「配了完全不生效」。
|
|
145
|
+
// marker 先算出来:自检要用它记下「哪些服务没接上」。
|
|
146
|
+
// 用户已经知道去哪儿看 marker(README 写着),所以它是最便宜的可见出口。
|
|
147
|
+
const marker = cfg.markerPath || join(homedir(), '.dsh', 'galatea-loaded.txt');
|
|
148
|
+
|
|
149
|
+
const missing = inject.filter((name) => ctx == null || ctx[name] === undefined);
|
|
150
|
+
if (missing.length > 0) {
|
|
151
|
+
const line = `[galatea] 这些服务没接上:${missing.join(', ')} —— 对应的功能不会工作`;
|
|
152
|
+
console.warn(line);
|
|
153
|
+
try {
|
|
154
|
+
appendFileSync(marker, ` ${line}\n`);
|
|
155
|
+
} catch {
|
|
156
|
+
// 自检自己失败不该连累插件
|
|
157
|
+
}
|
|
158
|
+
}
|
|
118
159
|
|
|
119
160
|
// ── 正控:这一段真的跑过吗 ────────────────────────────────
|
|
120
161
|
// marker 不是日志。它只回答一个问题:apply() 到底有没有被执行。
|
|
121
162
|
// 「进程起来了」「配置里写了」都不算证据。
|
|
122
|
-
const marker = cfg.markerPath || join(homedir(), '.dsh', 'galatea-loaded.txt');
|
|
123
163
|
try {
|
|
124
164
|
mkdirSync(dirname(marker), { recursive: true });
|
|
125
165
|
appendFileSync(marker, `galatea loaded at ${new Date().toISOString()} pid=${process.pid}\n`);
|
|
@@ -198,11 +238,13 @@ export function apply(ctx, config) {
|
|
|
198
238
|
// 想确认它在动,看心跳账本里有没有新记录就够了。
|
|
199
239
|
//
|
|
200
240
|
// 默认关(autoBeatMinutes = 0):一个会自己转的东西,不该在装上的那一刻就开始转。
|
|
201
|
-
const everyMin = Number(
|
|
241
|
+
const everyMin = Number(cfg.autoBeatMinutes ?? 0);
|
|
202
242
|
if (Number.isFinite(everyMin) && everyMin > 0) {
|
|
203
|
-
if (ctx && typeof ctx.
|
|
243
|
+
if (ctx && typeof ctx.interval === 'function') {
|
|
204
244
|
const ms = Math.max(60_000, everyMin * 60_000);
|
|
205
|
-
ctx.setInterval
|
|
245
|
+
// 用 ctx.interval,不用已 deprecated 的 ctx.setInterval —— 它返回 dispose,
|
|
246
|
+
// 由当前 fiber 管着,宿主热重载时不会叠出第二个定时器。
|
|
247
|
+
ctx.interval(() => {
|
|
206
248
|
try {
|
|
207
249
|
tick({});
|
|
208
250
|
} catch (err) {
|
|
@@ -212,7 +254,15 @@ export function apply(ctx, config) {
|
|
|
212
254
|
}, ms);
|
|
213
255
|
console.log(`[galatea] 自动心跳已开:每 ${everyMin} 分钟跑一次(只算不发)`);
|
|
214
256
|
} else {
|
|
215
|
-
console
|
|
257
|
+
// 用户明确要求了、却被静默拒绝 —— 这一次不能只在 console 里说。
|
|
258
|
+
// 真机上 console.warn 用户看不见,表现是「配了完全不生效,也没有任何提示」。
|
|
259
|
+
const line = '[galatea] 你配了 autoBeatMinutes,但宿主没有 ctx.interval —— 自动心跳不会跑。';
|
|
260
|
+
console.warn(line);
|
|
261
|
+
try {
|
|
262
|
+
appendFileSync(marker, ` ${line}\n`);
|
|
263
|
+
} catch {
|
|
264
|
+
// 记录失败不该连累插件
|
|
265
|
+
}
|
|
216
266
|
}
|
|
217
267
|
}
|
|
218
268
|
}
|