pi-advisor-flow 0.2.7 → 0.2.8

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this project are documented here.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## 0.2.8
8
+
9
+ ### Fixed
10
+
11
+ - Advisor session blocks are reported to Herdr again. Herdr grants each pane a single lifecycle status authority, which for Pi is Herdr's own `herdr-agent-state` integration, and silently drops semantic state from any other source. The Advisor block now signals that integration over Pi's in-process event bus (`herdr:blocked`) instead of relying on display metadata alone, so a blocked pane shows `blocked` rather than `working`. Only the unblocked-to-blocked edge emits, because the listener refcounts; clears are always delivered.
12
+
7
13
  ## 0.2.7
8
14
 
9
15
  ### Security
@@ -1,5 +1,6 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { registerCommands } from "../src/commands.js";
3
+ import { setHerdrBlockedEmitter } from "../src/herdr.js";
3
4
  import {
4
5
  consultAdvisor as consultAdvisorImplementation,
5
6
  parseAutomaticDecision as parseAutomaticDecisionImplementation,
@@ -28,6 +29,9 @@ export const runAdvisorGate = (
28
29
  ) => runAdvisorGateImplementation(...args);
29
30
 
30
31
  export default function (pi: ExtensionAPI) {
32
+ setHerdrBlockedEmitter((active, label) =>
33
+ pi.events.emit("herdr:blocked", { active, label })
34
+ );
31
35
  registerAdvisorTool(pi);
32
36
  registerCommands(pi);
33
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-advisor-flow",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "author": "Philip Brembeck",
5
5
  "repository": {
6
6
  "type": "git",
package/src/herdr.ts CHANGED
@@ -38,6 +38,25 @@ export interface HerdrNotificationRequest {
38
38
  export type HerdrRequest = HerdrMetadataRequest | HerdrNotificationRequest;
39
39
  type Report = (request: HerdrRequest) => void;
40
40
 
41
+ // Herdr only accepts semantic state from the pane's lifecycle authority, which
42
+ // for pi is herdr's own herdr-agent-state extension (source "herdr:pi"). Socket
43
+ // reports from any other source are dropped, so the blocked state has to be
44
+ // signalled through the in-process pi event bus that integration listens on.
45
+ type BlockedEmitter = (active: boolean, label: string) => void;
46
+ let emitBlocked: BlockedEmitter | undefined;
47
+
48
+ export const setHerdrBlockedEmitter = (emitter: BlockedEmitter | undefined) => {
49
+ emitBlocked = emitter;
50
+ };
51
+
52
+ const safeEmitBlocked = (active: boolean, label = "Advisor blocked") => {
53
+ try {
54
+ emitBlocked?.(active, label);
55
+ } catch {
56
+ /* Herdr is optional. */
57
+ }
58
+ };
59
+
41
60
  const isControlCharacter = (character: string) =>
42
61
  character <= "\u001f" || character === "\u007f";
43
62
 
@@ -167,8 +186,14 @@ export class HerdrAdvisorBlock {
167
186
  if (!this.enabled()) {
168
187
  return;
169
188
  }
189
+ const label = cleanNotification(reason, 200);
190
+ const wasBlocked: boolean = this.#blocked;
191
+ if (!wasBlocked) {
192
+ // The listener refcounts, so only the false → true edge may emit.
193
+ safeEmitBlocked(true, label);
194
+ }
170
195
  this.#blocked = true;
171
- this.safeReport({ blocked: cleanNotification(reason, 200) });
196
+ this.safeReport({ blocked: label });
172
197
  }
173
198
 
174
199
  clear() {
@@ -179,6 +204,7 @@ export class HerdrAdvisorBlock {
179
204
  }
180
205
  // Clearing previously reported state is a de-escalation and must still be
181
206
  // delivered if integration was disabled after the block was reported.
207
+ safeEmitBlocked(false);
182
208
  try {
183
209
  this.report({
184
210
  id: `${BLOCK_SOURCE}:${nextSequence()}`,