taskchef 5.11.1 → 5.11.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/.codex-plugin/plugin.json +1 -1
- package/README.md +11 -8
- package/package.json +1 -1
- package/src/dashboard.js +2 -35
package/README.md
CHANGED
|
@@ -174,10 +174,9 @@ executors report results:
|
|
|
174
174
|
taskchef dashboard
|
|
175
175
|
```
|
|
176
176
|
|
|
177
|
-
Open the printed
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
address bar. Use `--port <number>` to choose another port and `--workspace
|
|
177
|
+
Open the printed local URL, which is `http://127.0.0.1:3210/` by default. The
|
|
178
|
+
same server can be open in the Codex in-app browser and an external browser at
|
|
179
|
+
the same time. Use `--port <number>` to choose another port and `--workspace
|
|
181
180
|
<path>` to override the normal workspace resolution. Press Ctrl+C in the
|
|
182
181
|
terminal to stop the server.
|
|
183
182
|
|
|
@@ -191,10 +190,14 @@ The dashboard:
|
|
|
191
190
|
- opens the recorded task directly in Codex when it has a supported UUID thread
|
|
192
191
|
ID, with a project-opening fallback for unresolved or legacy identities.
|
|
193
192
|
|
|
194
|
-
The server binds only to the numeric IPv4 loopback interface
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
The server binds only to the numeric IPv4 loopback interface and rejects
|
|
194
|
+
non-loopback configuration. It intentionally does not authenticate browser
|
|
195
|
+
sessions, so any local process or browser that can reach the port can read the
|
|
196
|
+
dashboard data. Keep the server running only while needed and do not expose it
|
|
197
|
+
through a proxy or tunnel. State-changing actions still require an exact Host
|
|
198
|
+
and same-origin request. The server validates the same task schema as the CLI,
|
|
199
|
+
retains its last valid snapshot if the log becomes invalid, and never writes
|
|
200
|
+
dispatcher-workspace files. It limits event
|
|
198
201
|
streams and disconnects slow clients instead of buffering snapshots without
|
|
199
202
|
bound. It watches the workspace directory
|
|
200
203
|
so TaskChef's atomic log replacement remains visible, uses a low-frequency file
|
package/package.json
CHANGED
package/src/dashboard.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomBytes } from "node:crypto";
|
|
2
1
|
import { EventEmitter } from "node:events";
|
|
3
2
|
import { constants, watch } from "node:fs";
|
|
4
3
|
import { open, readFile, realpath, stat } from "node:fs/promises";
|
|
@@ -383,14 +382,6 @@ export function createSseClient(response, {
|
|
|
383
382
|
return client;
|
|
384
383
|
}
|
|
385
384
|
|
|
386
|
-
function requestSessionCookie(request, cookieName) {
|
|
387
|
-
return request.headers.cookie
|
|
388
|
-
?.split(";")
|
|
389
|
-
.map((part) => part.trim())
|
|
390
|
-
.find((part) => part.startsWith(`${cookieName}=`))
|
|
391
|
-
?.slice(cookieName.length + 1) ?? null;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
385
|
function publicMonitorError() {
|
|
395
386
|
return {
|
|
396
387
|
message: "The task log is temporarily unavailable. Showing the last valid snapshot.",
|
|
@@ -418,10 +409,6 @@ export async function createDashboardServer({
|
|
|
418
409
|
const monitor = new DashboardMonitor(workspace, monitorOptions);
|
|
419
410
|
await monitor.start();
|
|
420
411
|
const clients = new Set();
|
|
421
|
-
const capabilityToken = randomBytes(32).toString("base64url");
|
|
422
|
-
let launchToken = capabilityToken;
|
|
423
|
-
const sessionToken = randomBytes(32).toString("base64url");
|
|
424
|
-
const sessionCookieName = `taskchef_session_${randomBytes(12).toString("hex")}`;
|
|
425
412
|
let allowedAuthority;
|
|
426
413
|
let allowedOrigin;
|
|
427
414
|
|
|
@@ -447,26 +434,6 @@ export async function createDashboardServer({
|
|
|
447
434
|
sendJson(response, 421, { message: "Misdirected request." });
|
|
448
435
|
return;
|
|
449
436
|
}
|
|
450
|
-
const authenticated = requestSessionCookie(request, sessionCookieName) === sessionToken;
|
|
451
|
-
if (
|
|
452
|
-
(method === "GET" || method === "HEAD")
|
|
453
|
-
&& launchToken !== null
|
|
454
|
-
&& url.pathname === "/"
|
|
455
|
-
&& url.searchParams.get("token") === launchToken
|
|
456
|
-
) {
|
|
457
|
-
launchToken = null;
|
|
458
|
-
response.writeHead(303, {
|
|
459
|
-
...securityHeaders("text/plain; charset=utf-8"),
|
|
460
|
-
Location: "/",
|
|
461
|
-
"Set-Cookie": `${sessionCookieName}=${sessionToken}; HttpOnly; SameSite=Strict; Path=/`,
|
|
462
|
-
});
|
|
463
|
-
response.end("Opening TaskChef dashboard.\n");
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
if (!authenticated) {
|
|
467
|
-
sendJson(response, 401, { message: "Dashboard launch capability required." });
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
437
|
if (method !== "GET" && method !== "HEAD" && method !== "POST") {
|
|
471
438
|
response.writeHead(405, { Allow: "GET, HEAD, POST" });
|
|
472
439
|
response.end();
|
|
@@ -514,7 +481,7 @@ export async function createDashboardServer({
|
|
|
514
481
|
const taskMatch = url.pathname.match(/^\/api\/tasks\/([a-zA-Z0-9._-]+)\/open-codex$/);
|
|
515
482
|
if (taskMatch && method === "POST") {
|
|
516
483
|
if (request.headers.origin !== allowedOrigin) {
|
|
517
|
-
sendJson(response, 403, { message: "Dashboard
|
|
484
|
+
sendJson(response, 403, { message: "Dashboard origin validation failed." });
|
|
518
485
|
return;
|
|
519
486
|
}
|
|
520
487
|
const task = monitor.tasks.find((candidate) => candidate.id === taskMatch[1]);
|
|
@@ -600,7 +567,7 @@ export async function createDashboardServer({
|
|
|
600
567
|
host,
|
|
601
568
|
port: boundPort,
|
|
602
569
|
origin: allowedOrigin,
|
|
603
|
-
url: `${allowedOrigin}
|
|
570
|
+
url: `${allowedOrigin}/`,
|
|
604
571
|
monitor,
|
|
605
572
|
get eventClientCount() { return clients.size; },
|
|
606
573
|
async close() {
|