a8b50f5109
---ci---
project: ci
phase: 6
milestone: v0.9
status: complete
artifacts:
tags: [v0.9.0]
decisions:
- id: D-047
decision: v0.9 theme = Distribution & Expansion
rationale: npm publish + OpenAI/Anthropic backends + agent flesh + parallel execution
confidence: 0.92
- id: D-049
decision: Feature milestone — patch tags v0.8.1-v0.8.6 then v0.9.0
rationale: OpenAI backend, agent flesh, npm publish all feat
confidence: 0.95
- id: D-059
decision: Rename OllamaBaseBackend to LLMBaseBackend + thin OllamaBaseBackend subclass
rationale: 15 of 17 methods backend-agnostic
confidence: 0.92
- id: D-060
decision: OpenAI/Anthropic backends use native fetch() not SDK packages
rationale: No dependency bloat; fetch native in Node 18+
confidence: 0.85
- id: D-066
decision: Concurrency limiter internal (no p-limit dependency)
rationale: 15 lines; avoids dependency for trivial feature
confidence: 0.90
- id: D-067
decision: Promise.allSettled for review agents at orchestrator lines 373-400
rationale: Current sequential loop replaced with parallel execution
confidence: 0.88
requirements:
covered: [PUBLISH-01, PUBLISH-02, PUBLISH-03, PUBLISH-04, OPENAI-01, OPENAI-02, OPENAI-03, OPENAI-04, OPENAI-05, FLESH-01, FLESH-02, FLESH-03, FLESH-04, FLESH-05, ANTHROPIC-01, ANTHROPIC-02, FLESH-06, FLESH-07, NPM-01, NPM-02, PARALLEL-01, PARALLEL-02, PARALLEL-03, INTEG-01, INTEG-02, INTEG-03, INTEG-04, INTEG-05]
---/ci---
6 phases, 28 tasks, 4077 net lines added, 57 test suites, 527 tests, zero stub agents
93 lines
3.0 KiB
TypeScript
93 lines
3.0 KiB
TypeScript
import * as fs from "node:fs";
|
|
import * as path from "node:path";
|
|
import * as os from "node:os";
|
|
import { ProjectResearcherAgent } from "../agents/project-researcher.js";
|
|
|
|
describe("ProjectResearcherAgent", () => {
|
|
let tempDir: string;
|
|
|
|
beforeEach(() => {
|
|
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "ciagent-project-researcher-test-"));
|
|
});
|
|
|
|
afterEach(() => {
|
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it("reads package.json and categorizes dependencies", () => {
|
|
fs.writeFileSync(
|
|
path.join(tempDir, "package.json"),
|
|
JSON.stringify({
|
|
dependencies: { express: "^4.18.0", graphql: "^16.0.0" },
|
|
devDependencies: { jest: "^29.0.0", typescript: "^5.0.0" },
|
|
})
|
|
);
|
|
|
|
const agent = new ProjectResearcherAgent();
|
|
const pkg = agent.readPackageJson(tempDir);
|
|
const tsconfig = {};
|
|
const summary = agent.categorizeFindings(pkg, tsconfig, []);
|
|
|
|
expect(summary.frameworks).toContain("express");
|
|
expect(summary.frameworks).toContain("jest");
|
|
expect(summary.apis).toContain("graphql");
|
|
expect(summary.tooling).toContain("typescript");
|
|
});
|
|
|
|
it("reads tsconfig and extracts compiler options", () => {
|
|
fs.writeFileSync(
|
|
path.join(tempDir, "tsconfig.json"),
|
|
JSON.stringify({
|
|
compilerOptions: { target: "ES2022", module: "Node16" },
|
|
})
|
|
);
|
|
|
|
const agent = new ProjectResearcherAgent();
|
|
const tsconfig = agent.readTsconfig(tempDir);
|
|
|
|
expect((tsconfig.compilerOptions as Record<string, unknown>).target).toBe("ES2022");
|
|
expect((tsconfig.compilerOptions as Record<string, unknown>).module).toBe("Node16");
|
|
});
|
|
|
|
it("categorizes tooling from scripts and engines", () => {
|
|
const pkg = {
|
|
scripts: { build: "tsc", test: "jest", lint: "eslint ." },
|
|
engines: { node: ">=18.0.0" },
|
|
};
|
|
|
|
const agent = new ProjectResearcherAgent();
|
|
const summary = agent.categorizeFindings(pkg, {}, []);
|
|
|
|
expect(summary.tooling).toContain("build_script");
|
|
expect(summary.tooling).toContain("test_script");
|
|
expect(summary.tooling).toContain("lint_script");
|
|
expect(summary.tooling).toContain("node:>=18.0.0");
|
|
});
|
|
|
|
it("detects patterns from devDependencies", () => {
|
|
const pkg = {
|
|
devDependencies: { jest: "^29.0.0", tsyringe: "^4.8.0" },
|
|
};
|
|
|
|
const agent = new ProjectResearcherAgent();
|
|
const summary = agent.categorizeFindings(pkg, {}, []);
|
|
|
|
expect(summary.patterns).toContain("test_driven");
|
|
expect(summary.patterns).toContain("dependency_injection");
|
|
});
|
|
|
|
it("returns empty summary when no package.json exists", () => {
|
|
const agent = new ProjectResearcherAgent();
|
|
const summary = agent.mechanicalProjectResearch(tempDir);
|
|
|
|
expect(summary.frameworks).toEqual([]);
|
|
expect(summary.apis).toEqual([]);
|
|
expect(summary.patterns).toEqual([]);
|
|
expect(summary.technologyDecisions).toEqual([]);
|
|
});
|
|
|
|
it("agent name is project-researcher", () => {
|
|
const agent = new ProjectResearcherAgent();
|
|
expect(agent.name).toBe("project-researcher");
|
|
});
|
|
}); |