Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
350 changes: 350 additions & 0 deletions issues/2.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/__tests__/builtin-agent-profiles.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ beforeAll(async () => {
});

describe("builtin agent profiles", () => {
it("loads exactly 5 builtin profiles", () => {
expect(registry.list()).toHaveLength(5);
it("loads exactly 7 builtin profiles", () => {
expect(registry.list()).toHaveLength(7);
});

it("coder profile has name === 'coder' and model === 'gpt-4o'", () => {
Expand Down
3 changes: 2 additions & 1 deletion src/__tests__/builtin-skills.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ describe("built-in skill library", () => {
"test-writer",
"git-workflow",
"security-auditor",
"build-verify",
];

it("loads all 5 built-in skills", () => {
it("loads all 6 built-in skills", () => {
const names = registry.list().map((s) => s.name);
for (const name of BUILTIN_NAMES) {
expect(names).toContain(name);
Expand Down
4 changes: 4 additions & 0 deletions src/__tests__/fixtures/workspace-cargo/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "my-app"
version = "0.1.0"
edition = "2021"
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":3,"cmakeMinimumRequired":{"major":3,"minor":21},"configurePresets":[{"name":"default","binaryDir":"build"}],"buildPresets":[{"name":"default","configurePreset":"default"}],"testPresets":[{"name":"default","configurePreset":"default"}]}
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugins { kotlin("jvm") version "1.9.0" }
Empty file.
1 change: 1 addition & 0 deletions src/__tests__/fixtures/workspace-gradle/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugins { id("java") }
Empty file.
1 change: 1 addition & 0 deletions src/__tests__/fixtures/workspace-maven/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<project><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>my-app</artifactId><version>1.0</version></project>
Empty file.
115 changes: 103 additions & 12 deletions src/__tests__/planner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { BaseChatModel } from "@langchain/core/language_models/chat_models"
import { ToolRegistry } from "../tools/registry";
import { generatePlan, validatePlan, refinePlan } from "../subagents/planner";
import type { Plan } from "../subagents/planner";
import type { WorkspaceInfo } from "../workspace";
import type { WorkspaceContext } from "../workspace";

// ─────────────────────────────────────────────────────────────────────────────
// Helpers
Expand All @@ -36,17 +36,19 @@ function makeRegistry(...names: string[]): ToolRegistry {
return registry;
}

/** A representative workspace used across tests. */
const MOCK_WORKSPACE: WorkspaceInfo = {
language: "node",
framework: "express",
packageManager: "npm",
hasTests: true,
testCommand: "npm test",
lintCommand: "npm run lint",
buildCommand: "npm run build",
entryPoints: ["src/index.ts"],
gitInitialized: true,
/** A representative workspace context used across tests. */
const MOCK_WORKSPACE: WorkspaceContext = {
workspaceInfo: {
language: "node",
framework: "express",
packageManager: "npm",
hasTests: true,
testCommand: "npm test",
lintCommand: "npm run lint",
buildCommand: "npm run build",
entryPoints: ["src/index.ts"],
gitInitialized: true,
},
};

// ─────────────────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -461,3 +463,92 @@ describe("generatePlan — agentProfile field", () => {
expect(userMsg!.content).toContain("devops");
});
});

// ─────────────────────────────────────────────────────────────────────────────
// WorkspaceContext — richer context from ProjectExplorer
// ─────────────────────────────────────────────────────────────────────────────

describe("generatePlan — WorkspaceContext with buildSystems", () => {
it("includes buildSystems notes in the planner task when context has buildSystems", async () => {
const invoke = jest.fn().mockResolvedValueOnce({
content: JSON.stringify({
steps: [{ description: "build the project", toolsNeeded: [], estimatedComplexity: "medium" }],
}),
tool_calls: [],
});

const mockLlm = {
bindTools: jest.fn().mockReturnValue({ invoke }),
} as unknown as BaseChatModel;

const richContext: WorkspaceContext = {
workspaceInfo: {
language: "rust",
framework: "none",
packageManager: "cargo",
hasTests: true,
testCommand: "",
lintCommand: "",
buildCommand: "",
entryPoints: [],
gitInitialized: true,
},
buildSystems: [
{
name: "cargo",
configFile: "Cargo.toml",
notes: "Workspace with members: core, cli. Use --workspace flag for full builds.",
},
],
};

await generatePlan("verify the build", richContext, new ToolRegistry(), mockLlm);

const messages: Array<{ content: string }> = invoke.mock.calls[0][0];
const userMsg = messages.find(
(m) => typeof m.content === "string" && m.content.includes("verify the build")
);
expect(userMsg).toBeDefined();
// buildSystems notes should appear in the task
expect(userMsg!.content).toContain("cargo");
expect(userMsg!.content).toContain("Cargo.toml");
expect(userMsg!.content).toContain("--workspace");
});

it("includes explorerNotes in the planner task when context has explorerNotes", async () => {
const invoke = jest.fn().mockResolvedValueOnce({
content: JSON.stringify({
steps: [{ description: "step", toolsNeeded: [], estimatedComplexity: "low" }],
}),
tool_calls: [],
});

const mockLlm = {
bindTools: jest.fn().mockReturnValue({ invoke }),
} as unknown as BaseChatModel;

const contextWithNotes: WorkspaceContext = {
workspaceInfo: {
language: "cpp",
framework: "none",
packageManager: "cmake",
hasTests: false,
testCommand: "",
lintCommand: "",
buildCommand: "",
entryPoints: [],
gitInitialized: false,
},
explorerNotes: "Multi-language monorepo: C++ core with Python bindings",
};

await generatePlan("verify-the-cpp-bindings", contextWithNotes, new ToolRegistry(), mockLlm);

const messages: Array<{ content: string }> = invoke.mock.calls[0][0];
const userMsg = messages.find(
(m) => typeof m.content === "string" && m.content.includes("verify-the-cpp-bindings")
);
expect(userMsg).toBeDefined();
expect(userMsg!.content).toContain("Multi-language monorepo");
});
});
Loading