@dsh-plus/lifeboat 0.2.3 → 0.2.4

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/lib/index.js CHANGED
@@ -164,12 +164,19 @@ async function writeWithRetry(write) {
164
164
  await write();
165
165
  }
166
166
  }
167
- /** 装配 LLM 应急翻译:启动后及 settings/llm 变化时评估一次(并发合并)。 */
168
- function installLlmFallback(ctx, deps) {
167
+ /** 启动宽限(ms):llm-pi 等兄弟插件的 adapter 注册晚于 lifeboat 就绪,
168
+ * 启动竞态下立即评估会把"还没加载"误判为"缺席"——每次重启都误发
169
+ * 「应急翻译 + 已还原」两条通知。宽限期内一律不评估,宽限结束自动评估
170
+ * 一次,事件订阅覆盖后续变化;真故障(llm-pi 缺席)在宽限后照常告警。 */
171
+ const BOOT_GRACE_MS = 6e4;
172
+ /** 装配 LLM 应急翻译:启动宽限结束后及 settings/llm 变化时评估一次(并发合并)。 */
173
+ function installLlmFallback(ctx, deps, graceMs = BOOT_GRACE_MS) {
169
174
  const logger = ctx.logger("lifeboat");
170
175
  const writes = ctx.settings;
171
176
  const settingsFile = dshHomePath("settings.yaml");
172
177
  let inFlight;
178
+ const startedAt = Date.now();
179
+ const withinGrace = () => Date.now() - startedAt < graceMs;
173
180
  const listProviderIds = () => new Set(ctx.llm.listProviders().map((p) => p.id));
174
181
  async function activate(provider, model) {
175
182
  const providers = (await readRawSection(settingsFile, RAW_NS_LLM_PI).catch(() => void 0))?.providers;
@@ -227,6 +234,7 @@ function installLlmFallback(ctx, deps) {
227
234
  await activate(def.provider, def.model);
228
235
  }
229
236
  const run = () => {
237
+ if (withinGrace()) return;
230
238
  if (inFlight !== void 0) return;
231
239
  inFlight = evaluate().catch((error) => {
232
240
  const message = error instanceof Error ? error.message : String(error);
@@ -236,7 +244,7 @@ function installLlmFallback(ctx, deps) {
236
244
  inFlight = void 0;
237
245
  });
238
246
  };
239
- const bootTimer = setTimeout(run, 1e4);
247
+ const bootTimer = setTimeout(run, graceMs);
240
248
  ctx.effect(() => () => clearTimeout(bootTimer), "lifeboat: fallback boot timer");
241
249
  ctx.on("ready", run);
242
250
  const WATCHED_NS = /* @__PURE__ */ new Set([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-plus/lifeboat",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "dsh-plus service plugin: 故障救生艇——兄弟插件崩溃时自动隔离(写用户 patch 层禁用),llm-pi 缺席时把其配置临时翻译为官方 llm-pi-ai 路由,恢复后自动还原",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -211,13 +211,25 @@ export interface FallbackDeps {
211
211
  writeState(state: FallbackStateT | null): Promise<void>
212
212
  }
213
213
 
214
- /** 装配 LLM 应急翻译:启动后及 settings/llm 变化时评估一次(并发合并)。 */
215
- export function installLlmFallback(ctx: Context, deps: FallbackDeps): void {
214
+ /** 启动宽限(ms):llm-pi 等兄弟插件的 adapter 注册晚于 lifeboat 就绪,
215
+ * 启动竞态下立即评估会把"还没加载"误判为"缺席"——每次重启都误发
216
+ * 「应急翻译 + 已还原」两条通知。宽限期内一律不评估,宽限结束自动评估
217
+ * 一次,事件订阅覆盖后续变化;真故障(llm-pi 缺席)在宽限后照常告警。 */
218
+ export const BOOT_GRACE_MS = 60_000
219
+
220
+ /** 装配 LLM 应急翻译:启动宽限结束后及 settings/llm 变化时评估一次(并发合并)。 */
221
+ export function installLlmFallback(
222
+ ctx: Context,
223
+ deps: FallbackDeps,
224
+ graceMs: number = BOOT_GRACE_MS,
225
+ ): void {
216
226
  const logger = ctx.logger('lifeboat')
217
227
  const settings = ctx.settings as SettingsProvider
218
228
  const writes = settings as unknown as SettingsWrite
219
229
  const settingsFile = dshHomePath('settings.yaml')
220
230
  let inFlight: Promise<void> | undefined
231
+ const startedAt = Date.now()
232
+ const withinGrace = (): boolean => Date.now() - startedAt < graceMs
221
233
 
222
234
  const listProviderIds = (): Set<string> => new Set(ctx.llm.listProviders().map((p) => p.id))
223
235
 
@@ -300,6 +312,7 @@ export function installLlmFallback(ctx: Context, deps: FallbackDeps): void {
300
312
  }
301
313
 
302
314
  const run = (): void => {
315
+ if (withinGrace()) return
303
316
  if (inFlight !== undefined) return
304
317
  inFlight = evaluate()
305
318
  .catch((error: unknown) => {
@@ -312,9 +325,11 @@ export function installLlmFallback(ctx: Context, deps: FallbackDeps): void {
312
325
  })
313
326
  }
314
327
 
315
- // 首次评估延迟到启动收尾:lifeboat 首位加载时兄弟插件的 adapter 尚未注册,
316
- // 立刻评估会把"还没加载"误判为"缺席"。事件订阅覆盖后续变化。
317
- const bootTimer = setTimeout(run, 10_000)
328
+ // 首次评估延迟到启动宽限结束:lifeboat 首位加载时兄弟插件的 adapter 尚未
329
+ // 注册(llm-pi 就绪可能远超 10s),提前评估会把"还没加载"误判为"缺席"
330
+ // (每次重启都误发应急翻译 + 还原通知)。宽限结束评估一次,事件订阅
331
+ // 覆盖后续变化;宽限内的 settings/llm 事件同样被时间闸跳过,由收尾评估兜底。
332
+ const bootTimer = setTimeout(run, graceMs)
318
333
  ctx.effect(() => () => clearTimeout(bootTimer), 'lifeboat: fallback boot timer')
319
334
  ctx.on('ready' as never, run)
320
335
  // 只响应与本判定相关的命名空间变化:journal 写自身命名空间,不过滤会自触发循环。