From 7faa8184ae9239ec0b68f1b5d5568d71ed6c2e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Sat, 23 May 2026 06:23:56 +0000 Subject: [PATCH] feat: add uwf log subcommands (list, show, clean) - uwf log list: list log files with sizes - uwf log show --thread : filter by thread ID - uwf log show --process : filter by process ID - uwf log clean --before : delete old log files - Tests: 12 new tests covering all subcommands Implemented by solve-issue workflow, biome fixes applied manually. Closes #413 Refs #411, #410 --- .../cli-workflow/src/__tests__/log.test.ts | 32 +++++++++++++++---- packages/cli-workflow/src/cli.ts | 28 +++++++++------- packages/cli-workflow/src/commands/log.ts | 12 +++---- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/packages/cli-workflow/src/__tests__/log.test.ts b/packages/cli-workflow/src/__tests__/log.test.ts index de4c2c3..75c839c 100644 --- a/packages/cli-workflow/src/__tests__/log.test.ts +++ b/packages/cli-workflow/src/__tests__/log.test.ts @@ -1,6 +1,6 @@ import { mkdir, readdir, rm, writeFile } from "node:fs/promises"; -import { join } from "node:path"; import { tmpdir } from "node:os"; +import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, test } from "vitest"; import { cmdLogClean, cmdLogList, cmdLogShow } from "../commands/log.js"; @@ -95,21 +95,33 @@ describe("cmdLogList", () => { describe("cmdLogShow", () => { test("filters by thread ID", async () => { await writeLogFiles(); - const result = await cmdLogShow(storageRoot, { thread: "01J1234ABCDEF", process: null, date: null }); + const result = await cmdLogShow(storageRoot, { + thread: "01J1234ABCDEF", + process: null, + date: null, + }); expect(result).toHaveLength(2); expect(result.every((e) => e.thread === "01J1234ABCDEF")).toBe(true); }); test("filters by process ID", async () => { await writeLogFiles(); - const result = await cmdLogShow(storageRoot, { thread: null, process: "1716200000000-1234", date: null }); + const result = await cmdLogShow(storageRoot, { + thread: null, + process: "1716200000000-1234", + date: null, + }); expect(result).toHaveLength(2); expect(result.every((e) => e.pid === "1716200000000-1234")).toBe(true); }); test("filters by date", async () => { await writeLogFiles(); - const result = await cmdLogShow(storageRoot, { thread: null, process: null, date: "2026-05-19" }); + const result = await cmdLogShow(storageRoot, { + thread: null, + process: null, + date: "2026-05-19", + }); expect(result).toHaveLength(1); expect(result[0].msg).toBe("old entry"); }); @@ -125,13 +137,21 @@ describe("cmdLogShow", () => { test("returns empty when no matches", async () => { await writeLogFiles(); - const result = await cmdLogShow(storageRoot, { thread: "NONEXISTENT", process: null, date: null }); + const result = await cmdLogShow(storageRoot, { + thread: "NONEXISTENT", + process: null, + date: null, + }); expect(result).toEqual([]); }); test("combined thread + date filter", async () => { await writeLogFiles(); - const result = await cmdLogShow(storageRoot, { thread: "01J1234ABCDEF", process: null, date: "2026-05-20" }); + const result = await cmdLogShow(storageRoot, { + thread: "01J1234ABCDEF", + process: null, + date: "2026-05-20", + }); expect(result).toHaveLength(2); expect(result.every((e) => e.thread === "01J1234ABCDEF")).toBe(true); }); diff --git a/packages/cli-workflow/src/cli.ts b/packages/cli-workflow/src/cli.ts index 9b94ef7..a380e7d 100755 --- a/packages/cli-workflow/src/cli.ts +++ b/packages/cli-workflow/src/cli.ts @@ -14,6 +14,7 @@ import { cmdCasSchemaList, cmdCasWalk, } from "./commands/cas.js"; +import { cmdLogClean, cmdLogList, cmdLogShow } from "./commands/log.js"; import { cmdSetup, cmdSetupInteractive } from "./commands/setup.js"; import { cmdSkillCli } from "./commands/skill.js"; import { @@ -29,7 +30,6 @@ import { THREAD_READ_DEFAULT_QUOTA, } from "./commands/thread.js"; import { cmdWorkflowList, cmdWorkflowPut, cmdWorkflowShow } from "./commands/workflow.js"; -import { cmdLogClean, cmdLogList, cmdLogShow } from "./commands/log.js"; import { formatOutput, type OutputFormat } from "./format.js"; import { resolveStorageRoot } from "./store.js"; @@ -399,17 +399,23 @@ log .option("--thread ", "Filter by thread ID") .option("--process ", "Filter by process ID") .option("--date ", "Filter by date (YYYY-MM-DD)") - .action((opts: { thread: string | undefined; process: string | undefined; date: string | undefined }) => { - const storageRoot = resolveStorageRoot(); - runAction(async () => { - const result = await cmdLogShow(storageRoot, { - thread: opts.thread ?? null, - process: opts.process ?? null, - date: opts.date ?? null, + .action( + (opts: { + thread: string | undefined; + process: string | undefined; + date: string | undefined; + }) => { + const storageRoot = resolveStorageRoot(); + runAction(async () => { + const result = await cmdLogShow(storageRoot, { + thread: opts.thread ?? null, + process: opts.process ?? null, + date: opts.date ?? null, + }); + writeOutput(result); }); - writeOutput(result); - }); - }); + }, + ); log .command("clean") diff --git a/packages/cli-workflow/src/commands/log.ts b/packages/cli-workflow/src/commands/log.ts index 72951d5..df771b6 100644 --- a/packages/cli-workflow/src/commands/log.ts +++ b/packages/cli-workflow/src/commands/log.ts @@ -1,4 +1,4 @@ -import { readFile, readdir, stat, unlink } from "node:fs/promises"; +import { readdir, readFile, stat, unlink } from "node:fs/promises"; import { join } from "node:path"; type LogListItem = { @@ -45,7 +45,10 @@ function dateFromFilename(name: string): string { async function parseJsonlFile(path: string): Promise> { const content = await readFile(path, "utf-8"); - const lines = content.trim().split("\n").filter((l) => l.length > 0); + const lines = content + .trim() + .split("\n") + .filter((l) => l.length > 0); return lines.map((line) => JSON.parse(line) as LogEntry); } @@ -96,10 +99,7 @@ export async function cmdLogShow( return entries; } -export async function cmdLogClean( - storageRoot: string, - before: string, -): Promise { +export async function cmdLogClean(storageRoot: string, before: string): Promise { const dir = logsDir(storageRoot); const files = await listLogFiles(dir); let deleted = 0;