@danypops/pi-papyrus 0.59.1 → 0.59.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.
@@ -152,6 +152,7 @@ export function buildTaskWidgetSection(
152
152
  export class TaskOverlay {
153
153
  private widgetGroup: PapyrusWidgetGroup | undefined;
154
154
  private snapshot: TaskGraph = { nodes: [], rootIds: [] };
155
+ private degraded = false;
155
156
  private projectRoot: string | undefined;
156
157
  private sessionId: string | undefined;
157
158
  private generation = 0;
@@ -188,7 +189,8 @@ export class TaskOverlay {
188
189
  if (!this.projectRoot) return;
189
190
  const generation = this.generation;
190
191
  const sessionId = this.sessionId;
191
- let snapshot: TaskGraph;
192
+ let snapshot = this.snapshot;
193
+ let degraded = false;
192
194
  try {
193
195
  snapshot = await callServicePassive<Record<string, unknown>, TaskGraph>("tasks.graph", {
194
196
  limit: 500,
@@ -196,10 +198,11 @@ export class TaskOverlay {
196
198
  session_id: sessionId,
197
199
  });
198
200
  } catch {
199
- snapshot = { nodes: [], rootIds: [] };
201
+ degraded = true;
200
202
  }
201
203
  if (generation !== this.generation) return;
202
204
  this.snapshot = snapshot;
205
+ this.degraded = degraded;
203
206
  try {
204
207
  this.widgetGroup?.requestUpdate();
205
208
  } catch {
@@ -225,12 +228,15 @@ export class TaskOverlay {
225
228
  /** Theme-free existence check -- PapyrusWidgetGroup's own eager (pre-paint) hide decision needs
226
229
  * this without needing a theme, which is only ever available inside the widget's own render(width). */
227
230
  hasOpenWork(): boolean {
228
- return buildTaskWidgetProjection(this.snapshot).openTotal > 0;
231
+ return this.degraded || buildTaskWidgetProjection(this.snapshot).openTotal > 0;
229
232
  }
230
233
 
231
- /** undefined when there is no open work to show -- PapyrusWidgetGroup's own signal to omit this section entirely. */
234
+ /** Returns current tasks, retaining stale rows or an unavailable status while the service recovers. */
232
235
  buildSection(theme: Theme): WidgetSection | undefined {
233
- return buildTaskWidgetSection(theme, buildTaskWidgetProjection(this.snapshot), this.rotation);
236
+ const section = buildTaskWidgetSection(theme, buildTaskWidgetProjection(this.snapshot), this.rotation);
237
+ if (section) return this.degraded ? { ...section, label: `${section.label} · stale` } : section;
238
+ if (this.degraded) return { label: "Tasks · unavailable", render: () => ["Papyrus service unavailable; retrying."] };
239
+ return undefined;
234
240
  }
235
241
 
236
242
  /**
@@ -267,6 +273,7 @@ export class NoteOverlay {
267
273
  private widgetGroup: PapyrusWidgetGroup | undefined;
268
274
  private notes: NoteWidgetRow[] = [];
269
275
  private totalOpenCount = 0;
276
+ private degraded = false;
270
277
  private projectRoot: string | undefined;
271
278
  private generation = 0;
272
279
  private readonly poll = new BoundedPoll();
@@ -289,8 +296,9 @@ export class NoteOverlay {
289
296
  if (!this.projectRoot) return;
290
297
  const generation = this.generation;
291
298
  const projectRoot = this.projectRoot;
292
- let notes: NoteWidgetRow[] = [];
293
- let totalOpenCount = 0;
299
+ let notes = this.notes;
300
+ let totalOpenCount = this.totalOpenCount;
301
+ let degraded = false;
294
302
  try {
295
303
  const rows = await callServicePassive<Record<string, unknown>, Artifact[]>("notes.list", {
296
304
  project_root: projectRoot,
@@ -299,11 +307,12 @@ export class NoteOverlay {
299
307
  totalOpenCount = rows.length;
300
308
  notes = rows.slice(0, NOTE_WIDGET_OPEN_LIMIT).map((row) => ({ id: row.id, title: row.title }));
301
309
  } catch {
302
- // A missing daemon is the normal passive-startup case.
310
+ degraded = true;
303
311
  }
304
312
  if (generation !== this.generation) return;
305
313
  this.totalOpenCount = totalOpenCount;
306
314
  this.notes = notes;
315
+ this.degraded = degraded;
307
316
  try {
308
317
  this.widgetGroup?.requestUpdate();
309
318
  } catch {
@@ -313,12 +322,15 @@ export class NoteOverlay {
313
322
 
314
323
  /** Theme-free existence check -- see TaskOverlay's own hasOpenWork() for why this needs to stay theme-free. */
315
324
  hasOpenNotes(): boolean {
316
- return this.totalOpenCount > 0;
325
+ return this.degraded || this.totalOpenCount > 0;
317
326
  }
318
327
 
319
- /** undefined when there are no open notes -- PapyrusWidgetGroup's own signal to omit this section entirely. */
328
+ /** Returns current notes, retaining stale rows or an unavailable status while the service recovers. */
320
329
  buildSection(): WidgetSection | undefined {
321
- return buildNoteWidgetSection(this.notes, this.totalOpenCount, this.rotation);
330
+ const section = buildNoteWidgetSection(this.notes, this.totalOpenCount, this.rotation);
331
+ if (section) return this.degraded ? { ...section, label: `${section.label} · stale` } : section;
332
+ if (this.degraded) return { label: "Notes · unavailable", render: () => ["Papyrus service unavailable; retrying."] };
333
+ return undefined;
322
334
  }
323
335
 
324
336
  startPolling(intervalMs: number = NOTE_WIDGET_POLL_INTERVAL_MS): void {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danypops/pi-papyrus",
3
- "version": "0.59.1",
3
+ "version": "0.59.2",
4
4
  "description": "Pi host extension for Papyrus: native tools, TUI panels, and context injection over the daemon-backed graph store",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@danypops/jittor": "^0.19.2",
23
- "@danypops/papyrus": "^0.60.7",
23
+ "@danypops/papyrus": "^0.60.10",
24
24
  "@danypops/vehicle-client": "^0.10.3",
25
25
  "@danypops/vehicle-core": "^0.18.5",
26
26
  "@danypops/vehicle-server": "^0.25.2",