feat(ipuaro): add commands configuration

- Add CommandsConfigSchema with timeout option
- Integrate timeout configuration in RunCommandTool
- Add 22 new unit tests (19 schema + 3 integration)
- Complete v0.22.0 Extended Configuration milestone
This commit is contained in:
imfozilbek
2025-12-02 03:03:57 +05:00
parent c34d57c231
commit 9c94335729
6 changed files with 233 additions and 10 deletions

View File

@@ -354,6 +354,36 @@ describe("RunCommandTool", () => {
expect(execFn).toHaveBeenCalledWith("ls", expect.objectContaining({ timeout: 5000 }))
})
it("should use config timeout", async () => {
const execFn = createMockExec({})
const toolWithMock = new RunCommandTool(undefined, execFn, { timeout: 45000 })
const ctx = createMockContext()
await toolWithMock.execute({ command: "ls" }, ctx)
expect(execFn).toHaveBeenCalledWith("ls", expect.objectContaining({ timeout: 45000 }))
})
it("should use null config timeout as default", async () => {
const execFn = createMockExec({})
const toolWithMock = new RunCommandTool(undefined, execFn, { timeout: null })
const ctx = createMockContext()
await toolWithMock.execute({ command: "ls" }, ctx)
expect(execFn).toHaveBeenCalledWith("ls", expect.objectContaining({ timeout: 30000 }))
})
it("should prefer param timeout over config timeout", async () => {
const execFn = createMockExec({})
const toolWithMock = new RunCommandTool(undefined, execFn, { timeout: 45000 })
const ctx = createMockContext()
await toolWithMock.execute({ command: "ls", timeout: 5000 }, ctx)
expect(execFn).toHaveBeenCalledWith("ls", expect.objectContaining({ timeout: 5000 }))
})
it("should execute in project root", async () => {
const execFn = createMockExec({})
const toolWithMock = new RunCommandTool(undefined, execFn)

View File

@@ -0,0 +1,137 @@
/**
* Tests for CommandsConfigSchema.
*/
import { describe, expect, it } from "vitest"
import { CommandsConfigSchema } from "../../../src/shared/constants/config.js"
describe("CommandsConfigSchema", () => {
describe("default values", () => {
it("should use defaults when empty object provided", () => {
const result = CommandsConfigSchema.parse({})
expect(result).toEqual({
timeout: null,
})
})
it("should use defaults via .default({})", () => {
const result = CommandsConfigSchema.default({}).parse({})
expect(result).toEqual({
timeout: null,
})
})
})
describe("timeout", () => {
it("should accept null (default)", () => {
const result = CommandsConfigSchema.parse({ timeout: null })
expect(result.timeout).toBe(null)
})
it("should accept positive integer", () => {
const result = CommandsConfigSchema.parse({ timeout: 5000 })
expect(result.timeout).toBe(5000)
})
it("should accept large timeout", () => {
const result = CommandsConfigSchema.parse({ timeout: 600000 })
expect(result.timeout).toBe(600000)
})
it("should accept 1", () => {
const result = CommandsConfigSchema.parse({ timeout: 1 })
expect(result.timeout).toBe(1)
})
it("should accept small timeout", () => {
const result = CommandsConfigSchema.parse({ timeout: 100 })
expect(result.timeout).toBe(100)
})
it("should reject zero", () => {
expect(() => CommandsConfigSchema.parse({ timeout: 0 })).toThrow()
})
it("should reject negative number", () => {
expect(() => CommandsConfigSchema.parse({ timeout: -5000 })).toThrow()
})
it("should reject float", () => {
expect(() => CommandsConfigSchema.parse({ timeout: 5000.5 })).toThrow()
})
it("should reject string", () => {
expect(() => CommandsConfigSchema.parse({ timeout: "5000" })).toThrow()
})
it("should reject boolean", () => {
expect(() => CommandsConfigSchema.parse({ timeout: true })).toThrow()
})
it("should reject undefined (use null instead)", () => {
const result = CommandsConfigSchema.parse({ timeout: undefined })
expect(result.timeout).toBe(null)
})
})
describe("partial config", () => {
it("should use default null when timeout not provided", () => {
const result = CommandsConfigSchema.parse({})
expect(result).toEqual({
timeout: null,
})
})
it("should accept explicit null", () => {
const result = CommandsConfigSchema.parse({
timeout: null,
})
expect(result).toEqual({
timeout: null,
})
})
it("should accept explicit timeout value", () => {
const result = CommandsConfigSchema.parse({
timeout: 10000,
})
expect(result).toEqual({
timeout: 10000,
})
})
})
describe("full config", () => {
it("should accept valid config with null", () => {
const config = {
timeout: null,
}
const result = CommandsConfigSchema.parse(config)
expect(result).toEqual(config)
})
it("should accept valid config with timeout", () => {
const config = {
timeout: 30000,
}
const result = CommandsConfigSchema.parse(config)
expect(result).toEqual(config)
})
it("should accept default explicitly", () => {
const config = {
timeout: null,
}
const result = CommandsConfigSchema.parse(config)
expect(result).toEqual(config)
})
})
})