readyroom 0.1.5 → 0.1.7
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/README.md +6 -6
- package/dist/server.mjs +18 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ These words are used exactly, in code, comments, tool descriptions, and docs. No
|
|
|
57
57
|
- **ticket** — one pending request: `{ id, stream, question, options, context, urgency, status, created_at, expires_at }`.
|
|
58
58
|
- **stream** — which agent asked. Defaults to `$READYROOM_STREAM`, else `basename(cwd)`.
|
|
59
59
|
- **drain** — the human answering tickets from the page.
|
|
60
|
-
- **
|
|
60
|
+
- **readyroom page** — the single HTML page served at `GET /`.
|
|
61
61
|
|
|
62
62
|
The tool names (`ask_human`, `wait_for_answer`, `list_pending`, `cancel_ticket`) are the
|
|
63
63
|
agent-facing contract and do not change with the product name. The product name is a separate
|
|
@@ -222,7 +222,7 @@ handles `SIGTERM`.
|
|
|
222
222
|
|
|
223
223
|
### Cloudflare Worker
|
|
224
224
|
|
|
225
|
-
Always-on, reachable from anywhere, no box to patch. The Worker serves the
|
|
225
|
+
Always-on, reachable from anywhere, no box to patch. The Worker serves the readyroom page and
|
|
226
226
|
the Streamable HTTP MCP endpoint from the same origin, backed by one SQLite Durable Object
|
|
227
227
|
instance.
|
|
228
228
|
|
|
@@ -526,7 +526,7 @@ The Worker has no state dir, no bind address, and no daemon role. Three conseque
|
|
|
526
526
|
1. **The token is mandatory.** There is no loopback and no safe fallback, so a token-less
|
|
527
527
|
request to any `/api/*` route is rejected. (On the Node target, a missing token is an allow —
|
|
528
528
|
the bind refusal rule guarantees a token-less server is only reachable on loopback.)
|
|
529
|
-
2. **`/api/events` returns `501`** with a short plain-text body. The
|
|
529
|
+
2. **`/api/events` returns `501`** with a short plain-text body. The readyroom page's polling
|
|
530
530
|
fallback carries the Worker target; no Durable-Object-held stream fleet is built for v1.
|
|
531
531
|
3. **`wait_for_answer` clamps its timeout** to a short window (5 seconds) and returns
|
|
532
532
|
`status: "pending"` promptly rather than erroring. This is the **one place the three targets
|
|
@@ -534,7 +534,7 @@ The Worker has no state dir, no bind address, and no daemon role. Three conseque
|
|
|
534
534
|
protocol — call again later — is already the correct handling, so no agent needs to know
|
|
535
535
|
which target it is talking to.
|
|
536
536
|
|
|
537
|
-
## The
|
|
537
|
+
## The readyroom page
|
|
538
538
|
|
|
539
539
|
The page is a **status board**, not a chat log. It shows what is waiting and clears when you
|
|
540
540
|
have answered — which is why there is no markdown parser and no message history.
|
|
@@ -552,7 +552,7 @@ network otherwise cut. It is inlined at build time into each target's bundle.
|
|
|
552
552
|
option buttons, a free-text field, and an Answer button.
|
|
553
553
|
- **Keyboard-first.** `j`/`k` move between tickets, `1`-`5` pick an option, `Enter` submits, `u`
|
|
554
554
|
undoes the last answer. Draining a queue with a mouse is the slow path.
|
|
555
|
-
- **Tab title carries the count.** `(3)
|
|
555
|
+
- **Tab title carries the count.** `(3) readyroom`.
|
|
556
556
|
- **No colour-only signalling.** Urgency and status are carried by text and borders as well as
|
|
557
557
|
hue, so the page is legible on an e-ink display and in grayscale print.
|
|
558
558
|
- **No animation on the critical path.** Respects `prefers-reduced-motion`. No hover-only
|
|
@@ -570,7 +570,7 @@ network otherwise cut. It is inlined at build time into each target's bundle.
|
|
|
570
570
|
|
|
571
571
|
```
|
|
572
572
|
GET /healthz -> 200, body "ok"
|
|
573
|
-
GET / -> the
|
|
573
|
+
GET / -> the readyroom page (index.html)
|
|
574
574
|
GET /api/tickets -> { tickets: Ticket[] } pending + last 5 min of answered
|
|
575
575
|
GET /api/events -> text/event-stream of ticket changes (501 on the Worker)
|
|
576
576
|
POST /api/answer -> { id, answer, answered_by? } -> 200 | 404 | 409 already answered
|
package/dist/server.mjs
CHANGED
|
@@ -7506,7 +7506,7 @@ var public_default = `<!DOCTYPE html>
|
|
|
7506
7506
|
<head>
|
|
7507
7507
|
<meta charset="utf-8">
|
|
7508
7508
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7509
|
-
<title>
|
|
7509
|
+
<title>readyroom</title>
|
|
7510
7510
|
<style>
|
|
7511
7511
|
/* No external fonts, no external origins, no images fetched over the network.
|
|
7512
7512
|
Everything below is self-contained so the page renders with the network cut. */
|
|
@@ -7660,7 +7660,7 @@ var public_default = `<!DOCTYPE html>
|
|
|
7660
7660
|
</head>
|
|
7661
7661
|
<body>
|
|
7662
7662
|
<header>
|
|
7663
|
-
<h1>
|
|
7663
|
+
<h1>readyroom</h1>
|
|
7664
7664
|
<p class="sub">Drain the queue. <kbd>j</kbd>/<kbd>k</kbd> move · <kbd>1</kbd>-<kbd>5</kbd> pick · <kbd>Enter</kbd> answer · <kbd>u</kbd> undo</p>
|
|
7665
7665
|
<div id="status" class="banner" role="status" aria-live="polite">
|
|
7666
7666
|
<span class="tag">Status:</span> <span id="status-text">starting</span>
|
|
@@ -8155,7 +8155,7 @@ var public_default = `<!DOCTYPE html>
|
|
|
8155
8155
|
var recent = recentTickets();
|
|
8156
8156
|
|
|
8157
8157
|
/* requirement 5: tab title carries the count */
|
|
8158
|
-
document.title = pending.length > 0 ? "(" + pending.length + ")
|
|
8158
|
+
document.title = pending.length > 0 ? "(" + pending.length + ") readyroom" : "readyroom";
|
|
8159
8159
|
|
|
8160
8160
|
/* status line */
|
|
8161
8161
|
var statusText = "idle";
|
|
@@ -21259,21 +21259,22 @@ async function attachStdio(server) {
|
|
|
21259
21259
|
await server.connect(transport);
|
|
21260
21260
|
return transport;
|
|
21261
21261
|
}
|
|
21262
|
-
async function attachStreamableHttp(
|
|
21262
|
+
async function attachStreamableHttp(serverFactory, options) {
|
|
21263
21263
|
const log4 = options.log ?? ((message) => process.stderr.write(`readyroom: ${message}
|
|
21264
21264
|
`));
|
|
21265
|
-
const transport = new StreamableHTTPServerTransport({
|
|
21266
|
-
sessionIdGenerator: void 0,
|
|
21267
|
-
enableJsonResponse: true
|
|
21268
|
-
});
|
|
21269
|
-
await server.connect(transport);
|
|
21270
21265
|
const handle = async (req, res) => {
|
|
21271
21266
|
if (!checkOrigin(req, options.allowedOrigins)) {
|
|
21272
21267
|
res.writeHead(403, { "content-type": "text/plain; charset=utf-8" });
|
|
21273
21268
|
res.end("Forbidden: missing or disallowed Origin");
|
|
21274
21269
|
return;
|
|
21275
21270
|
}
|
|
21271
|
+
const server = serverFactory();
|
|
21272
|
+
const transport = new StreamableHTTPServerTransport({
|
|
21273
|
+
sessionIdGenerator: void 0,
|
|
21274
|
+
enableJsonResponse: true
|
|
21275
|
+
});
|
|
21276
21276
|
try {
|
|
21277
|
+
await server.connect(transport);
|
|
21277
21278
|
await transport.handleRequest(req, res);
|
|
21278
21279
|
} catch (error2) {
|
|
21279
21280
|
log4(`mcp transport error on port ${options.port}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
@@ -21281,12 +21282,17 @@ async function attachStreamableHttp(server, options) {
|
|
|
21281
21282
|
res.writeHead(500, { "content-type": "text/plain; charset=utf-8" });
|
|
21282
21283
|
res.end("Internal Server Error");
|
|
21283
21284
|
}
|
|
21285
|
+
} finally {
|
|
21286
|
+
await transport.close().catch(() => {
|
|
21287
|
+
});
|
|
21288
|
+
await server.close().catch(() => {
|
|
21289
|
+
});
|
|
21284
21290
|
}
|
|
21285
21291
|
};
|
|
21286
21292
|
return {
|
|
21287
|
-
transport,
|
|
21288
21293
|
handle,
|
|
21289
|
-
close: () =>
|
|
21294
|
+
close: async () => {
|
|
21295
|
+
}
|
|
21290
21296
|
};
|
|
21291
21297
|
}
|
|
21292
21298
|
|
|
@@ -21462,7 +21468,7 @@ async function runDaemon(config2, defaultStream) {
|
|
|
21462
21468
|
await store.load();
|
|
21463
21469
|
const deps = { store, defaultStream, now };
|
|
21464
21470
|
const allowedOrigins = buildAllowedOrigins(config2.port, config2.allowedOrigins);
|
|
21465
|
-
const mcp = await attachStreamableHttp(createMcpServer(deps), {
|
|
21471
|
+
const mcp = await attachStreamableHttp(() => createMcpServer(deps), {
|
|
21466
21472
|
port: config2.port,
|
|
21467
21473
|
allowedOrigins,
|
|
21468
21474
|
log: log3
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "readyroom",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "An MCP server that lets coding agents request a human decision without hijacking whichever window is focused. Agents enqueue a ticket; the human drains the queue from one page when they choose to.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|