fix(workflow): add typecheck script and fix remaining type errors
- Add typecheck script (bunx tsc --build) to package.json - Update check script to run typecheck before biome - Fix mock fetch casts in test files (bun-types preconnect) - Fix RequestInfo → Request | string | URL in llm-extract test - Fix ThreadContext generic cast in solve-issue-template test - Fix git-exec.ts missing return and module resolution - Remove @types/node from workflow-role-committer - Add exports field to workflow-util-agent/package.json
This commit is contained in:
+2
-1
@@ -7,7 +7,8 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "bun run --filter '*' build",
|
||||
"check": "biome check .",
|
||||
"check": "bunx tsc --build && biome check .",
|
||||
"typecheck": "bunx tsc --build",
|
||||
"format": "biome format --write .",
|
||||
"test": "bun run --filter '*' test"
|
||||
},
|
||||
|
||||
@@ -12,8 +12,5 @@
|
||||
"@uncaged/workflow": "workspace:*",
|
||||
"@uncaged/workflow-util-role": "workspace:*",
|
||||
"zod": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ describe("createLlmAdapter", () => {
|
||||
const originalFetch = globalThis.fetch;
|
||||
|
||||
test("posts system + user (start.content) and returns assistant text", async () => {
|
||||
globalThis.fetch = () =>
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(
|
||||
new Response(JSON.stringify({ choices: [{ message: { content: "model reply" } }] }), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
}),
|
||||
);
|
||||
)) as unknown as typeof fetch;
|
||||
|
||||
const provider = { baseUrl: "https://api.example/v1", apiKey: "k", model: "m" };
|
||||
const adapter = createLlmAdapter(provider);
|
||||
@@ -37,13 +37,13 @@ describe("createLlmAdapter", () => {
|
||||
});
|
||||
|
||||
test("throws on non-ok fetch response", async () => {
|
||||
globalThis.fetch = () =>
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(
|
||||
new Response("Internal Server Error", {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "text/plain" },
|
||||
}),
|
||||
);
|
||||
)) as unknown as typeof fetch;
|
||||
|
||||
const provider = { baseUrl: "https://api.example/v1", apiKey: "k", model: "m" };
|
||||
const adapter = createLlmAdapter(provider);
|
||||
@@ -53,7 +53,7 @@ describe("createLlmAdapter", () => {
|
||||
});
|
||||
|
||||
test("throws on fetch network failure", async () => {
|
||||
globalThis.fetch = () => Promise.reject(new Error("ECONNREFUSED"));
|
||||
globalThis.fetch = (() => Promise.reject(new Error("ECONNREFUSED"))) as unknown as typeof fetch;
|
||||
|
||||
const provider = { baseUrl: "https://api.example/v1", apiKey: "k", model: "m" };
|
||||
const adapter = createLlmAdapter(provider);
|
||||
|
||||
@@ -50,7 +50,10 @@ describe("createReviewerRole", () => {
|
||||
});
|
||||
|
||||
test("runs reviewer extract", async () => {
|
||||
globalThis.fetch = () => Promise.resolve(toolCallResponse(JSON.stringify({ approved: true })));
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(
|
||||
toolCallResponse(JSON.stringify({ approved: true })),
|
||||
)) as unknown as typeof fetch;
|
||||
|
||||
const agent: AgentFn = async (_ctx, prompt) => {
|
||||
expect(prompt).toContain("git diff");
|
||||
@@ -68,7 +71,10 @@ describe("createReviewerRole", () => {
|
||||
});
|
||||
|
||||
test("includes uncaged-workflow thread hint when threadId set", async () => {
|
||||
globalThis.fetch = () => Promise.resolve(toolCallResponse(JSON.stringify({ approved: false })));
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(
|
||||
toolCallResponse(JSON.stringify({ approved: false })),
|
||||
)) as unknown as typeof fetch;
|
||||
|
||||
let seen = "";
|
||||
const agent: AgentFn = async (_ctx, prompt) => {
|
||||
|
||||
@@ -115,7 +115,7 @@ describe("createSolveIssueRoles", () => {
|
||||
expect(typeof roles.committer).toBe("function");
|
||||
|
||||
const ctx = makeCtx(10, []);
|
||||
const plannerOut = await roles.planner(ctx);
|
||||
const plannerOut = await roles.planner(ctx as unknown as ThreadContext);
|
||||
expect(plannerOut.meta.plan).toBe("");
|
||||
expect(Array.isArray(plannerOut.meta.files)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
"type": "module",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./src/index.ts",
|
||||
"default": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "echo 'TODO'",
|
||||
"test": "bun test"
|
||||
|
||||
@@ -55,7 +55,8 @@ describe("createRole", () => {
|
||||
});
|
||||
|
||||
test("runs AgentFn then structured extract", async () => {
|
||||
globalThis.fetch = () => Promise.resolve(toolCallResponse(JSON.stringify({ n: 3 })));
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(toolCallResponse(JSON.stringify({ n: 3 })))) as unknown as typeof fetch;
|
||||
|
||||
const schema = z.object({ n: z.number() });
|
||||
const agent: AgentFn = async (_ctx, prompt) => prompt;
|
||||
@@ -73,7 +74,8 @@ describe("createRole", () => {
|
||||
});
|
||||
|
||||
test("passes ThreadContext to AgentFn", async () => {
|
||||
globalThis.fetch = () => Promise.resolve(toolCallResponse(JSON.stringify({ n: 0 })));
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(toolCallResponse(JSON.stringify({ n: 0 })))) as unknown as typeof fetch;
|
||||
|
||||
const seen: ThreadContext[] = [];
|
||||
const agent: AgentFn = async (ctx, _prompt) => {
|
||||
@@ -94,7 +96,8 @@ describe("createRole", () => {
|
||||
});
|
||||
|
||||
test("resolves dynamic systemPrompt functions before AgentFn", async () => {
|
||||
globalThis.fetch = () => Promise.resolve(toolCallResponse(JSON.stringify({ n: 99 })));
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(toolCallResponse(JSON.stringify({ n: 99 })))) as unknown as typeof fetch;
|
||||
|
||||
const schema = z.object({ n: z.number() });
|
||||
const agent: AgentFn = async (_ctx, prompt) => prompt;
|
||||
|
||||
@@ -14,10 +14,10 @@ describe("extractMetaOrThrow", () => {
|
||||
|
||||
test("dryRun returns dryRunMeta without calling fetch", async () => {
|
||||
let calls = 0;
|
||||
globalThis.fetch = () => {
|
||||
globalThis.fetch = (() => {
|
||||
calls += 1;
|
||||
return Promise.resolve(new Response("{}", { status: 200 }));
|
||||
};
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
const schema = z.object({ n: z.number() });
|
||||
const out = await extractMetaOrThrow("r", "raw", schema, {
|
||||
@@ -33,7 +33,7 @@ describe("extractMetaOrThrow", () => {
|
||||
});
|
||||
|
||||
test("throws when extraction fails after retry", async () => {
|
||||
globalThis.fetch = () =>
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
@@ -49,7 +49,7 @@ describe("extractMetaOrThrow", () => {
|
||||
}),
|
||||
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||
),
|
||||
);
|
||||
)) as unknown as typeof fetch;
|
||||
|
||||
const schema = z.object({ n: z.number() });
|
||||
|
||||
@@ -61,7 +61,7 @@ describe("extractMetaOrThrow", () => {
|
||||
});
|
||||
|
||||
test("returns validated meta on successful tool call", async () => {
|
||||
globalThis.fetch = () =>
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
@@ -82,7 +82,7 @@ describe("extractMetaOrThrow", () => {
|
||||
}),
|
||||
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||
),
|
||||
);
|
||||
)) as unknown as typeof fetch;
|
||||
|
||||
const schema = z.object({
|
||||
branch: z.string(),
|
||||
|
||||
@@ -17,7 +17,7 @@ describe("llmExtract", () => {
|
||||
let capturedUrl: string | null = null;
|
||||
let capturedInit: RequestInit | null = null;
|
||||
|
||||
globalThis.fetch = (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
globalThis.fetch = ((input: Request | string | URL, init?: RequestInit) => {
|
||||
capturedUrl = typeof input === "string" ? input : input.toString();
|
||||
capturedInit = init ?? null;
|
||||
return Promise.resolve(
|
||||
@@ -44,7 +44,7 @@ describe("llmExtract", () => {
|
||||
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||
),
|
||||
);
|
||||
};
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
const result = await llmExtract({
|
||||
text: "some plan",
|
||||
@@ -66,13 +66,13 @@ describe("llmExtract", () => {
|
||||
}
|
||||
expect(result.value).toEqual({ name: "cpu-usage", description: "CPU load" });
|
||||
|
||||
expect(capturedUrl).toBe("https://example.com/v1/chat/completions");
|
||||
expect(capturedInit?.method).toBe("POST");
|
||||
expect(capturedInit?.headers).toMatchObject({
|
||||
expect(capturedUrl!).toBe("https://example.com/v1/chat/completions");
|
||||
expect(capturedInit!.method).toBe("POST");
|
||||
expect(capturedInit!.headers).toMatchObject({
|
||||
Authorization: "Bearer k",
|
||||
"Content-Type": "application/json",
|
||||
});
|
||||
const body = JSON.parse(capturedInit?.body as string) as {
|
||||
const body = JSON.parse(capturedInit!.body as string) as {
|
||||
model: string;
|
||||
tool_choice: { function: { name: string } };
|
||||
};
|
||||
@@ -83,7 +83,7 @@ describe("llmExtract", () => {
|
||||
test("returns schema_validation_failed when arguments do not match the schema", async () => {
|
||||
const schema = z.object({ n: z.number() });
|
||||
|
||||
globalThis.fetch = () =>
|
||||
globalThis.fetch = (() =>
|
||||
Promise.resolve(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
@@ -99,7 +99,7 @@ describe("llmExtract", () => {
|
||||
}),
|
||||
{ status: 200, headers: { "Content-Type": "application/json" } },
|
||||
),
|
||||
);
|
||||
)) as unknown as typeof fetch;
|
||||
|
||||
const result = await llmExtract({
|
||||
text: "x",
|
||||
@@ -120,10 +120,10 @@ describe("llmExtract", () => {
|
||||
|
||||
test("dryRun skips fetch and returns dryRunMeta", async () => {
|
||||
let calls = 0;
|
||||
globalThis.fetch = () => {
|
||||
globalThis.fetch = (() => {
|
||||
calls += 1;
|
||||
return Promise.resolve(new Response("{}", { status: 200 }));
|
||||
};
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
const schema = z.object({ n: z.number() });
|
||||
const result = await llmExtract({
|
||||
|
||||
Reference in New Issue
Block a user