@rubytech/taskmaster 1.26.0 → 1.26.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/dist/build-info.json +3 -3
- package/dist/control-ui/assets/{index-C1r0QazL.js → index-1WwUK7EM.js} +109 -103
- package/dist/control-ui/assets/index-1WwUK7EM.js.map +1 -0
- package/dist/control-ui/index.html +1 -1
- package/dist/gateway/logs-download-http.js +67 -0
- package/dist/gateway/protocol/schema/logs-chat.js +2 -2
- package/dist/gateway/server-http.js +3 -0
- package/dist/gateway/server-methods/logs.js +1 -1
- package/package.json +1 -1
- package/dist/control-ui/assets/index-C1r0QazL.js.map +0 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>Taskmaster Control</title>
|
|
7
7
|
<meta name="color-scheme" content="dark light" />
|
|
8
8
|
<link rel="icon" type="image/png" href="./favicon.png" />
|
|
9
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
+
<script type="module" crossorigin src="./assets/index-1WwUK7EM.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="./assets/index-C7ieCeTV.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getResolvedLoggerSettings } from "../logging.js";
|
|
4
|
+
import { loadConfig } from "../config/config.js";
|
|
5
|
+
import { isMasterSession } from "./server-methods/access.js";
|
|
6
|
+
const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
7
|
+
function todayLocal() {
|
|
8
|
+
const d = new Date();
|
|
9
|
+
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* GET /logs/download?date=YYYY-MM-DD&token=...
|
|
13
|
+
*
|
|
14
|
+
* Serves the raw log file as a download. Requires admin (master PIN) session
|
|
15
|
+
* when a master PIN is configured.
|
|
16
|
+
*/
|
|
17
|
+
export function handleLogDownloadRequest(req, res) {
|
|
18
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
19
|
+
if (url.pathname !== "/logs/download" || req.method !== "GET")
|
|
20
|
+
return false;
|
|
21
|
+
// Auth: require master session when a master PIN is set.
|
|
22
|
+
const config = loadConfig();
|
|
23
|
+
const hasMasterPin = Boolean(config.access?.masterPin);
|
|
24
|
+
if (hasMasterPin) {
|
|
25
|
+
const token = url.searchParams.get("token");
|
|
26
|
+
if (!token || !isMasterSession(token)) {
|
|
27
|
+
res.statusCode = 403;
|
|
28
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
29
|
+
res.end("Forbidden: admin login required");
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const dateParam = url.searchParams.get("date");
|
|
34
|
+
const date = dateParam && DATE_RE.test(dateParam) ? dateParam : todayLocal();
|
|
35
|
+
const logDir = path.dirname(getResolvedLoggerSettings().file);
|
|
36
|
+
const file = path.join(logDir, `taskmaster-${date}.log`);
|
|
37
|
+
try {
|
|
38
|
+
const stat = fs.statSync(file);
|
|
39
|
+
if (!stat.isFile()) {
|
|
40
|
+
res.statusCode = 404;
|
|
41
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
42
|
+
res.end("Log file not found");
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
res.statusCode = 200;
|
|
46
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
47
|
+
res.setHeader("Content-Disposition", `attachment; filename="taskmaster-${date}.log"`);
|
|
48
|
+
res.setHeader("Content-Length", stat.size);
|
|
49
|
+
const stream = fs.createReadStream(file);
|
|
50
|
+
stream.pipe(res);
|
|
51
|
+
stream.on("error", () => {
|
|
52
|
+
if (!res.headersSent) {
|
|
53
|
+
res.statusCode = 500;
|
|
54
|
+
res.end("Read error");
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
res.end();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
res.statusCode = 404;
|
|
63
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
64
|
+
res.end("Log file not found");
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
@@ -2,8 +2,8 @@ import { Type } from "@sinclair/typebox";
|
|
|
2
2
|
import { NonEmptyString } from "./primitives.js";
|
|
3
3
|
export const LogsTailParamsSchema = Type.Object({
|
|
4
4
|
cursor: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
5
|
-
limit: Type.Optional(Type.Integer({ minimum: 1, maximum:
|
|
6
|
-
maxBytes: Type.Optional(Type.Integer({ minimum: 1, maximum:
|
|
5
|
+
limit: Type.Optional(Type.Integer({ minimum: 1, maximum: 50_000 })),
|
|
6
|
+
maxBytes: Type.Optional(Type.Integer({ minimum: 1, maximum: 10_000_000 })),
|
|
7
7
|
minLevel: Type.Optional(Type.Union([
|
|
8
8
|
Type.Literal("fatal"),
|
|
9
9
|
Type.Literal("error"),
|
|
@@ -15,6 +15,7 @@ import { extractHookToken, getHookChannelError, normalizeAgentPayload, normalize
|
|
|
15
15
|
import { applyHookMappings } from "./hooks-mapping.js";
|
|
16
16
|
import { handleOpenAiHttpRequest } from "./openai-http.js";
|
|
17
17
|
import { handleOpenResponsesHttpRequest } from "./openresponses-http.js";
|
|
18
|
+
import { handleLogDownloadRequest } from "./logs-download-http.js";
|
|
18
19
|
import { handleMediaRequest } from "./media-http.js";
|
|
19
20
|
import { handleToolsInvokeHttpRequest } from "./tools-invoke-http.js";
|
|
20
21
|
function sendJson(res, status, body) {
|
|
@@ -248,6 +249,8 @@ export function createGatewayHttpServer(opts) {
|
|
|
248
249
|
}
|
|
249
250
|
}
|
|
250
251
|
}
|
|
252
|
+
if (handleLogDownloadRequest(req, res))
|
|
253
|
+
return;
|
|
251
254
|
if (await handleHooksRequest(req, res))
|
|
252
255
|
return;
|
|
253
256
|
if (await handleToolsInvokeHttpRequest(req, res, {
|
|
@@ -8,7 +8,7 @@ import { ErrorCodes, errorShape, formatValidationErrors, validateLogsTailParams,
|
|
|
8
8
|
import { isMasterSession } from "./access.js";
|
|
9
9
|
const CONTROL_UI_CLIENT_ID = "taskmaster-control-ui";
|
|
10
10
|
const DEFAULT_LIMIT = 5000;
|
|
11
|
-
const DEFAULT_MAX_BYTES =
|
|
11
|
+
const DEFAULT_MAX_BYTES = 5_000_000;
|
|
12
12
|
const MAX_LIMIT = 50_000;
|
|
13
13
|
const MAX_BYTES = 10_000_000;
|
|
14
14
|
const ROLLING_LOG_RE = /^taskmaster-\d{4}-\d{2}-\d{2}\.log$/;
|