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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "5.11.1",
3
+ "version": "5.11.2",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
package/README.md CHANGED
@@ -174,10 +174,9 @@ executors report results:
174
174
  taskchef dashboard
175
175
  ```
176
176
 
177
- Open the printed capability URL, which starts with `http://127.0.0.1:3210` and
178
- contains a one-time launch token. Do not share it: the browser exchanges it for
179
- a local session cookie before loading task data, then removes the token from the
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, requires the
195
- unguessable launch capability before serving instructions or results, validates
196
- the same task schema as the CLI, retains its last valid snapshot if the log
197
- becomes invalid, and never writes dispatcher-workspace files. It limits event
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "5.11.1",
3
+ "version": "5.11.2",
4
4
  "description": "A non-blocking interactive dispatcher for visible Codex tasks.",
5
5
  "license": "MIT",
6
6
  "author": "Favo Yang",
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 session validation failed." });
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}/?token=${encodeURIComponent(capabilityToken)}`,
570
+ url: `${allowedOrigin}/`,
604
571
  monitor,
605
572
  get eventClientCount() { return clients.size; },
606
573
  async close() {