Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quiet-pandas-watch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"sideshow": patch
---

Allow Pi-compatible agents to hide the persistent Sideshow TUI status with `SIDESHOW_TUI_STATUS=0` while retaining native tools and trace synchronization.
4 changes: 4 additions & 0 deletions docs/connecting-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ pi install npm:sideshow
pi -e npm:sideshow
```

The extension shows its current server or session in Pi's TUI status area by
default. Set `SIDESHOW_TUI_STATUS=0` before launching Pi to hide that status
without disabling the native tools or automatic trace synchronization.

## MCP

Tools: `publish_post`, `update_post`, `list_posts`, `get_post`,
Expand Down
26 changes: 19 additions & 7 deletions extensions/sideshow.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ function agentName() {
return process.env.SIDESHOW_AGENT || "pi";
}

function showTuiStatus() {
return process.env.SIDESHOW_TUI_STATUS !== "0";
}

function authHeaders(extra = {}) {
return {
...(process.env.SIDESHOW_TOKEN
Expand Down Expand Up @@ -379,12 +383,16 @@ export default function sideshowExtension(pi) {

pi.on("session_start", (_event, ctx) => {
state.sessionId = reconstructSession(ctx);
ctx.ui.setStatus(
"sideshow",
state.sessionId
? `sideshow ${state.sessionId}`
: `sideshow ${baseUrl().replace(/^https?:\/\//, "")}`,
);
if (showTuiStatus()) {
ctx.ui.setStatus(
"sideshow",
state.sessionId
? `sideshow ${state.sessionId}`
: `sideshow ${baseUrl().replace(/^https?:\/\//, "")}`,
);
} else {
ctx.ui.setStatus("sideshow", undefined);
}
});

pi.on("turn_end", async (_event, ctx) => {
Expand All @@ -403,7 +411,11 @@ export default function sideshowExtension(pi) {
const command = args.trim();
if (command === "reset") {
state.sessionId = process.env.SIDESHOW_SESSION || undefined;
ctx.ui.setStatus("sideshow", `sideshow ${baseUrl().replace(/^https?:\/\//, "")}`);
if (showTuiStatus()) {
ctx.ui.setStatus("sideshow", `sideshow ${baseUrl().replace(/^https?:\/\//, "")}`);
} else {
ctx.ui.setStatus("sideshow", undefined);
}
ctx.ui.notify("Reset remembered sideshow session", "info");
return;
}
Expand Down
64 changes: 64 additions & 0 deletions test/piExtension.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import assert from "node:assert/strict";
import { afterEach, describe, it } from "node:test";

import sideshowExtension from "../extensions/sideshow.js";

Check failure on line 4 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Could not find a declaration file for module '../extensions/sideshow.js'. '/home/runner/work/sideshow/sideshow/extensions/sideshow.js' implicitly has an 'any' type.

const originalTuiStatus = process.env.SIDESHOW_TUI_STATUS;

afterEach(() => {
if (originalTuiStatus === undefined) delete process.env.SIDESHOW_TUI_STATUS;
else process.env.SIDESHOW_TUI_STATUS = originalTuiStatus;
});

function loadExtension() {
const handlers = new Map();
const commands = new Map();
const pi = {
on(event, handler) {

Check failure on line 17 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Parameter 'handler' implicitly has an 'any' type.

Check failure on line 17 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Parameter 'event' implicitly has an 'any' type.
handlers.set(event, handler);
},
registerCommand(name, command) {

Check failure on line 20 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Parameter 'command' implicitly has an 'any' type.

Check failure on line 20 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Parameter 'name' implicitly has an 'any' type.
commands.set(name, command);
},
registerTool() {},
};
sideshowExtension(pi);
return { handlers, commands };
}

function context(statuses) {

Check failure on line 29 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Parameter 'statuses' implicitly has an 'any' type.
return {
sessionManager: { getBranch: () => [] },
ui: {
setStatus: (key, text) => statuses.push([key, text]),

Check failure on line 33 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Parameter 'text' implicitly has an 'any' type.

Check failure on line 33 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Parameter 'key' implicitly has an 'any' type.
notify() {},
},
};
}

describe("Pi extension TUI status", () => {
it("shows status by default", () => {
delete process.env.SIDESHOW_TUI_STATUS;
const { handlers } = loadExtension();
const statuses = [];

Check failure on line 43 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Variable 'statuses' implicitly has type 'any[]' in some locations where its type cannot be determined.

handlers.get("session_start")({}, context(statuses));

Check failure on line 45 in test/piExtension.test.ts

View workflow job for this annotation

GitHub Actions / validate

Variable 'statuses' implicitly has an 'any[]' type.

assert.deepEqual(statuses, [["sideshow", "sideshow localhost:8228"]]);
});

it("clears status when SIDESHOW_TUI_STATUS=0", async () => {
process.env.SIDESHOW_TUI_STATUS = "0";
const { handlers, commands } = loadExtension();
const statuses = [];
const ctx = context(statuses);

handlers.get("session_start")({}, ctx);
await commands.get("sideshow").handler("reset", ctx);

assert.deepEqual(statuses, [
["sideshow", undefined],
["sideshow", undefined],
]);
});
});
Loading