@dorokuma/herdsman-pi 0.6.5 → 0.6.6

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/package.json +1 -1
  2. package/src/index.ts +30 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dorokuma/herdsman-pi",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "Pi extension bridge for Herdsman agent history. Forked from @ryonakae/shepherd.",
5
5
  "type": "module",
6
6
  "keywords": [
package/src/index.ts CHANGED
@@ -45,6 +45,7 @@ type PiPresence = {
45
45
 
46
46
  type ConnectionStateResponse = {
47
47
  changed?: boolean;
48
+ ackedEventId?: number;
48
49
  context?: AgentWorkspaceContextSnapshot | null;
49
50
  events?: AgentEventWireRecord[];
50
51
  presence: PiPresence;
@@ -223,6 +224,11 @@ export function createHerdsmanPiExtension(options: ExtensionOptions = {}) {
223
224
  state.runActive = false;
224
225
  };
225
226
 
227
+ const pruneAcknowledgedEvents = (ackedEventId: number | undefined) => {
228
+ if (ackedEventId === undefined) return;
229
+ state.pendingEvents = state.pendingEvents.filter((event) => event.id > ackedEventId);
230
+ };
231
+
226
232
  const applyOwnerContext = (response: ConnectionStateResponse) => {
227
233
  state.latestContext = isLocalOwner(response) ? response.context ?? undefined : undefined;
228
234
  };
@@ -448,6 +454,8 @@ export function createHerdsmanPiExtension(options: ExtensionOptions = {}) {
448
454
  applyOwnerContext(response);
449
455
  setHerdsmanUi(ctx);
450
456
  addPendingEvents(response.events ?? [], ctx);
457
+ pruneAcknowledgedEvents(response.state?.ackedEventId ?? response.ackedEventId);
458
+ setHerdsmanUi(ctx);
451
459
  scheduleWake(ctx);
452
460
  };
453
461
 
@@ -530,9 +538,11 @@ export function createHerdsmanPiExtension(options: ExtensionOptions = {}) {
530
538
  ? {
531
539
  ...snapshot,
532
540
  agents: snapshot.agents.filter((agent) => {
533
- const nextAgent = next?.agents.find((candidate) => candidate.paneId === agent.paneId);
534
- if (!nextAgent) return false;
535
- return !agent.id || !nextAgent.id || agent.id === nextAgent.id;
541
+ const nextAgents = next?.agents.filter((candidate) => candidate.paneId === agent.paneId) ?? [];
542
+ if (nextAgents.length === 0) return false;
543
+ return nextAgents.some(
544
+ (nextAgent) => !agent.id || !nextAgent.id || agent.id === nextAgent.id,
545
+ );
536
546
  }),
537
547
  }
538
548
  : undefined;
@@ -762,10 +772,25 @@ export function createHerdsmanPiExtension(options: ExtensionOptions = {}) {
762
772
 
763
773
  for (const event of batch.events) {
764
774
  try {
765
- await state.client.request("agent.notifications.ack", { eventId: event.id });
775
+ const ackResponse = (await state.client.request("agent.notifications.ack", {
776
+ eventId: event.id,
777
+ })) as { ackedEventId?: number; state?: { ackedEventId?: number } };
778
+ pruneAcknowledgedEvents(ackResponse?.ackedEventId ?? ackResponse?.state?.ackedEventId);
766
779
  state.pendingEvents = state.pendingEvents.filter((pending) => pending.id !== event.id);
767
780
  setHerdsmanUi(ctx);
768
- } catch {
781
+ } catch (error) {
782
+ if (
783
+ error instanceof Error &&
784
+ /no longer pending|invalidated/i.test(error.message)
785
+ ) {
786
+ state.pendingEvents = state.pendingEvents.filter((pending) => pending.id > event.id);
787
+ state.failedWakeThroughEventId = Math.max(
788
+ state.failedWakeThroughEventId,
789
+ ...batch.events.map((batchEvent) => batchEvent.id),
790
+ );
791
+ setHerdsmanUi(ctx);
792
+ continue;
793
+ }
769
794
  // Keep the event pending so the next Herdsman round retries the acknowledgement.
770
795
  // Acknowledgement failure must not block delivery of the main turn.
771
796
  ctx.ui.notify?.(