@treeseed/sdk 0.12.11 → 0.12.12
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/workflow/operations.js +4 -1
- package/dist/workflow/runs.js +87 -2
- package/package.json +1 -1
|
@@ -2455,7 +2455,10 @@ async function fetchJsonForArtifact(url) {
|
|
|
2455
2455
|
const timeout = setTimeout(() => controller.abort(), 2e4);
|
|
2456
2456
|
try {
|
|
2457
2457
|
const response = await fetch(url, {
|
|
2458
|
-
headers: {
|
|
2458
|
+
headers: {
|
|
2459
|
+
accept: "application/json",
|
|
2460
|
+
"user-agent": "treeseed-release-verifier/1.0 (https://treeseed.dev)"
|
|
2461
|
+
},
|
|
2459
2462
|
signal: controller.signal
|
|
2460
2463
|
});
|
|
2461
2464
|
let json = null;
|
package/dist/workflow/runs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { hostname } from "node:os";
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
const WORKFLOW_CONTROL_DIR = ".treeseed/workflow";
|
|
@@ -226,6 +226,80 @@ function writeWorkflowRunJournal(root, journal) {
|
|
|
226
226
|
function readWorkflowRunJournal(root, runId) {
|
|
227
227
|
return safeJsonParse(workflowRunPath(root, runId));
|
|
228
228
|
}
|
|
229
|
+
function jsonStringField(source, key) {
|
|
230
|
+
const pattern = new RegExp(`"${key}"\\s*:\\s*"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"`, "u");
|
|
231
|
+
const match = source.match(pattern);
|
|
232
|
+
if (!match) return null;
|
|
233
|
+
try {
|
|
234
|
+
return JSON.parse(`"${match[1]}"`);
|
|
235
|
+
} catch {
|
|
236
|
+
return match[1];
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function jsonBooleanField(source, key) {
|
|
240
|
+
const pattern = new RegExp(`"${key}"\\s*:\\s*(true|false)`, "u");
|
|
241
|
+
const match = source.match(pattern);
|
|
242
|
+
return match ? match[1] === "true" : null;
|
|
243
|
+
}
|
|
244
|
+
function readFileEnds(path, bytes) {
|
|
245
|
+
const fd = openSync(path, "r");
|
|
246
|
+
try {
|
|
247
|
+
const stat = fstatSync(fd);
|
|
248
|
+
const headLength = Math.min(bytes, stat.size);
|
|
249
|
+
const tailLength = Math.min(bytes, stat.size);
|
|
250
|
+
const head = Buffer.alloc(headLength);
|
|
251
|
+
const tail = Buffer.alloc(tailLength);
|
|
252
|
+
readSync(fd, head, 0, headLength, 0);
|
|
253
|
+
readSync(fd, tail, 0, tailLength, Math.max(0, stat.size - tailLength));
|
|
254
|
+
return { size: stat.size, head: head.toString("utf8"), tail: tail.toString("utf8") };
|
|
255
|
+
} finally {
|
|
256
|
+
closeSync(fd);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function archivedWorkflowRunSummary(path) {
|
|
260
|
+
const { head, tail } = readFileEnds(path, 128 * 1024);
|
|
261
|
+
if (!tail.includes('"archivedAt"')) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const runId = jsonStringField(head, "runId");
|
|
265
|
+
const command = jsonStringField(head, "command");
|
|
266
|
+
const executionMode = jsonStringField(head, "executionMode");
|
|
267
|
+
const status = jsonStringField(head, "status");
|
|
268
|
+
const createdAt = jsonStringField(head, "createdAt");
|
|
269
|
+
const updatedAt = jsonStringField(head, "updatedAt");
|
|
270
|
+
const archivedAt = jsonStringField(tail, "archivedAt");
|
|
271
|
+
const classifiedAt = jsonStringField(tail, "classifiedAt") ?? archivedAt;
|
|
272
|
+
if (!runId || !command || !executionMode || !status || !createdAt || !updatedAt || !archivedAt || !classifiedAt) {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
schemaVersion: 1,
|
|
277
|
+
kind: "treeseed.workflow.run",
|
|
278
|
+
runId,
|
|
279
|
+
command,
|
|
280
|
+
executionMode,
|
|
281
|
+
status,
|
|
282
|
+
createdAt,
|
|
283
|
+
updatedAt,
|
|
284
|
+
resumable: jsonBooleanField(head, "resumable") ?? false,
|
|
285
|
+
input: {},
|
|
286
|
+
session: {
|
|
287
|
+
root: "",
|
|
288
|
+
mode: "root-only",
|
|
289
|
+
branchName: null,
|
|
290
|
+
repos: []
|
|
291
|
+
},
|
|
292
|
+
steps: [],
|
|
293
|
+
failure: null,
|
|
294
|
+
result: null,
|
|
295
|
+
classification: {
|
|
296
|
+
state: "obsolete",
|
|
297
|
+
reasons: ["workflow run was archived"],
|
|
298
|
+
classifiedAt,
|
|
299
|
+
archivedAt
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
229
303
|
function updateWorkflowRunJournal(root, runId, updater) {
|
|
230
304
|
const current = readWorkflowRunJournal(root, runId);
|
|
231
305
|
if (!current) {
|
|
@@ -480,7 +554,18 @@ function listWorkflowRunJournalsForScope(root, scope) {
|
|
|
480
554
|
if (!existsSync(runsDir)) {
|
|
481
555
|
return [];
|
|
482
556
|
}
|
|
483
|
-
return readdirSync(runsDir).filter((entry) => entry.endsWith(".json")).map((entry) =>
|
|
557
|
+
return readdirSync(runsDir).filter((entry) => entry.endsWith(".json")).map((entry) => {
|
|
558
|
+
const path = resolve(runsDir, entry);
|
|
559
|
+
try {
|
|
560
|
+
if (statSync(path).size > 5 * 1024 * 1024) {
|
|
561
|
+
const archivedSummary = archivedWorkflowRunSummary(path);
|
|
562
|
+
if (archivedSummary) return archivedSummary;
|
|
563
|
+
}
|
|
564
|
+
} catch {
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
return safeJsonParse(path);
|
|
568
|
+
}).filter((entry) => entry != null).sort((left, right) => right.createdAt.localeCompare(left.createdAt));
|
|
484
569
|
}
|
|
485
570
|
function listWorkflowRunJournals(root) {
|
|
486
571
|
const local = listWorkflowRunJournalsForScope(root, "worktree");
|