@pi-unipi/unipi 2.20.1 → 2.20.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.20.2] — 2026-09-17
10
+
11
+ ### Fixed
12
+
13
+ - `core`, `background-tasks`, `fusion`: **panes waiting on an auto-resume wake read `working` in herdr, not `idle`.** When the lead's turn ended while background work will re-invoke the agent — a bg task with wake-on-completion, or a Fusion sidekick handoff — herdr's sidebar flipped to `idle` the moment `agent_settled` fired, even as the session's own wake line said "agent resumes automatically when done". New key-scoped claim helper `setHerdrWorking()` in `@pi-unipi/core` emits `herdr:working {active,label}` exactly once per claim transition (the same refcounted event protocol `herdr:blocked` uses); `background-tasks` holds the claim while its bg-wake line is installed and `fusion` holds it while the sidekick wake line is up. Consumed by a one-listener patch to herdr's pi integration (held-working refcount in `desiredState()`, `blocked` still outranks it) — herdr enforces one status authority per pane and ignores second-source `pane.report_agent` reports, so the event protocol is the only channel. Until herdr upstreams the protocol, the patched integration file is local (`herdr integration install pi` reverts it; pristine v8 backup at `~/.pi/agent/herdr-agent-state.v8.orig.bak`).
14
+
9
15
  ## [2.20.1] — 2026-09-17
10
16
 
11
17
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/unipi",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "All-in-one extension suite for Pi coding agent",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -84,29 +84,29 @@
84
84
  "typebox": "^1.1.38"
85
85
  },
86
86
  "dependencies": {
87
- "@pi-unipi/ask-user": "2.20.1",
88
- "@pi-unipi/background-tasks": "2.20.1",
89
- "@pi-unipi/btw": "2.20.1",
90
- "@pi-unipi/command-enchantment": "2.20.1",
91
- "@pi-unipi/compactor": "2.20.1",
92
- "@pi-unipi/core": "2.20.1",
93
- "@pi-unipi/footer": "2.20.1",
94
- "@pi-unipi/image": "2.20.1",
95
- "@pi-unipi/fusion": "2.20.1",
96
- "@pi-unipi/info-screen": "2.20.1",
97
- "@pi-unipi/input-shortcuts": "2.20.1",
98
- "@pi-unipi/kanboard": "2.20.1",
99
- "@pi-unipi/mcp": "2.20.1",
100
- "@pi-unipi/memory": "2.20.1",
101
- "@pi-unipi/milestone": "2.20.1",
102
- "@pi-unipi/notify": "2.20.1",
103
- "@pi-unipi/ralph": "2.20.1",
104
- "@pi-unipi/subagents": "2.20.1",
105
- "@pi-unipi/trajectory": "2.20.1",
106
- "@pi-unipi/updater": "2.20.1",
107
- "@pi-unipi/utility": "2.20.1",
108
- "@pi-unipi/web-api": "2.20.1",
109
- "@pi-unipi/workflow": "2.20.1"
87
+ "@pi-unipi/ask-user": "2.20.2",
88
+ "@pi-unipi/background-tasks": "2.20.2",
89
+ "@pi-unipi/btw": "2.20.2",
90
+ "@pi-unipi/command-enchantment": "2.20.2",
91
+ "@pi-unipi/compactor": "2.20.2",
92
+ "@pi-unipi/core": "2.20.2",
93
+ "@pi-unipi/footer": "2.20.2",
94
+ "@pi-unipi/image": "2.20.2",
95
+ "@pi-unipi/fusion": "2.20.2",
96
+ "@pi-unipi/info-screen": "2.20.2",
97
+ "@pi-unipi/input-shortcuts": "2.20.2",
98
+ "@pi-unipi/kanboard": "2.20.2",
99
+ "@pi-unipi/mcp": "2.20.2",
100
+ "@pi-unipi/memory": "2.20.2",
101
+ "@pi-unipi/milestone": "2.20.2",
102
+ "@pi-unipi/notify": "2.20.2",
103
+ "@pi-unipi/ralph": "2.20.2",
104
+ "@pi-unipi/subagents": "2.20.2",
105
+ "@pi-unipi/trajectory": "2.20.2",
106
+ "@pi-unipi/updater": "2.20.2",
107
+ "@pi-unipi/utility": "2.20.2",
108
+ "@pi-unipi/web-api": "2.20.2",
109
+ "@pi-unipi/workflow": "2.20.2"
110
110
  },
111
111
  "devDependencies": {
112
112
  "@earendil-works/pi-agent-core": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/ask-user",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Structured user input tool for Pi coding agent — single-select, multi-select, freeform",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -40,7 +40,7 @@
40
40
  "access": "public"
41
41
  },
42
42
  "dependencies": {
43
- "@pi-unipi/core": "2.20.1"
43
+ "@pi-unipi/core": "2.20.2"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/command-enchantment",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Enhanced TUI autocomplete for /unipi:* commands — colored, sorted, and grouped by package",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/background-tasks",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Background tasks for UniPi — durable shell jobs and delegated background agents with a footer dock",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@earendil-works/pi-ai": "^0.84.0",
13
- "@pi-unipi/core": "2.20.1",
13
+ "@pi-unipi/core": "2.20.2",
14
14
  "turndown": "^7.2.4"
15
15
  },
16
16
  "devDependencies": {
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
13
- import { createSpinnerLine } from "@pi-unipi/core";
13
+ import { createSpinnerLine, setHerdrWorking } from "@pi-unipi/core";
14
14
  import { loadBackgroundTasksConfig } from "./config.js";
15
15
  import { BackgroundTaskRegistry } from "./registry.js";
16
16
  import {
@@ -134,9 +134,21 @@ export default function backgroundTasksExtension(pi: ExtensionAPI): void {
134
134
  { placement: "aboveEditor" },
135
135
  );
136
136
  wakeLineInstalled = true;
137
+ // The pane is not done: a running task will re-invoke the agent. Keep
138
+ // herdr at `working` instead of `idle` for exactly as long as the wake
139
+ // line is up (one claim transition per widget install, not per tick).
140
+ const wakeCount = registry
141
+ .allTasks()
142
+ .filter((task) => task.status === "running" && task.triggerOnCompletion).length;
143
+ setHerdrWorking(
144
+ pi,
145
+ "bg-wake",
146
+ `${wakeCount === 1 ? "1 bg task" : `${String(wakeCount)} bg tasks`} will resume agent`,
147
+ );
137
148
  } else if (!wantWakeLine && wakeLineInstalled) {
138
149
  target.ui.setWidget("background-tasks", undefined);
139
150
  wakeLineInstalled = false;
151
+ setHerdrWorking(pi, "bg-wake", null);
140
152
  }
141
153
  if (running.length === 0 && unseenFinishedCount === 0) {
142
154
  target.ui.setStatus("background-tasks", undefined);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/btw",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "A pi extension for parallel side conversations with /unipi:btw — part of the Unipi suite",
5
5
  "type": "module",
6
6
  "main": "extensions/btw.ts",
@@ -37,7 +37,7 @@
37
37
  "@earendil-works/pi-tui": "^0.84.0"
38
38
  },
39
39
  "dependencies": {
40
- "@pi-unipi/core": "2.20.1"
40
+ "@pi-unipi/core": "2.20.2"
41
41
  },
42
42
  "pi": {
43
43
  "extensions": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/compactor",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Context engine for Pi — zero-LLM compaction, session continuity, sandbox execution, and tool display optimization",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -34,8 +34,8 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.20.1",
38
- "@pi-unipi/info-screen": "2.20.1",
37
+ "@pi-unipi/core": "2.20.2",
38
+ "@pi-unipi/info-screen": "2.20.2",
39
39
  "@earendil-works/pi-agent-core": "^0.84.0"
40
40
  },
41
41
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/core",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Shared utilities, event types, and constants for Unipi extension suite",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -304,6 +304,42 @@ export async function withHerdrBlocked<T>(
304
304
  }
305
305
  }
306
306
 
307
+ /**
308
+ * Claim herdr `working` state for a long-lived "the agent will auto-resume" wait
309
+ * (bg task wake, fusion sidekick handoff) — the states where pi has already
310
+ * settled but background work holds a pending wake.
311
+ *
312
+ * Key-scoped and level-based, not a wrapper: each key claims exactly once and
313
+ * emits `herdr:working` {active:true,label} on claim, {active:false,label} on
314
+ * clear — the same refcounted protocol `herdr:blocked` uses, so the herdr pi
315
+ * integration can keep the pane `working` after agent_settled.
316
+ *
317
+ * - label !== null && no previous claim → emit active
318
+ * - label !== null && same label → no emit (still claimed)
319
+ * - label !== null && different label → emit inactive(previous) then active
320
+ * - label === null && claimed → emit inactive, drop claim
321
+ * - label === null && not claimed → no emit
322
+ */
323
+ const herdrWorkingClaims = new Map<string, string>();
324
+
325
+ export function setHerdrWorking(
326
+ pi: { events: { emit: (name: string, payload: unknown) => void } },
327
+ key: string,
328
+ label: string | null,
329
+ ): void {
330
+ const previous = herdrWorkingClaims.get(key);
331
+ if (label === null) {
332
+ if (previous === undefined) return;
333
+ herdrWorkingClaims.delete(key);
334
+ emitEvent(pi, "herdr:working", { active: false, label: previous });
335
+ return;
336
+ }
337
+ if (previous === label) return;
338
+ if (previous !== undefined) emitEvent(pi, "herdr:working", { active: false, label: previous });
339
+ herdrWorkingClaims.set(key, label);
340
+ emitEvent(pi, "herdr:working", { active: true, label });
341
+ }
342
+
307
343
  /** Format a token count for display (e.g. 1234 → "1.2k", 1500000 → "1.5M"). */
308
344
  export function formatTokens(n: number): string {
309
345
  if (n < 1000) return String(n);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/footer",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Persistent status bar for Unipi — subscribes to UNIPI_EVENTS and renders key stats from all unipi packages",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.20.1",
36
- "@pi-unipi/background-tasks": "2.20.1"
35
+ "@pi-unipi/core": "2.20.2",
36
+ "@pi-unipi/background-tasks": "2.20.2"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/fusion",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Devin-style model picker, fusion presets (lead + sidekick), and Local Fusion runtime for UniPi",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.20.1",
36
- "@pi-unipi/subagents": "2.20.1"
35
+ "@pi-unipi/core": "2.20.2",
36
+ "@pi-unipi/subagents": "2.20.2"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-ai": "^0.84.0",
@@ -16,7 +16,7 @@
16
16
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
17
17
  import type { Api, Model } from "@earendil-works/pi-ai";
18
18
  import type { AutocompleteProvider, AutocompleteSuggestions } from "@earendil-works/pi-tui";
19
- import { createSpinnerLine, setSharedFusionStatus, UNIPI_PREFIX } from "@pi-unipi/core";
19
+ import { createSpinnerLine, setHerdrWorking, setSharedFusionStatus, UNIPI_PREFIX } from "@pi-unipi/core";
20
20
  import { homedir } from "node:os";
21
21
  import { join } from "node:path";
22
22
  import {
@@ -85,6 +85,8 @@ export interface SidekickWakeLine {
85
85
  export function createSidekickWakeLine(deps: {
86
86
  isBusy: () => boolean;
87
87
  progress: () => { toolCalls: number; startedAt: number } | undefined;
88
+ /** Claim hook: called with a label when the line goes up, null when it comes down. */
89
+ onHeld?: (label: string | null) => void;
88
90
  }): SidekickWakeLine {
89
91
  let installed = false;
90
92
 
@@ -102,14 +104,17 @@ export function createSidekickWakeLine(deps: {
102
104
  { placement: "aboveEditor" },
103
105
  );
104
106
  installed = true;
107
+ deps.onHeld?.("sidekick working — resumes automatically");
105
108
  } else if (!want && installed) {
106
109
  ctx.ui.setWidget(SIDEKICK_WAKE_WIDGET_KEY, undefined);
107
110
  installed = false;
111
+ deps.onHeld?.(null);
108
112
  }
109
113
  },
110
114
  clear(ctx) {
111
115
  if (!installed) return;
112
116
  installed = false;
117
+ deps.onHeld?.(null);
113
118
  if (!removable(ctx)) return;
114
119
  ctx.ui.setWidget(SIDEKICK_WAKE_WIDGET_KEY, undefined);
115
120
  },
@@ -190,6 +195,10 @@ export default function fusionExtension(pi: ExtensionAPI): void {
190
195
  const wakeLine = createSidekickWakeLine({
191
196
  isBusy: () => runtime?.isBusy() === true,
192
197
  progress: () => runtime?.progress(),
198
+ // While the wake line is up the pane must read `working` in herdr (the
199
+ // sidekick will re-invoke the lead), not `idle` — same claim the bg-tasks
200
+ // wake line makes.
201
+ onHeld: (label) => setHerdrWorking(pi, "fusion-sidekick", label),
193
202
  });
194
203
 
195
204
  function identity(ctx: ExtensionContext): FusionIdentity {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/image",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Image generation and image recognition tools for the Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.20.1"
37
+ "@pi-unipi/core": "2.20.2"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@earendil-works/pi-ai": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/info-screen",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Dashboard and module registry for Unipi — configurable info overlay with tabbed groups",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "2.20.1"
36
+ "@pi-unipi/core": "2.20.2"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/input-shortcuts",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle — chord-based overlay system",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -33,7 +33,7 @@
33
33
  "access": "public"
34
34
  },
35
35
  "dependencies": {
36
- "@pi-unipi/core": "2.20.1"
36
+ "@pi-unipi/core": "2.20.2"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/kanboard",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Visualization layer for unipi workflow — HTTP server with htmx/Alpine.js UI, modular parsers, TUI overlay, and kanban board",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@pi-unipi/core": "2.20.1"
42
+ "@pi-unipi/core": "2.20.2"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/mcp",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "MCP server management extension for Pi coding agent — browse, add, configure, and use MCP servers",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -30,7 +30,7 @@
30
30
  "test": "npx tsx --test tests/**/*.test.ts"
31
31
  },
32
32
  "dependencies": {
33
- "@pi-unipi/core": "2.20.1"
33
+ "@pi-unipi/core": "2.20.2"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/memory",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Persistent cross-session memory with MemPalace backend (auto-installed) and SQLite fallback for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -39,8 +39,8 @@
39
39
  "README.md"
40
40
  ],
41
41
  "dependencies": {
42
- "@pi-unipi/core": "2.20.1",
43
- "@pi-unipi/info-screen": "2.20.1",
42
+ "@pi-unipi/core": "2.20.2",
43
+ "@pi-unipi/info-screen": "2.20.2",
44
44
  "js-yaml": "^4.1.0"
45
45
  },
46
46
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/milestone",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Lifecycle layer for project-level goals — MILESTONES.md tracking, session hooks, auto-sync",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@pi-unipi/core": "2.20.1"
35
+ "@pi-unipi/core": "2.20.2"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/notify",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Cross-platform notification extension for Pi — native OS, Gotify, and Telegram notifications for agent lifecycle events",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.20.1",
37
+ "@pi-unipi/core": "2.20.2",
38
38
  "node-notifier": "^10.0.1"
39
39
  },
40
40
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/ralph",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Long-running iterative development loops for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -31,8 +31,8 @@
31
31
  "test": "npx tsx --test reminder.test.ts"
32
32
  },
33
33
  "dependencies": {
34
- "@pi-unipi/core": "2.20.1",
35
- "@pi-unipi/info-screen": "2.20.1"
34
+ "@pi-unipi/core": "2.20.2",
35
+ "@pi-unipi/info-screen": "2.20.2"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@earendil-works/pi-ai": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/subagents",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Subagents for UniPi — parallel execution, file locking, workflow integration",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -9,7 +9,7 @@
9
9
  "test": "npx tsx --test src/__tests__/*.test.ts"
10
10
  },
11
11
  "dependencies": {
12
- "@pi-unipi/core": "2.20.1",
12
+ "@pi-unipi/core": "2.20.2",
13
13
  "@earendil-works/pi-agent-core": "^0.84.0",
14
14
  "acorn": "8.18.0"
15
15
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/trajectory",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Live UniPi trajectory inspector for Pi sessions",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -624,6 +624,19 @@ async function withHerdrBlocked(pi, label, fn) {
624
624
  event(false);
625
625
  }
626
626
  }
627
+ function setHerdrWorking(pi, key, label) {
628
+ const previous = herdrWorkingClaims.get(key);
629
+ if (label === null) {
630
+ if (previous === void 0) return;
631
+ herdrWorkingClaims.delete(key);
632
+ emitEvent(pi, "herdr:working", { active: false, label: previous });
633
+ return;
634
+ }
635
+ if (previous === label) return;
636
+ if (previous !== void 0) emitEvent(pi, "herdr:working", { active: false, label: previous });
637
+ herdrWorkingClaims.set(key, label);
638
+ emitEvent(pi, "herdr:working", { active: true, label });
639
+ }
627
640
  function formatTokens(n) {
628
641
  if (n < 1e3) return String(n);
629
642
  if (n < 1e4) return `${(n / 1e3).toFixed(1)}k`;
@@ -652,11 +665,12 @@ function compareVersions(a, b) {
652
665
  function isNewerVersion(latest, current) {
653
666
  return compareVersions(latest, current) > 0;
654
667
  }
655
- var cachedPiVersion;
668
+ var cachedPiVersion, herdrWorkingClaims;
656
669
  var init_utils = __esm({
657
670
  "packages/core/utils.ts"() {
658
671
  "use strict";
659
672
  cachedPiVersion = null;
673
+ herdrWorkingClaims = /* @__PURE__ */ new Map();
660
674
  }
661
675
  });
662
676
 
@@ -1102,6 +1116,7 @@ __export(core_exports, {
1102
1116
  safeRepeat: () => safeRepeat,
1103
1117
  safeRepeatCount: () => safeRepeatCount,
1104
1118
  sanitize: () => sanitize,
1119
+ setHerdrWorking: () => setHerdrWorking,
1105
1120
  setSharedFusionStatus: () => setSharedFusionStatus,
1106
1121
  shouldRenderBorder: () => shouldRenderBorder,
1107
1122
  tryDelete: () => tryDelete,
@@ -25680,9 +25695,16 @@ function backgroundTasksExtension(pi) {
25680
25695
  { placement: "aboveEditor" }
25681
25696
  );
25682
25697
  wakeLineInstalled = true;
25698
+ const wakeCount = registry3.allTasks().filter((task) => task.status === "running" && task.triggerOnCompletion).length;
25699
+ setHerdrWorking(
25700
+ pi,
25701
+ "bg-wake",
25702
+ `${wakeCount === 1 ? "1 bg task" : `${String(wakeCount)} bg tasks`} will resume agent`
25703
+ );
25683
25704
  } else if (!wantWakeLine && wakeLineInstalled) {
25684
25705
  target.ui.setWidget("background-tasks", void 0);
25685
25706
  wakeLineInstalled = false;
25707
+ setHerdrWorking(pi, "bg-wake", null);
25686
25708
  }
25687
25709
  if (running.length === 0 && unseenFinishedCount === 0) {
25688
25710
  target.ui.setStatus("background-tasks", void 0);
@@ -52125,14 +52147,17 @@ function createSidekickWakeLine(deps) {
52125
52147
  { placement: "aboveEditor" }
52126
52148
  );
52127
52149
  installed = true;
52150
+ deps.onHeld?.("sidekick working \u2014 resumes automatically");
52128
52151
  } else if (!want && installed) {
52129
52152
  ctx.ui.setWidget(SIDEKICK_WAKE_WIDGET_KEY, void 0);
52130
52153
  installed = false;
52154
+ deps.onHeld?.(null);
52131
52155
  }
52132
52156
  },
52133
52157
  clear(ctx) {
52134
52158
  if (!installed) return;
52135
52159
  installed = false;
52160
+ deps.onHeld?.(null);
52136
52161
  if (!removable(ctx)) return;
52137
52162
  ctx.ui.setWidget(SIDEKICK_WAKE_WIDGET_KEY, void 0);
52138
52163
  }
@@ -52198,7 +52223,11 @@ function fusionExtension(pi) {
52198
52223
  let bashStreak = 0;
52199
52224
  const wakeLine = createSidekickWakeLine({
52200
52225
  isBusy: () => runtime?.isBusy() === true,
52201
- progress: () => runtime?.progress()
52226
+ progress: () => runtime?.progress(),
52227
+ // While the wake line is up the pane must read `working` in herdr (the
52228
+ // sidekick will re-invoke the lead), not `idle` — same claim the bg-tasks
52229
+ // wake line makes.
52230
+ onHeld: (label) => setHerdrWorking(pi, "fusion-sidekick", label)
52202
52231
  });
52203
52232
  function identity(ctx) {
52204
52233
  const reg = registryOf(ctx);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/updater",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Auto-updater, changelog browser, and readme browser for Unipi — checks npm registry, renders CHANGELOG.md and README.md files in TUI overlays",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -34,7 +34,7 @@
34
34
  "access": "public"
35
35
  },
36
36
  "dependencies": {
37
- "@pi-unipi/core": "2.20.1"
37
+ "@pi-unipi/core": "2.20.2"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "@earendil-works/pi-coding-agent": "^0.84.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/utility",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Utility commands and tools for Pi coding agent — lifecycle, diagnostics, cache, analytics, display, batch execution",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -36,7 +36,7 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
- "@pi-unipi/core": "2.20.1"
39
+ "@pi-unipi/core": "2.20.2"
40
40
  },
41
41
  "devDependencies": {},
42
42
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/web-api",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Web search, read, and summarize tools with provider-based backend selection for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -31,7 +31,7 @@
31
31
  "README.md"
32
32
  ],
33
33
  "dependencies": {
34
- "@pi-unipi/core": "2.20.1",
34
+ "@pi-unipi/core": "2.20.2",
35
35
  "defuddle": "^0.18.1",
36
36
  "linkedom": "^0.18.12",
37
37
  "wreq-js": "^2.3.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-unipi/workflow",
3
- "version": "2.20.1",
3
+ "version": "2.20.2",
4
4
  "description": "Structured development workflow commands for Pi coding agent",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -30,7 +30,7 @@
30
30
  "access": "public"
31
31
  },
32
32
  "dependencies": {
33
- "@pi-unipi/core": "2.20.1"
33
+ "@pi-unipi/core": "2.20.2"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@earendil-works/pi-ai": "^0.84.0",