@juicesharp/rpiv-advisor 1.12.0 → 1.14.0

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.
Files changed (2) hide show
  1. package/advisor.ts +34 -10
  2. package/package.json +2 -2
package/advisor.ts CHANGED
@@ -289,6 +289,30 @@ export function setDisabledForModels(models: Array<string | { model: string; min
289
289
  // Session restoration — called from index.ts session_start handler
290
290
  // ---------------------------------------------------------------------------
291
291
 
292
+ /**
293
+ * Module-local "already announced" latch. Pi fires `session_start` for every
294
+ * session including programmatic spawns (workflow stages, batch ops, any
295
+ * extension's `newSession` call). State mutation belongs on every fire;
296
+ * the user-facing announcement does NOT — repeating it per stage in a
297
+ * `/wf` run just spams the status line. The latch flips on the first
298
+ * notify and stays set until the module is reloaded (`/reload`) or the
299
+ * process restarts. Test-resettable via `__resetAdvisorAnnounced()`.
300
+ *
301
+ * This is the same shape as `restoredAdvisorState`'s own decision to
302
+ * mutate state every call but notify once. We used to read a workflow-
303
+ * branded `Symbol.for("@juicesharp/rpiv-workflow:child-session")` to
304
+ * achieve the same effect — that coupled this package to rpiv-workflow's
305
+ * internals for no real reason: every extension that wants "notify the
306
+ * user once per process" has the same shape, and none of them need to
307
+ * know who spawned the session.
308
+ */
309
+ let restoreAnnounced = false;
310
+
311
+ /** Test reset — wired into test/setup.ts `beforeEach`. */
312
+ export function __resetAdvisorAnnounced(): void {
313
+ restoreAnnounced = false;
314
+ }
315
+
292
316
  export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): void {
293
317
  const config = loadAdvisorConfig();
294
318
 
@@ -299,11 +323,15 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
299
323
  const parsed = parseModelKey(config.modelKey);
300
324
  if (!parsed) return;
301
325
 
326
+ const notifyOnce = (msg: string, level: "info" | "warning" | "error"): void => {
327
+ if (!ctx.hasUI || restoreAnnounced) return;
328
+ ctx.ui.notify(msg, level);
329
+ restoreAnnounced = true;
330
+ };
331
+
302
332
  const model = ctx.modelRegistry.find(parsed.provider, parsed.modelId);
303
333
  if (!model) {
304
- if (ctx.hasUI) {
305
- ctx.ui.notify(errModelUnavailable(config.modelKey), "warning");
306
- }
334
+ notifyOnce(errModelUnavailable(config.modelKey), "warning");
307
335
  return;
308
336
  }
309
337
 
@@ -313,10 +341,8 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
313
341
  }
314
342
 
315
343
  if (isExecutorBlocked(ctx, pi.getThinkingLevel())) {
316
- if (ctx.hasUI) {
317
- const advisorLabel = `${model.provider}:${model.id}`;
318
- ctx.ui.notify(msgAdvisorRestoredInactive(advisorLabel, config.effort), "info");
319
- }
344
+ const advisorLabel = `${model.provider}:${model.id}`;
345
+ notifyOnce(msgAdvisorRestoredInactive(advisorLabel, config.effort), "info");
320
346
  return;
321
347
  }
322
348
 
@@ -325,9 +351,7 @@ export function restoreAdvisorState(ctx: ExtensionContext, pi: ExtensionAPI): vo
325
351
  pi.setActiveTools([...active, ADVISOR_TOOL_NAME]);
326
352
  }
327
353
 
328
- if (ctx.hasUI) {
329
- ctx.ui.notify(msgAdvisorRestored(`${model.provider}:${model.id}`, config.effort), "info");
330
- }
354
+ notifyOnce(msgAdvisorRestored(`${model.provider}:${model.id}`, config.effort), "info");
331
355
  }
332
356
 
333
357
  // ---------------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juicesharp/rpiv-advisor",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "Pi extension. A second opinion the model can request from a stronger reviewer model before it acts.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -40,7 +40,7 @@
40
40
  ]
41
41
  },
42
42
  "dependencies": {
43
- "@juicesharp/rpiv-config": "^1.12.0"
43
+ "@juicesharp/rpiv-config": "^1.14.0"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@earendil-works/pi-ai": "*",