From dbb7885ffde67fd5d5ee3a6119886cd20e968317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E6=9C=88?= Date: Thu, 4 Jun 2026 16:45:45 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20fix=20biome=20check=20errors=20(40=20?= =?UTF-8?q?=E2=86=92=200)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Auto-fix: import sorting, formatting (17 files) - Unsafe auto-fix: unused vars, template literals (7 files) - Manual: nursery/noConsole → suspicious/noConsole suppression - Manual: suppress noExcessiveCognitiveComplexity for cmdThreadResume and parseWorkflowPayload - Manual: remove unused destructured vars in current-role tests Closes #48 --- .../agent-builtin/__tests__/detail.test.ts | 2 +- .../agent-builtin/__tests__/read-file.test.ts | 66 +++++++++---------- .../__tests__/run-command.test.ts | 54 +++++++-------- .../agent-builtin/__tests__/session.test.ts | 2 +- .../__tests__/write-file.test.ts | 56 ++++++++-------- .../cli/src/__tests__/current-role.test.ts | 19 ++---- .../src/__tests__/thread-list-filters.test.ts | 4 +- .../cli/src/__tests__/thread-resume.test.ts | 6 +- .../src/__tests__/thread-show-status.test.ts | 13 ++-- packages/cli/src/commands/thread.ts | 13 ++-- packages/cli/src/store.ts | 11 +--- packages/cli/src/validate.ts | 1 + packages/protocol/src/thread-index.ts | 12 +++- .../__tests__/run-parseArgv.test.ts | 29 ++++++-- packages/util-agent/__tests__/storage.test.ts | 31 +++++---- packages/util/__tests__/base32.test.ts | 6 +- packages/util/__tests__/log-tag.test.ts | 50 +++++++------- packages/util/__tests__/refs-field.test.ts | 36 +++++----- packages/util/__tests__/result.test.ts | 38 +++++------ packages/util/__tests__/storage-root.test.ts | 30 +++++---- 20 files changed, 244 insertions(+), 235 deletions(-) diff --git a/packages/agent-builtin/__tests__/detail.test.ts b/packages/agent-builtin/__tests__/detail.test.ts index bf91d32..6a330c6 100644 --- a/packages/agent-builtin/__tests__/detail.test.ts +++ b/packages/agent-builtin/__tests__/detail.test.ts @@ -1,8 +1,8 @@ import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { afterEach, beforeEach, describe, expect, test } from "vitest"; import { createMemoryStore } from "@ocas/core"; +import { afterEach, beforeEach, describe, expect, test } from "vitest"; import { storeBuiltinDetail } from "../src/detail.js"; import { appendSessionTurn, initSessionDir } from "../src/session.js"; import type { BuiltinTurnPayload } from "../src/types.js"; diff --git a/packages/agent-builtin/__tests__/read-file.test.ts b/packages/agent-builtin/__tests__/read-file.test.ts index aae8ef9..16ddaa1 100644 --- a/packages/agent-builtin/__tests__/read-file.test.ts +++ b/packages/agent-builtin/__tests__/read-file.test.ts @@ -1,51 +1,51 @@ -import { describe, it, expect, beforeAll, afterAll } from "vitest"; -import { readFileTool } from "../src/tools/read-file.js"; -import { writeFile, mkdir, rm } from "node:fs/promises"; -import { join } from "node:path"; +import { mkdir, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { readFileTool } from "../src/tools/read-file.js"; const testDir = join(tmpdir(), `read-file-test-${Date.now()}`); const ctx = { cwd: testDir, storageRoot: testDir }; beforeAll(async () => { - await mkdir(testDir, { recursive: true }); - await writeFile(join(testDir, "hello.txt"), "hello world", "utf8"); + await mkdir(testDir, { recursive: true }); + await writeFile(join(testDir, "hello.txt"), "hello world", "utf8"); }); afterAll(async () => { - await rm(testDir, { recursive: true, force: true }); + await rm(testDir, { recursive: true, force: true }); }); describe("readFileTool", () => { - it("reads a file successfully", async () => { - const result = await readFileTool.execute({ path: "hello.txt" }, ctx); - expect(result).toBe("hello world"); - }); + it("reads a file successfully", async () => { + const result = await readFileTool.execute({ path: "hello.txt" }, ctx); + expect(result).toBe("hello world"); + }); - it("returns error for non-existent file", async () => { - const result = await readFileTool.execute({ path: "nope.txt" }, ctx); - expect(result).toMatch(/^Error:/); - }); + it("returns error for non-existent file", async () => { + const result = await readFileTool.execute({ path: "nope.txt" }, ctx); + expect(result).toMatch(/^Error:/); + }); - it("returns error for directory", async () => { - const result = await readFileTool.execute({ path: "." }, ctx); - expect(result).toBe("Error: not a file"); - }); + it("returns error for directory", async () => { + const result = await readFileTool.execute({ path: "." }, ctx); + expect(result).toBe("Error: not a file"); + }); - it("returns error when path is not a string", async () => { - const result = await readFileTool.execute({ path: 123 }, ctx); - expect(result).toBe("Error: path must be a string"); - }); + it("returns error when path is not a string", async () => { + const result = await readFileTool.execute({ path: 123 }, ctx); + expect(result).toBe("Error: path must be a string"); + }); - it("returns error when args is null", async () => { - const result = await readFileTool.execute(null, ctx); - expect(result).toBe("Error: path must be a string"); - }); + it("returns error when args is null", async () => { + const result = await readFileTool.execute(null, ctx); + expect(result).toBe("Error: path must be a string"); + }); - it("returns error for file exceeding 512KB limit", async () => { - const bigFile = join(testDir, "big.txt"); - await writeFile(bigFile, Buffer.alloc(512 * 1024 + 1, 65)); - const result = await readFileTool.execute({ path: "big.txt" }, ctx); - expect(result).toMatch(/Error:.*limit/); - }); + it("returns error for file exceeding 512KB limit", async () => { + const bigFile = join(testDir, "big.txt"); + await writeFile(bigFile, Buffer.alloc(512 * 1024 + 1, 65)); + const result = await readFileTool.execute({ path: "big.txt" }, ctx); + expect(result).toMatch(/Error:.*limit/); + }); }); diff --git a/packages/agent-builtin/__tests__/run-command.test.ts b/packages/agent-builtin/__tests__/run-command.test.ts index 7573063..9e7f31d 100644 --- a/packages/agent-builtin/__tests__/run-command.test.ts +++ b/packages/agent-builtin/__tests__/run-command.test.ts @@ -1,38 +1,38 @@ -import { describe, it, expect } from "vitest"; -import { runCommandTool } from "../src/tools/run-command.js"; import { tmpdir } from "node:os"; +import { describe, expect, it } from "vitest"; +import { runCommandTool } from "../src/tools/run-command.js"; const ctx = { cwd: tmpdir(), storageRoot: tmpdir() }; describe("runCommandTool", () => { - it("runs echo command and checks stdout", async () => { - const result = await runCommandTool.execute({ command: "echo hello" }, ctx); - expect(result).toContain("hello"); - expect(result).toContain("stdout"); - }); + it("runs echo command and checks stdout", async () => { + const result = await runCommandTool.execute({ command: "echo hello" }, ctx); + expect(result).toContain("hello"); + expect(result).toContain("stdout"); + }); - it("returns exit code", async () => { - const result = await runCommandTool.execute({ command: "exit 0" }, ctx); - expect(result).toContain("exit_code: 0"); - }); + it("returns exit code", async () => { + const result = await runCommandTool.execute({ command: "exit 0" }, ctx); + expect(result).toContain("exit_code: 0"); + }); - it("returns non-zero exit code", async () => { - const result = await runCommandTool.execute({ command: "exit 42" }, ctx); - expect(result).toContain("exit_code: 42"); - }); + it("returns non-zero exit code", async () => { + const result = await runCommandTool.execute({ command: "exit 42" }, ctx); + expect(result).toContain("exit_code: 42"); + }); - it("returns error when command is not a string", async () => { - const result = await runCommandTool.execute({ command: 123 }, ctx); - expect(result).toBe("Error: command must be a string"); - }); + it("returns error when command is not a string", async () => { + const result = await runCommandTool.execute({ command: 123 }, ctx); + expect(result).toBe("Error: command must be a string"); + }); - it("returns error when args is null", async () => { - const result = await runCommandTool.execute(null, ctx); - expect(result).toBe("Error: command must be a string"); - }); + it("returns error when args is null", async () => { + const result = await runCommandTool.execute(null, ctx); + expect(result).toBe("Error: command must be a string"); + }); - it("custom cwd works", async () => { - const result = await runCommandTool.execute({ command: "pwd", cwd: "/tmp" }, ctx); - expect(result).toContain("/tmp"); - }); + it("custom cwd works", async () => { + const result = await runCommandTool.execute({ command: "pwd", cwd: "/tmp" }, ctx); + expect(result).toContain("/tmp"); + }); }); diff --git a/packages/agent-builtin/__tests__/session.test.ts b/packages/agent-builtin/__tests__/session.test.ts index e32c741..24d60a7 100644 --- a/packages/agent-builtin/__tests__/session.test.ts +++ b/packages/agent-builtin/__tests__/session.test.ts @@ -3,13 +3,13 @@ import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, test } from "vitest"; -import type { BuiltinTurnPayload } from "../src/types.js"; import { appendSessionTurn, initSessionDir, readSessionTurns, removeSession, } from "../src/session.js"; +import type { BuiltinTurnPayload } from "../src/types.js"; describe("session", () => { let storageRoot: string; diff --git a/packages/agent-builtin/__tests__/write-file.test.ts b/packages/agent-builtin/__tests__/write-file.test.ts index 0b064f2..4a7febd 100644 --- a/packages/agent-builtin/__tests__/write-file.test.ts +++ b/packages/agent-builtin/__tests__/write-file.test.ts @@ -1,43 +1,43 @@ -import { describe, it, expect, afterAll } from "vitest"; -import { writeFileTool } from "../src/tools/write-file.js"; import { readFile, rm } from "node:fs/promises"; -import { join } from "node:path"; import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterAll, describe, expect, it } from "vitest"; +import { writeFileTool } from "../src/tools/write-file.js"; const testDir = join(tmpdir(), `write-file-test-${Date.now()}`); const ctx = { cwd: testDir, storageRoot: testDir }; afterAll(async () => { - await rm(testDir, { recursive: true, force: true }); + await rm(testDir, { recursive: true, force: true }); }); describe("writeFileTool", () => { - it("writes file successfully", async () => { - const result = await writeFileTool.execute({ path: "out.txt", content: "hi" }, ctx); - expect(result).toMatch(/Wrote 2 bytes/); - const content = await readFile(join(testDir, "out.txt"), "utf8"); - expect(content).toBe("hi"); - }); + it("writes file successfully", async () => { + const result = await writeFileTool.execute({ path: "out.txt", content: "hi" }, ctx); + expect(result).toMatch(/Wrote 2 bytes/); + const content = await readFile(join(testDir, "out.txt"), "utf8"); + expect(content).toBe("hi"); + }); - it("creates parent directories", async () => { - const result = await writeFileTool.execute({ path: "a/b/c.txt", content: "nested" }, ctx); - expect(result).toMatch(/Wrote/); - const content = await readFile(join(testDir, "a/b/c.txt"), "utf8"); - expect(content).toBe("nested"); - }); + it("creates parent directories", async () => { + const result = await writeFileTool.execute({ path: "a/b/c.txt", content: "nested" }, ctx); + expect(result).toMatch(/Wrote/); + const content = await readFile(join(testDir, "a/b/c.txt"), "utf8"); + expect(content).toBe("nested"); + }); - it("returns error when path is not a string", async () => { - const result = await writeFileTool.execute({ path: 123, content: "x" }, ctx); - expect(result).toBe("Error: path and content must be strings"); - }); + it("returns error when path is not a string", async () => { + const result = await writeFileTool.execute({ path: 123, content: "x" }, ctx); + expect(result).toBe("Error: path and content must be strings"); + }); - it("returns error when content is not a string", async () => { - const result = await writeFileTool.execute({ path: "x.txt", content: 42 }, ctx); - expect(result).toBe("Error: path and content must be strings"); - }); + it("returns error when content is not a string", async () => { + const result = await writeFileTool.execute({ path: "x.txt", content: 42 }, ctx); + expect(result).toBe("Error: path and content must be strings"); + }); - it("returns error when args is null", async () => { - const result = await writeFileTool.execute(null, ctx); - expect(result).toBe("Error: path and content must be strings"); - }); + it("returns error when args is null", async () => { + const result = await writeFileTool.execute(null, ctx); + expect(result).toBe("Error: path and content must be strings"); + }); }); diff --git a/packages/cli/src/__tests__/current-role.test.ts b/packages/cli/src/__tests__/current-role.test.ts index 369ae24..310a1aa 100644 --- a/packages/cli/src/__tests__/current-role.test.ts +++ b/packages/cli/src/__tests__/current-role.test.ts @@ -6,12 +6,7 @@ import type { CasRef, ThreadId } from "@united-workforce/protocol"; import { describe, expect, test } from "vitest"; import { createMarker, deleteMarker } from "../background/index.js"; import { cmdThreadList, cmdThreadShow, cmdThreadStart } from "../commands/thread.js"; -import { - completeThread, - createUwfStore, - loadActiveThreads, - setThread, -} from "../store.js"; +import { completeThread, createUwfStore, loadActiveThreads, setThread } from "../store.js"; const OUTPUT_SCHEMA = { type: "object" as const, @@ -287,11 +282,11 @@ describe("currentRole field", () => { try { const wf = join(tmpDir, "test-current-role.yaml"); await writeFile(wf, SIMPLE_WORKFLOW_YAML, "utf8"); - const { thread, workflow } = await cmdThreadStart(storageRoot, wf, "test", tmpDir); + const { thread } = await cmdThreadStart(storageRoot, wf, "test", tmpDir); const tid = thread as ThreadId; const uwfForIndex = await createUwfStore(storageRoot); - const head = loadActiveThreads(uwfForIndex.varStore)[tid]!.head; + loadActiveThreads(uwfForIndex.varStore)[tid]!.head; completeThread(uwfForIndex.varStore, tid, "completed"); const result = await cmdThreadShow(storageRoot, tid); @@ -308,11 +303,11 @@ describe("currentRole field", () => { try { const wf = join(tmpDir, "test-current-role.yaml"); await writeFile(wf, SIMPLE_WORKFLOW_YAML, "utf8"); - const { thread, workflow } = await cmdThreadStart(storageRoot, wf, "test", tmpDir); + const { thread } = await cmdThreadStart(storageRoot, wf, "test", tmpDir); const tid = thread as ThreadId; const uwfForIndex = await createUwfStore(storageRoot); - const head = loadActiveThreads(uwfForIndex.varStore)[tid]!.head; + loadActiveThreads(uwfForIndex.varStore)[tid]!.head; completeThread(uwfForIndex.varStore, tid, "cancelled"); const result = await cmdThreadShow(storageRoot, tid); @@ -329,7 +324,7 @@ describe("currentRole field", () => { try { const wf = join(tmpDir, "test-current-role.yaml"); await writeFile(wf, SIMPLE_WORKFLOW_YAML, "utf8"); - const { thread, workflow } = await cmdThreadStart(storageRoot, wf, "test", tmpDir); + const { thread } = await cmdThreadStart(storageRoot, wf, "test", tmpDir); const tid = thread as ThreadId; await createMarker(storageRoot, { @@ -366,7 +361,7 @@ describe("currentRole field", () => { const comp = await cmdThreadStart(storageRoot, wf, "completed", tmpDir); const compId = comp.thread as ThreadId; const uwfForIndex = await createUwfStore(storageRoot); - const compHead = loadActiveThreads(uwfForIndex.varStore)[compId]!.head; + const _compHead = loadActiveThreads(uwfForIndex.varStore)[compId]!.head; completeThread(uwfForIndex.varStore, compId, "completed"); const list = await cmdThreadList(storageRoot, null, null, null, 0, 100); diff --git a/packages/cli/src/__tests__/thread-list-filters.test.ts b/packages/cli/src/__tests__/thread-list-filters.test.ts index e5b74cc..4e6318a 100644 --- a/packages/cli/src/__tests__/thread-list-filters.test.ts +++ b/packages/cli/src/__tests__/thread-list-filters.test.ts @@ -72,8 +72,8 @@ async function markThreadRunning(storageRoot: string, threadId: ThreadId, workfl async function completeThread( storageRoot: string, threadId: ThreadId, - workflowHash: CasRef, - headHash: CasRef, + _workflowHash: CasRef, + _headHash: CasRef, ) { const uwfIdx = await createUwfStore(storageRoot); completeThreadInStore(uwfIdx.varStore, threadId, "completed"); diff --git a/packages/cli/src/__tests__/thread-resume.test.ts b/packages/cli/src/__tests__/thread-resume.test.ts index 53cf56c..3b8aa9e 100644 --- a/packages/cli/src/__tests__/thread-resume.test.ts +++ b/packages/cli/src/__tests__/thread-resume.test.ts @@ -539,9 +539,9 @@ describe("uwf thread resume - completed threads", () => { const { createUwfStore, getThread } = await import("../store.js"); const verifyUwf = await createUwfStore(tmpDir); const verifyEntry = getThread(verifyUwf.varStore, THREAD_ID); - // biome-ignore lint/nursery/noConsole: test debugging + // biome-ignore lint/suspicious/noConsole: test debugging console.log("Seeded entry status:", verifyEntry?.status); - // biome-ignore lint/nursery/noConsole: test debugging + // biome-ignore lint/suspicious/noConsole: test debugging console.log("Seeded entry:", JSON.stringify(verifyEntry, null, 2)); const promptCapturePath = join(tmpDir, "captured-prompt-completed.txt"); @@ -601,7 +601,7 @@ echo '${adapterJson}' ); if (result.status !== 0) { - // biome-ignore lint/nursery/noConsole: test debugging + // biome-ignore lint/suspicious/noConsole: test debugging console.error("Command failed:", result.stderr); } diff --git a/packages/cli/src/__tests__/thread-show-status.test.ts b/packages/cli/src/__tests__/thread-show-status.test.ts index 18df70e..2a154bb 100644 --- a/packages/cli/src/__tests__/thread-show-status.test.ts +++ b/packages/cli/src/__tests__/thread-show-status.test.ts @@ -6,12 +6,7 @@ import type { CasRef, ThreadId } from "@united-workforce/protocol"; import { describe, expect, test } from "vitest"; import { createMarker, deleteMarker } from "../background/index.js"; import { cmdThreadShow, cmdThreadStart } from "../commands/thread.js"; -import { - completeThread, - createUwfStore, - loadAllThreads, - setThread, -} from "../store.js"; +import { completeThread, createUwfStore, loadAllThreads, setThread } from "../store.js"; const OUTPUT_SCHEMA = { type: "object" as const, @@ -205,7 +200,7 @@ describe("thread show status field", () => { // Create a thread const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir); const threadId = startResult.thread as ThreadId; - const workflow = startResult.workflow; + const _workflow = startResult.workflow; // Get the head hash before moving to history const uwfForIndex = await createUwfStore(storageRoot); @@ -234,7 +229,7 @@ describe("thread show status field", () => { // Create a thread const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir); const threadId = startResult.thread as ThreadId; - const workflow = startResult.workflow; + const _workflow = startResult.workflow; // Get the head hash before moving to history const uwfForIndex = await createUwfStore(storageRoot); @@ -263,7 +258,7 @@ describe("thread show status field", () => { // Create a thread const startResult = await cmdThreadStart(storageRoot, workflowPath, "test prompt", tmpDir); const threadId = startResult.thread as ThreadId; - const workflow = startResult.workflow; + const _workflow = startResult.workflow; // Get the head hash before moving to history const uwfForIndex = await createUwfStore(storageRoot); diff --git a/packages/cli/src/commands/thread.ts b/packages/cli/src/commands/thread.ts index 113f21b..3baa949 100644 --- a/packages/cli/src/commands/thread.ts +++ b/packages/cli/src/commands/thread.ts @@ -1031,6 +1031,7 @@ function archiveThread(uwf: UwfStore, threadId: ThreadId, _workflow: CasRef, _he completeThread(uwf.varStore, threadId, "completed"); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: orchestration function with inherent branching export async function cmdThreadResume( storageRoot: string, threadId: ThreadId, @@ -1057,13 +1058,7 @@ export async function cmdThreadResume( if (entry.status === "completed" || entry.status === "cancelled") { status = entry.status; } else { - status = await resolveActiveThreadStatus( - storageRoot, - threadId, - uwf, - headHash, - workflowHash, - ); + status = await resolveActiveThreadStatus(storageRoot, threadId, uwf, headHash, workflowHash); } if (status !== "suspended" && status !== "completed") { @@ -1278,7 +1273,7 @@ function resolveResumeStepTarget( } async function resolveModeratorStepTarget( - storageRoot: string, + _storageRoot: string, threadId: ThreadId, entry: ThreadIndexEntry, headHash: CasRef, @@ -1347,7 +1342,7 @@ async function resolveModeratorStepTarget( } async function finalizeAgentStep( - storageRoot: string, + _storageRoot: string, threadId: ThreadId, workflowHash: CasRef, workflow: WorkflowPayload, diff --git a/packages/cli/src/store.ts b/packages/cli/src/store.ts index 5e508ef..a45dd5b 100644 --- a/packages/cli/src/store.ts +++ b/packages/cli/src/store.ts @@ -6,13 +6,7 @@ import { join } from "node:path"; import { bootstrap, type Hash, type Store, type VarStore } from "@ocas/core"; import { createFsStore, createSqliteVarStore } from "@ocas/fs"; -import type { - CasRef, - ThreadId, - ThreadIndexEntry, - ThreadListItem, - ThreadsIndex, -} from "@united-workforce/protocol"; +import type { CasRef, ThreadId, ThreadIndexEntry, ThreadsIndex } from "@united-workforce/protocol"; import { parseThreadsIndex } from "@united-workforce/protocol"; import { parse } from "yaml"; @@ -26,7 +20,6 @@ export const REGISTRY_VAR_PREFIX = "@uwf/registry/"; /** Variable name prefix for active thread entries (`@uwf/thread/`). */ export const THREAD_VAR_PREFIX = "@uwf/thread/"; - /** A workflow entry discovered from the project-local .workflows/ directory. */ export type ProjectWorkflowEntry = { /** Workflow name (from YAML `name` field, equals filename stem). */ @@ -154,7 +147,6 @@ export function getThreadsPath(storageRoot: string): string { return join(storageRoot, "threads.yaml"); } - export type UwfStore = { storageRoot: string; store: Store; @@ -387,7 +379,6 @@ export function completeThread( setThread(varStore, threadId, completed); } - type LegacyHistoryEntry = { thread: ThreadId; workflow: CasRef; diff --git a/packages/cli/src/validate.ts b/packages/cli/src/validate.ts index 754f00e..0684321 100644 --- a/packages/cli/src/validate.ts +++ b/packages/cli/src/validate.ts @@ -96,6 +96,7 @@ export function checkWorkflowFilenameConsistency( } /** Validate YAML-parsed workflow document shape (outputSchema may be inline JSON Schema). */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: validation function with many field checks export function parseWorkflowPayload(raw: unknown): WorkflowPayload | null { if (!isRecord(raw)) { return null; diff --git a/packages/protocol/src/thread-index.ts b/packages/protocol/src/thread-index.ts index f5f0720..fc2ceee 100644 --- a/packages/protocol/src/thread-index.ts +++ b/packages/protocol/src/thread-index.ts @@ -21,7 +21,10 @@ export function normalizeThreadIndexEntry(raw: unknown): ThreadIndexEntry | null head: head as CasRef, suspendedRole: typeof suspendedRole === "string" ? suspendedRole : null, suspendMessage: typeof suspendMessage === "string" ? suspendMessage : null, - status: typeof status === "string" ? (status as "idle" | "running" | "suspended" | "completed" | "cancelled") : "idle", + status: + typeof status === "string" + ? (status as "idle" | "running" | "suspended" | "completed" | "cancelled") + : "idle", completedAt: typeof completedAt === "number" ? completedAt : null, }; } @@ -79,7 +82,12 @@ export function serializeThreadIndexEntry( entry: ThreadIndexEntry, ): string | Record { // Compact string only for idle status with no suspend metadata - if (entry.status === "idle" && entry.suspendedRole === null && entry.suspendMessage === null && entry.completedAt === null) { + if ( + entry.status === "idle" && + entry.suspendedRole === null && + entry.suspendMessage === null && + entry.completedAt === null + ) { return entry.head; } diff --git a/packages/util-agent/__tests__/run-parseArgv.test.ts b/packages/util-agent/__tests__/run-parseArgv.test.ts index 0bad04e..3b3f8c4 100644 --- a/packages/util-agent/__tests__/run-parseArgv.test.ts +++ b/packages/util-agent/__tests__/run-parseArgv.test.ts @@ -1,15 +1,15 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { parseArgv } from "../src/run.js"; describe("parseArgv", () => { let exitSpy: ReturnType; - let stderrSpy: ReturnType; + let _stderrSpy: ReturnType; beforeEach(() => { exitSpy = vi.spyOn(process, "exit").mockImplementation((() => { throw new Error("process.exit"); }) as never); - stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation((() => true) as never); + _stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation((() => true) as never); }); afterEach(() => { @@ -17,22 +17,37 @@ describe("parseArgv", () => { }); it("returns threadId, role, prompt for valid argv", () => { - const result = parseArgv(["node", "script", "--thread", "abc123", "--role", "developer", "--prompt", "do stuff"]); + const result = parseArgv([ + "node", + "script", + "--thread", + "abc123", + "--role", + "developer", + "--prompt", + "do stuff", + ]); expect(result).toEqual({ threadId: "abc123", role: "developer", prompt: "do stuff" }); }); it("exits when --thread is missing", () => { - expect(() => parseArgv(["node", "script", "--role", "dev", "--prompt", "x"])).toThrow("process.exit"); + expect(() => parseArgv(["node", "script", "--role", "dev", "--prompt", "x"])).toThrow( + "process.exit", + ); expect(exitSpy).toHaveBeenCalledWith(1); }); it("exits when --role is missing", () => { - expect(() => parseArgv(["node", "script", "--thread", "t1", "--prompt", "x"])).toThrow("process.exit"); + expect(() => parseArgv(["node", "script", "--thread", "t1", "--prompt", "x"])).toThrow( + "process.exit", + ); expect(exitSpy).toHaveBeenCalledWith(1); }); it("exits when --prompt is missing", () => { - expect(() => parseArgv(["node", "script", "--thread", "t1", "--role", "dev"])).toThrow("process.exit"); + expect(() => parseArgv(["node", "script", "--thread", "t1", "--role", "dev"])).toThrow( + "process.exit", + ); expect(exitSpy).toHaveBeenCalledWith(1); }); }); diff --git a/packages/util-agent/__tests__/storage.test.ts b/packages/util-agent/__tests__/storage.test.ts index 1a3fe2f..4b63195 100644 --- a/packages/util-agent/__tests__/storage.test.ts +++ b/packages/util-agent/__tests__/storage.test.ts @@ -1,14 +1,14 @@ import { homedir } from "node:os"; import { join } from "node:path"; -import { describe, it, expect } from "vitest"; +import { describe, expect, it } from "vitest"; import { - resolveStorageRoot, - getDefaultStorageRoot, getCasDir, getConfigPath, + getDefaultStorageRoot, getEnvPath, getGlobalCasDir, normalizeWorkflowConfig, + resolveStorageRoot, } from "../src/storage.js"; const VALID_CONFIG = { @@ -79,28 +79,33 @@ describe("normalizeWorkflowConfig", () => { }); it("throws when defaultAgent missing", () => { - expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, defaultAgent: undefined })) - .toThrow("defaultAgent and defaultModel"); + expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, defaultAgent: undefined })).toThrow( + "defaultAgent and defaultModel", + ); }); it("throws when defaultModel missing", () => { - expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, defaultModel: 42 })) - .toThrow("defaultAgent and defaultModel"); + expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, defaultModel: 42 })).toThrow( + "defaultAgent and defaultModel", + ); }); it("throws on invalid providers entry", () => { - expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, providers: { bad: "string" } })) - .toThrow("config.providers.bad must be a mapping"); + expect(() => + normalizeWorkflowConfig({ ...VALID_CONFIG, providers: { bad: "string" } }), + ).toThrow("config.providers.bad must be a mapping"); }); it("throws on invalid models entry", () => { - expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, models: { m: { provider: 123, name: "x" } } })) - .toThrow("config.models.m requires provider and name"); + expect(() => + normalizeWorkflowConfig({ ...VALID_CONFIG, models: { m: { provider: 123, name: "x" } } }), + ).toThrow("config.models.m requires provider and name"); }); it("throws on invalid agents entry", () => { - expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, agents: "bad" })) - .toThrow("config.agents must be a mapping"); + expect(() => normalizeWorkflowConfig({ ...VALID_CONFIG, agents: "bad" })).toThrow( + "config.agents must be a mapping", + ); }); it("returns null for undefined modelOverrides", () => { diff --git a/packages/util/__tests__/base32.test.ts b/packages/util/__tests__/base32.test.ts index 2d2ba53..add9bb7 100644 --- a/packages/util/__tests__/base32.test.ts +++ b/packages/util/__tests__/base32.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from "vitest"; import { CROCKFORD_BASE32_ALPHABET, - encodeCrockfordBase32Bits, decodeCrockfordBase32Bits, - encodeUint64AsCrockford, decodeCrockfordToUint64, + encodeCrockfordBase32Bits, + encodeUint64AsCrockford, } from "../src/base32.js"; describe("CROCKFORD_BASE32_ALPHABET", () => { @@ -105,7 +105,7 @@ describe("encodeUint64AsCrockford / decodeCrockfordToUint64", () => { }); it("roundtrips arbitrary value", () => { - const value = 0xDEAD_BEEF_CAFE_BABEn; + const value = 0xdead_beef_cafe_baben; const encoded = encodeUint64AsCrockford(value); const decoded = decodeCrockfordToUint64(encoded); expect(decoded).toEqual({ ok: true, value }); diff --git a/packages/util/__tests__/log-tag.test.ts b/packages/util/__tests__/log-tag.test.ts index 7d8cb4b..08c0b2e 100644 --- a/packages/util/__tests__/log-tag.test.ts +++ b/packages/util/__tests__/log-tag.test.ts @@ -1,38 +1,38 @@ -import { describe, it, expect } from 'vitest'; -import { assertValidLogTag } from '../src/process-logger/log-tag.js'; +import { describe, expect, it } from "vitest"; +import { assertValidLogTag } from "../src/process-logger/log-tag.js"; -describe('assertValidLogTag', () => { - it('accepts valid 8-char Crockford Base32 tags', () => { - expect(() => assertValidLogTag('0123ABCD')).not.toThrow(); - expect(() => assertValidLogTag('VWXYZ789')).not.toThrow(); - expect(() => assertValidLogTag('00000000')).not.toThrow(); - expect(() => assertValidLogTag('ZZZZZZZZ')).not.toThrow(); +describe("assertValidLogTag", () => { + it("accepts valid 8-char Crockford Base32 tags", () => { + expect(() => assertValidLogTag("0123ABCD")).not.toThrow(); + expect(() => assertValidLogTag("VWXYZ789")).not.toThrow(); + expect(() => assertValidLogTag("00000000")).not.toThrow(); + expect(() => assertValidLogTag("ZZZZZZZZ")).not.toThrow(); }); - it('accepts lowercase (converted via toUpperCase)', () => { - expect(() => assertValidLogTag('abcdefgh')).not.toThrow(); - expect(() => assertValidLogTag('0a1b2c3d')).not.toThrow(); + it("accepts lowercase (converted via toUpperCase)", () => { + expect(() => assertValidLogTag("abcdefgh")).not.toThrow(); + expect(() => assertValidLogTag("0a1b2c3d")).not.toThrow(); }); - it('throws on too short', () => { - expect(() => assertValidLogTag('1234567')).toThrow(); - expect(() => assertValidLogTag('')).toThrow(); + it("throws on too short", () => { + expect(() => assertValidLogTag("1234567")).toThrow(); + expect(() => assertValidLogTag("")).toThrow(); }); - it('throws on too long', () => { - expect(() => assertValidLogTag('123456789')).toThrow(); + it("throws on too long", () => { + expect(() => assertValidLogTag("123456789")).toThrow(); }); - it('throws on invalid chars I, L, O, U', () => { - expect(() => assertValidLogTag('IIIIIIII')).toThrow(); - expect(() => assertValidLogTag('LLLLLLLL')).toThrow(); - expect(() => assertValidLogTag('OOOOOOOO')).toThrow(); - expect(() => assertValidLogTag('UUUUUUUU')).toThrow(); + it("throws on invalid chars I, L, O, U", () => { + expect(() => assertValidLogTag("IIIIIIII")).toThrow(); + expect(() => assertValidLogTag("LLLLLLLL")).toThrow(); + expect(() => assertValidLogTag("OOOOOOOO")).toThrow(); + expect(() => assertValidLogTag("UUUUUUUU")).toThrow(); }); - it('throws on special characters', () => { - expect(() => assertValidLogTag('1234567!')).toThrow(); - expect(() => assertValidLogTag('ABCD-EFG')).toThrow(); - expect(() => assertValidLogTag('ABCD EFG')).toThrow(); + it("throws on special characters", () => { + expect(() => assertValidLogTag("1234567!")).toThrow(); + expect(() => assertValidLogTag("ABCD-EFG")).toThrow(); + expect(() => assertValidLogTag("ABCD EFG")).toThrow(); }); }); diff --git a/packages/util/__tests__/refs-field.test.ts b/packages/util/__tests__/refs-field.test.ts index 6e3ec8e..569f793 100644 --- a/packages/util/__tests__/refs-field.test.ts +++ b/packages/util/__tests__/refs-field.test.ts @@ -1,40 +1,40 @@ -import { describe, it, expect } from 'vitest'; -import { mergeRefsWithContentHash, normalizeRefsField } from '../src/refs-field.js'; +import { describe, expect, it } from "vitest"; +import { mergeRefsWithContentHash, normalizeRefsField } from "../src/refs-field.js"; -describe('mergeRefsWithContentHash', () => { - it('appends a new content hash', () => { - expect(mergeRefsWithContentHash(['a', 'b'], 'c')).toEqual(['a', 'b', 'c']); +describe("mergeRefsWithContentHash", () => { + it("appends a new content hash", () => { + expect(mergeRefsWithContentHash(["a", "b"], "c")).toEqual(["a", "b", "c"]); }); - it('skips duplicate content hash', () => { - expect(mergeRefsWithContentHash(['a', 'b'], 'b')).toEqual(['a', 'b']); + it("skips duplicate content hash", () => { + expect(mergeRefsWithContentHash(["a", "b"], "b")).toEqual(["a", "b"]); }); - it('preserves order', () => { - expect(mergeRefsWithContentHash(['x', 'y'], 'z')).toEqual(['x', 'y', 'z']); + it("preserves order", () => { + expect(mergeRefsWithContentHash(["x", "y"], "z")).toEqual(["x", "y", "z"]); }); - it('handles empty refs', () => { - expect(mergeRefsWithContentHash([], 'a')).toEqual(['a']); + it("handles empty refs", () => { + expect(mergeRefsWithContentHash([], "a")).toEqual(["a"]); }); }); -describe('normalizeRefsField', () => { - it('returns empty array for non-array', () => { +describe("normalizeRefsField", () => { + it("returns empty array for non-array", () => { expect(normalizeRefsField(null)).toEqual([]); expect(normalizeRefsField(undefined)).toEqual([]); expect(normalizeRefsField(42)).toEqual([]); }); - it('passes through string array', () => { - expect(normalizeRefsField(['a', 'b'])).toEqual(['a', 'b']); + it("passes through string array", () => { + expect(normalizeRefsField(["a", "b"])).toEqual(["a", "b"]); }); - it('filters non-strings from mixed array', () => { - expect(normalizeRefsField(['a', 1, 'b', null])).toEqual(['a', 'b']); + it("filters non-strings from mixed array", () => { + expect(normalizeRefsField(["a", 1, "b", null])).toEqual(["a", "b"]); }); - it('handles empty array', () => { + it("handles empty array", () => { expect(normalizeRefsField([])).toEqual([]); }); }); diff --git a/packages/util/__tests__/result.test.ts b/packages/util/__tests__/result.test.ts index 7ec6977..69e1a4b 100644 --- a/packages/util/__tests__/result.test.ts +++ b/packages/util/__tests__/result.test.ts @@ -1,36 +1,36 @@ -import { describe, it, expect } from 'vitest'; -import { ok, err } from '../src/result.js'; +import { describe, expect, it } from "vitest"; +import { err, ok } from "../src/result.js"; -describe('result', () => { - describe('ok', () => { - it('wraps a value', () => { +describe("result", () => { + describe("ok", () => { + it("wraps a value", () => { const r = ok(42); expect(r).toEqual({ ok: true, value: 42 }); }); - it('wraps a string value', () => { - const r = ok('hello'); + it("wraps a string value", () => { + const r = ok("hello"); expect(r.ok).toBe(true); - if (r.ok) expect(r.value).toBe('hello'); + if (r.ok) expect(r.value).toBe("hello"); }); }); - describe('err', () => { - it('wraps an error', () => { - const r = err('fail'); - expect(r).toEqual({ ok: false, error: 'fail' }); + describe("err", () => { + it("wraps an error", () => { + const r = err("fail"); + expect(r).toEqual({ ok: false, error: "fail" }); }); - it('wraps an Error object', () => { - const e = new Error('boom'); + it("wraps an Error object", () => { + const e = new Error("boom"); const r = err(e); expect(r.ok).toBe(false); if (!r.ok) expect(r.error).toBe(e); }); }); - describe('type narrowing', () => { - it('narrows ok result', () => { + describe("type narrowing", () => { + it("narrows ok result", () => { const r = ok(10) as ReturnType> | ReturnType>; if (r.ok) { expect(r.value).toBe(10); @@ -39,10 +39,10 @@ describe('result', () => { } }); - it('narrows err result', () => { - const r = err('bad') as ReturnType> | ReturnType>; + it("narrows err result", () => { + const r = err("bad") as ReturnType> | ReturnType>; if (!r.ok) { - expect(r.error).toBe('bad'); + expect(r.error).toBe("bad"); } else { expect.unreachable(); } diff --git a/packages/util/__tests__/storage-root.test.ts b/packages/util/__tests__/storage-root.test.ts index 1e60f60..d0b7c44 100644 --- a/packages/util/__tests__/storage-root.test.ts +++ b/packages/util/__tests__/storage-root.test.ts @@ -1,25 +1,29 @@ -import { describe, it, expect } from 'vitest'; -import { homedir } from 'node:os'; -import { getDefaultStorageRoot, getDefaultWorkflowStorageRoot, getGlobalCasDir } from '../src/storage-root.js'; +import { homedir } from "node:os"; +import { describe, expect, it } from "vitest"; +import { + getDefaultStorageRoot, + getDefaultWorkflowStorageRoot, + getGlobalCasDir, +} from "../src/storage-root.js"; -describe('getDefaultStorageRoot', () => { - it('returns homedir + /.uwf', () => { - expect(getDefaultStorageRoot()).toBe(homedir() + '/.uwf'); +describe("getDefaultStorageRoot", () => { + it("returns homedir + /.uwf", () => { + expect(getDefaultStorageRoot()).toBe(`${homedir()}/.uwf`); }); }); -describe('getDefaultWorkflowStorageRoot', () => { - it('returns same as getDefaultStorageRoot (deprecated alias)', () => { +describe("getDefaultWorkflowStorageRoot", () => { + it("returns same as getDefaultStorageRoot (deprecated alias)", () => { expect(getDefaultWorkflowStorageRoot()).toBe(getDefaultStorageRoot()); }); }); -describe('getGlobalCasDir', () => { - it('appends /cas to given storage root', () => { - expect(getGlobalCasDir('/tmp/test')).toBe('/tmp/test/cas'); +describe("getGlobalCasDir", () => { + it("appends /cas to given storage root", () => { + expect(getGlobalCasDir("/tmp/test")).toBe("/tmp/test/cas"); }); - it('falls back to default when undefined', () => { - expect(getGlobalCasDir(undefined)).toBe(homedir() + '/.uwf/cas'); + it("falls back to default when undefined", () => { + expect(getGlobalCasDir(undefined)).toBe(`${homedir()}/.uwf/cas`); }); });