fix(tools): resolve exactOptionalPropertyTypes errors

Handle undefined values correctly in optional object properties
for TypeScript strict mode compatibility.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jiang Bohan 2026-01-31 01:57:38 +08:00
parent 7d04253791
commit e44861b56c
5 changed files with 75 additions and 35 deletions

View file

@ -149,14 +149,19 @@ async function main() {
}
// Build tools config if any tools options are set
const toolsConfig =
opts.toolsProfile || opts.toolsAllow || opts.toolsDeny
? {
profile: opts.toolsProfile as any,
allow: opts.toolsAllow,
deny: opts.toolsDeny,
}
: undefined;
let toolsConfig: import("./tools/policy.js").ToolsConfig | undefined;
if (opts.toolsProfile || opts.toolsAllow || opts.toolsDeny) {
toolsConfig = {};
if (opts.toolsProfile) {
toolsConfig.profile = opts.toolsProfile as any;
}
if (opts.toolsAllow) {
toolsConfig.allow = opts.toolsAllow;
}
if (opts.toolsDeny) {
toolsConfig.deny = opts.toolsDeny;
}
}
const agent = new Agent({
profileId: opts.profile,

View file

@ -60,7 +60,8 @@ function parseArgs(argv: string[]): CliOptions {
if (!arg) break;
if (arg === "--profile") {
opts.profile = args.shift();
const value = args.shift();
if (value) opts.profile = value;
continue;
}
if (arg === "--allow") {
@ -74,7 +75,8 @@ function parseArgs(argv: string[]): CliOptions {
continue;
}
if (arg === "--provider") {
opts.provider = args.shift();
const value = args.shift();
if (value) opts.provider = value;
continue;
}
if (arg === "--subagent") {
@ -93,20 +95,32 @@ function listTools(opts: CliOptions) {
console.log("");
// Build config
const config: ToolsConfig | undefined =
opts.profile || opts.allow || opts.deny
? {
profile: opts.profile as any,
allow: opts.allow,
deny: opts.deny,
}
: undefined;
let config: ToolsConfig | undefined;
if (opts.profile || opts.allow || opts.deny) {
config = {};
if (opts.profile) {
config.profile = opts.profile as any;
}
if (opts.allow) {
config.allow = opts.allow;
}
if (opts.deny) {
config.deny = opts.deny;
}
}
const filtered = filterTools(allTools, {
config,
provider: opts.provider,
isSubagent: opts.isSubagent,
});
const filterOpts: import("./tools/policy.js").FilterToolsOptions = {};
if (config) {
filterOpts.config = config;
}
if (opts.provider) {
filterOpts.provider = opts.provider;
}
if (opts.isSubagent) {
filterOpts.isSubagent = opts.isSubagent;
}
const filtered = filterTools(allTools, filterOpts);
if (config || opts.provider || opts.isSubagent) {
console.log("Applied filters:");

View file

@ -161,7 +161,12 @@ describe("glob", () => {
expect(result.details.count).toBe(0);
expect(result.details.files).toHaveLength(0);
expect(result.content[0].text).toContain("No files found");
const content = result.content[0];
expect(content).toBeDefined();
expect(content?.type).toBe("text");
if (content?.type === "text") {
expect(content.text).toContain("No files found");
}
});
it("should sort files by modification time (most recent first)", async () => {

View file

@ -131,8 +131,12 @@ export function getProfilePolicy(
const resolved = TOOL_PROFILES[profile];
if (!resolved) return undefined;
if (!resolved.allow && !resolved.deny) return undefined;
return {
allow: resolved.allow ? [...resolved.allow] : undefined,
deny: resolved.deny ? [...resolved.deny] : undefined,
};
const result: { allow?: string[]; deny?: string[] } = {};
if (resolved.allow) {
result.allow = [...resolved.allow];
}
if (resolved.deny) {
result.deny = [...resolved.deny];
}
return result;
}

View file

@ -1,6 +1,15 @@
import { describe, it, expect } from "vitest";
import { readStringParam, readNumberParam, jsonResult } from "./param-helpers.js";
// Helper to safely get text content from result
function getTextContent(result: ReturnType<typeof jsonResult>): string {
const content = result.content[0];
if (content?.type === "text") {
return content.text;
}
throw new Error("Expected text content");
}
describe("param-helpers", () => {
describe("readStringParam", () => {
it("should return string value when present", () => {
@ -195,8 +204,11 @@ describe("param-helpers", () => {
const result = jsonResult(payload);
expect(result.content).toHaveLength(1);
expect(result.content[0].type).toBe("text");
expect(result.content[0].text).toBe(JSON.stringify(payload, null, 2));
const content = result.content[0];
expect(content?.type).toBe("text");
if (content?.type === "text") {
expect(content.text).toBe(JSON.stringify(payload, null, 2));
}
expect(result.details).toBe(payload);
});
@ -204,7 +216,7 @@ describe("param-helpers", () => {
const payload = [1, 2, 3];
const result = jsonResult(payload);
expect(result.content[0].text).toBe(JSON.stringify(payload, null, 2));
expect(getTextContent(result)).toBe(JSON.stringify(payload, null, 2));
expect(result.details).toBe(payload);
});
@ -212,14 +224,14 @@ describe("param-helpers", () => {
const payload = "simple string";
const result = jsonResult(payload);
expect(result.content[0].text).toBe('"simple string"');
expect(getTextContent(result)).toBe('"simple string"');
expect(result.details).toBe(payload);
});
it("should handle null payload", () => {
const result = jsonResult(null);
expect(result.content[0].text).toBe("null");
expect(getTextContent(result)).toBe("null");
expect(result.details).toBeNull();
});
@ -230,8 +242,8 @@ describe("param-helpers", () => {
};
const result = jsonResult(payload);
expect(result.content[0].text).toContain("user");
expect(result.content[0].text).toContain("settings");
expect(getTextContent(result)).toContain("user");
expect(getTextContent(result)).toContain("settings");
expect(result.details).toBe(payload);
});
});