feat(coding-agent): added JSON syntax support for array and record config values
- Added support for setting array and record configuration values using JSON syntax. - Implemented JSON parsing and validation for array and record types in config CLI. - Added 2 integration tests covering array and record configuration workflows. - Enhanced test setup with temporary directory management and settings reset for isolation.
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
|
||||
- Added support for setting array and record configuration values using JSON syntax
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -195,6 +195,32 @@ function parseAndSetValue(path: SettingPath, rawValue: string): void {
|
||||
parsedValue = trimmed;
|
||||
break;
|
||||
}
|
||||
case "array": {
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(trimmed);
|
||||
} catch {
|
||||
throw new Error(`Invalid array JSON: ${rawValue}`);
|
||||
}
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new Error(`Invalid array JSON: ${rawValue}`);
|
||||
}
|
||||
parsedValue = parsed;
|
||||
break;
|
||||
}
|
||||
case "record": {
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(trimmed);
|
||||
} catch {
|
||||
throw new Error(`Invalid record JSON: ${rawValue}`);
|
||||
}
|
||||
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
||||
throw new Error(`Invalid record JSON: ${rawValue}`);
|
||||
}
|
||||
parsedValue = parsed;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
parsedValue = trimmed;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
import { afterEach, describe, expect, it, vi } from "bun:test";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
|
||||
import * as fs from "node:fs/promises";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import { getConfigRootDir, setAgentDir } from "@oh-my-pi/pi-utils";
|
||||
import { runConfigCommand } from "../src/cli/config-cli";
|
||||
import { _resetSettingsForTest } from "../src/config/settings";
|
||||
|
||||
afterEach(() => {
|
||||
let testAgentDir = "";
|
||||
const originalAgentDir = process.env.PI_CODING_AGENT_DIR;
|
||||
const fallbackAgentDir = path.join(getConfigRootDir(), "agent");
|
||||
|
||||
beforeEach(async () => {
|
||||
_resetSettingsForTest();
|
||||
testAgentDir = await fs.mkdtemp(path.join(os.tmpdir(), "omp-config-cli-"));
|
||||
setAgentDir(testAgentDir);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
vi.restoreAllMocks();
|
||||
_resetSettingsForTest();
|
||||
if (originalAgentDir) {
|
||||
setAgentDir(originalAgentDir);
|
||||
} else {
|
||||
setAgentDir(fallbackAgentDir);
|
||||
delete process.env.PI_CODING_AGENT_DIR;
|
||||
}
|
||||
await fs.rm(testAgentDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
describe("config CLI schema coverage", () => {
|
||||
@@ -52,4 +75,34 @@ describe("config CLI schema coverage", () => {
|
||||
expect(modelRolesLine).toContain("(record)");
|
||||
expect(modelRolesLine).not.toContain("[object Object]");
|
||||
});
|
||||
|
||||
it("sets and gets record settings as JSON objects", async () => {
|
||||
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
const recordValue = '{"default":"claude-opus-4-6"}';
|
||||
|
||||
await runConfigCommand({ action: "set", key: "modelRoles", value: recordValue, flags: { json: true } });
|
||||
await runConfigCommand({ action: "get", key: "modelRoles", flags: { json: true } });
|
||||
|
||||
const payload = logSpy.mock.calls.at(-1)?.[0];
|
||||
expect(typeof payload).toBe("string");
|
||||
const parsed = JSON.parse(String(payload)) as { key: string; value: unknown; type: string };
|
||||
expect(parsed.key).toBe("modelRoles");
|
||||
expect(parsed.type).toBe("record");
|
||||
expect(parsed.value).toEqual({ default: "claude-opus-4-6" });
|
||||
});
|
||||
|
||||
it("sets and gets array settings as JSON arrays", async () => {
|
||||
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
const arrayValue = '["claude-opus-4-6","gpt-5.3-codex"]';
|
||||
|
||||
await runConfigCommand({ action: "set", key: "enabledModels", value: arrayValue, flags: { json: true } });
|
||||
await runConfigCommand({ action: "get", key: "enabledModels", flags: { json: true } });
|
||||
|
||||
const payload = logSpy.mock.calls.at(-1)?.[0];
|
||||
expect(typeof payload).toBe("string");
|
||||
const parsed = JSON.parse(String(payload)) as { key: string; value: unknown; type: string };
|
||||
expect(parsed.key).toBe("enabledModels");
|
||||
expect(parsed.type).toBe("array");
|
||||
expect(parsed.value).toEqual(["claude-opus-4-6", "gpt-5.3-codex"]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user