Skip to content
3 changes: 3 additions & 0 deletions cli/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@
"url": "https://github.com/michaelshimeles/ralphy"
},
"dependencies": {
"commander": "^13.0.0",
"yaml": "^2.7.0",
"simple-git": "^3.27.0",
"@agentclientprotocol/sdk": "^0.13.1",
"@octokit/rest": "^21.0.0",
"picocolors": "^1.1.0",
"commander": "^13.0.0",
"nanospinner": "^1.2.0",
"node-notifier": "^10.0.1",
"picocolors": "^1.1.0",
"simple-git": "^3.27.0",
"yaml": "^2.7.0",
"zod": "^3.24.0"
},
"devDependencies": {
Expand Down
99 changes: 99 additions & 0 deletions cli/src/engines/copilot-acp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test";
import { existsSync, mkdirSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { CopilotAcpEngine } from "./copilot-acp.ts";
import * as baseModule from "./base.ts";

describe("CopilotAcpEngine", () => {
let engine: CopilotAcpEngine;
const testWorkDir = join(tmpdir(), "copilot-acp-test");

beforeEach(() => {
engine = new CopilotAcpEngine();
mkdirSync(testWorkDir, { recursive: true });
});

afterEach(() => {
if (existsSync(testWorkDir)) {
rmSync(testWorkDir, { recursive: true, force: true });
}
});

describe("Basic Properties", () => {
it("should have correct name and command", () => {
expect(engine.name).toBe("GitHub Copilot");
expect(engine.cliCommand).toBe("copilot");
});
});

describe("ACP Connection", () => {
it("should build prompt content correctly", () => {
const promptContent = (engine as any).buildPromptContent("test prompt");
expect(promptContent).toEqual([{ type: "text", text: "test prompt" }]);
});

it("should prepend model override as instruction", () => {
const promptContent = (engine as any).buildPromptContent("test prompt", {
modelOverride: "gpt-4",
});
expect(promptContent).toHaveLength(2);
expect(promptContent[0]).toEqual({ type: "text", text: "[Use model: gpt-4]" });
expect(promptContent[1]).toEqual({ type: "text", text: "test prompt" });
});

it("should handle empty prompt", () => {
const promptContent = (engine as any).buildPromptContent("");
expect(promptContent).toEqual([{ type: "text", text: "" }]);
});

it("should preserve multiline prompts", () => {
const multilinePrompt = "Line 1\nLine 2\nLine 3";
const promptContent = (engine as any).buildPromptContent(multilinePrompt);
expect(promptContent[0].text).toBe(multilinePrompt);
});
});

describe("Prompt Content Building", () => {
it("should handle various prompt content scenarios", async () => {
// Test with model override
const withModel = (engine as any).buildPromptContent("test", { modelOverride: "gpt-4" });
expect(withModel[0].text).toContain("gpt-4");
expect(withModel[1].text).toBe("test");

// Test without model
const withoutModel = (engine as any).buildPromptContent("test");
expect(withoutModel).toHaveLength(1);
expect(withoutModel[0].text).toBe("test");
});
});

describe("Streaming Execution", () => {
it("should have executeStreaming method available", () => {
expect(engine.executeStreaming).toBeDefined();
expect(typeof engine.executeStreaming).toBe("function");
});
});

describe("Error Handling", () => {
it("should check if copilot command is available", async () => {
const isAvailable = await engine.isAvailable();
// This will check actual system, but should not throw
expect(typeof isAvailable).toBe("boolean");
});
});

describe("Integration Properties", () => {
it("should have correct engine properties", () => {
expect(engine.name).toBe("GitHub Copilot");
expect(engine.cliCommand).toBe("copilot");
});

it("should support model override in options", () => {
const content = (engine as any).buildPromptContent("test", {
modelOverride: "custom-model",
});
expect(content[0].text).toContain("custom-model");
});
});
});
Comment thread
Shazwazza marked this conversation as resolved.
Loading