Skip to content
Merged
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/cuddly-clouds-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"sideshow": patch
---

Validate `sideshow surface add` has at least one surface flag before resolving or creating a session, and resolve long-poll waits promptly when clients disconnect.
4 changes: 4 additions & 0 deletions bin/sideshow.js
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,10 @@ const commands = {
});
const postId = positionals[0];
if (!postId) fail("usage: sideshow surface add <postId> [--md f] [--code f] ...");
const hasSurfaceFlag = (tokens ?? []).some(
(t) => t.kind === "option" && SURFACE_FLAGS.has(t.name),
);
if (!hasSurfaceFlag) fail("provide at least one surface flag (--md, --code, ...)");

const session = await resolveSession(flags, { create: true });
const surfaces = await surfacesFromFlags(flags, tokens, { session, layout: flags.layout });
Expand Down
25 changes: 18 additions & 7 deletions server/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,7 @@ export function createApp({
// Long-poll: resolves as soon as a matching comment lands, or at timeout.
async function waitForComments(
q: CommentWait,
signal?: AbortSignal,
): Promise<{ comments: Comment[]; lastSeq: number }> {
// An author=user session wait with no explicit cursor resumes from the
// session's agentSeq — "where the agent left off" lives server-side so the
Expand All @@ -910,9 +911,16 @@ export function createApp({
if (q.surfaceId && event.surfaceId !== q.surfaceId) return;
done();
});
const onAbort = () => done();
let settled = false;
signal?.addEventListener("abort", onAbort, { once: true });
if (signal?.aborted) done();
function done() {
if (settled) return;
settled = true;
clearTimeout(timer);
unsubscribe();
signal?.removeEventListener("abort", onAbort);
resolve();
}
});
Expand Down Expand Up @@ -1567,13 +1575,16 @@ export function createApp({
// If the client disconnects mid-wait, release the slot promptly.
c.req.raw.signal.addEventListener("abort", release, { once: true });
try {
const result = await waitForComments({
sessionId,
surfaceId,
author: c.req.query("author"),
afterSeq: c.req.query("after") ? Number(c.req.query("after")) : undefined,
waitSeconds,
});
const result = await waitForComments(
{
sessionId,
surfaceId,
author: c.req.query("author"),
afterSeq: c.req.query("after") ? Number(c.req.query("after")) : undefined,
waitSeconds,
},
c.req.raw.signal,
);
return c.json(result);
} finally {
release();
Expand Down
Loading
Loading