pi-link 0.5.0 → 0.5.1

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,16 @@ This changelog is based on the git history from `2026-03-21` (initial commit) th
6
6
 
7
7
  ---
8
8
 
9
+ ## 0.5.1 — 2026-09-22
10
+
11
+ ### Fixed
12
+
13
+ - **pi-link's tools are callable directly under Oh My Pi.** The three tools are registered with `loadMode: "essential"`, so harnesses that hide extension tools by default, such as Oh My Pi, list them with the other callable tools instead of behind a discovery path. Pi has no such field and ignores it.
14
+
15
+ - **Peers see a terminal's context usage change after a model switch or tree navigation.** A terminal now republishes its context when its model changes or it moves to another branch of the session tree. Before, an idle terminal kept showing its previous figure until its next run.
16
+
17
+ ---
18
+
9
19
  ## 0.5.0 — 2026-09-16
10
20
 
11
21
  ### Added
package/README.md CHANGED
@@ -663,11 +663,13 @@ The extension hooks into Pi's agent lifecycle events:
663
663
  - **`tool_execution_end`** → Drops that one call. The display stays `tool:<name>` while other calls remain, moves to the next call when the displayed one ends, and returns to `thinking` after the last one while the agent run continues.
664
664
  - **`session_before_compact`** → For a manual compaction, raises the gate that holds inbox delivery. Automatic (threshold/overflow) compaction is left alone: it runs inside the agent run, where Pi already queues and drains steered messages itself.
665
665
  - **`session_compact`** → Clears the local compaction gate and force-pushes a `status_update` so peers see the new (post-compaction) context usage immediately.
666
+ - **`model_select`** → Force-pushes a `status_update`: the context window, and so the usage percentage, belongs to the model.
667
+ - **`session_tree`** → Force-pushes a `status_update`: context usage belongs to the active branch.
666
668
  - **`session_shutdown`** → Full cleanup via `cleanup()`: closes all sockets, resolves pending promises, and disposes the extension.
667
669
 
668
- The five agent and tool handlers — `agent_start`, `agent_end`, `agent_settled` (when Pi still reports the session idle), `tool_execution_start` and `tool_execution_end` — each recompute the status and hand it to `pushStatus()`, which publishes only when the display identity changed since the last publish: a second concurrent tool starting behind the one already shown is silent, and so is a mutation that leaves a raised compaction gate on display. The session handlers keep the separate paths described in their own bullets, and `session_shutdown` cleans up rather than pushing. `disconnect()` is the only thing that clears the stored baseline, and `pushStatus()` returns immediately while the terminal is disconnected, so handler events in that interval restore nothing; once connected again, either a client's forced `welcome` push or the first of those ordinary handler events restores it. `session_compact` always pushes, whether the identity changed or not — including while a remote request's gate still holds the displayed identity.
670
+ The five agent and tool handlers — `agent_start`, `agent_end`, `agent_settled` (when Pi still reports the session idle), `tool_execution_start` and `tool_execution_end` — each recompute the status and hand it to `pushStatus()`, which publishes only when the display identity changed since the last publish: a second concurrent tool starting behind the one already shown is silent, and so is a mutation that leaves a raised compaction gate on display. The session handlers keep the separate paths described in their own bullets, and `session_shutdown` cleans up rather than pushing. `disconnect()` is the only thing that clears the stored baseline, and `pushStatus()` returns immediately while the terminal is disconnected, so handler events in that interval restore nothing; once connected again, either a client's forced `welcome` push or the first of those ordinary handler events restores it. `session_compact`, `model_select` and `session_tree` always push, whether the identity changed or not — including while a remote request's gate still holds the displayed identity.
669
671
 
670
- Status updates are push-based: each terminal broadcasts changes to the hub, which fans them out. New joiners receive a status snapshot for all terminals in the `welcome` message. Context updates reuse the same status path, including a forced post-compaction update.
672
+ Status updates are push-based: each terminal broadcasts changes to the hub, which fans them out. New joiners receive a status snapshot for all terminals in the `welcome` message. Context updates reuse the same status path, including forced updates after a compaction, a model change and tree navigation.
671
673
 
672
674
  ### Inbox
673
675
 
package/index.ts CHANGED
@@ -44,6 +44,9 @@ const BATCH_MAX_ITEMS = 20;
44
44
  const BATCH_MAX_CHARS = 16_000;
45
45
  // Visual rows of an incoming message kept while Pi's global expansion is off.
46
46
  const PREVIEW_ROWS = 6;
47
+ // Consumed by harnesses that hide extension tools by default (Oh My Pi);
48
+ // ignored by Pi, whose ToolDefinition has no such field.
49
+ const TOP_LEVEL_TOOL = { loadMode: "essential" } as const;
47
50
 
48
51
  // ─── Protocol ────────────────────────────────────────────────────────────────
49
52
 
@@ -1469,6 +1472,14 @@ export default function (pi: ExtensionAPI) {
1469
1472
  pushStatus(true);
1470
1473
  });
1471
1474
 
1475
+ pi.on("model_select", async () => {
1476
+ pushStatus(true); // the window, and so the usage percentage, belongs to the model
1477
+ });
1478
+
1479
+ pi.on("session_tree", async () => {
1480
+ pushStatus(true); // context usage belongs to the active branch
1481
+ });
1482
+
1472
1483
  pi.on("tool_execution_start", async (event) => {
1473
1484
  const before = statusIdentity(deriveStatus());
1474
1485
  activeTools.set(event.toolCallId, event.toolName);
@@ -1566,6 +1577,7 @@ export default function (pi: ExtensionAPI) {
1566
1577
  // ── Tools ────────────────────────────────────────────────────────────────
1567
1578
 
1568
1579
  pi.registerTool({
1580
+ ...TOP_LEVEL_TOOL,
1569
1581
  name: "link_send",
1570
1582
  label: "Link Send",
1571
1583
  description: [
@@ -1630,6 +1642,7 @@ export default function (pi: ExtensionAPI) {
1630
1642
  });
1631
1643
 
1632
1644
  pi.registerTool({
1645
+ ...TOP_LEVEL_TOOL,
1633
1646
  name: "link_compact",
1634
1647
  label: "Link Compact",
1635
1648
  description: [
@@ -1742,6 +1755,7 @@ export default function (pi: ExtensionAPI) {
1742
1755
  });
1743
1756
 
1744
1757
  pi.registerTool({
1758
+ ...TOP_LEVEL_TOOL,
1745
1759
  name: "link_list",
1746
1760
  label: "Link List",
1747
1761
  description: "List the Pi terminals in your group currently connected to the link.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-link",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "WebSocket-based inter-terminal communication for Pi. Connect multiple Pi terminals over a local link network.",
5
5
  "author": "alvivar",
6
6
  "license": "MIT",