feat(P01): interactive validation + doc updates + multi-project CLI — IDEATE-12,13,14 + MULTI-02,06
---ci---
phase: 1
milestone: v0.10
status: execute
decisions:
- id: D-083
decision: Interactive one-at-a-time validation with accept/skip/modify
rationale: Gives user full control over ideation results
confidence: 0.87
- id: D-085
decision: Ask-after-validation kickoff of run workflow
rationale: Balances automation with user control
confidence: 0.85
- id: D-091
decision: Full multi-project support with active_projects array + parallel execution
rationale: User wants complete multi-project capability
confidence: 0.85
requirements:
covered:
- IDEATE-12
- IDEATE-13
- IDEATE-14
- MULTI-02
- MULTI-06
---/ci---
- IDEATE-12: Interactive accept/skip/modify validation with readline
- IDEATE-13: acceptIdea/acceptIdeas methods update REQUIREMENTS.md and ROADMAP.md
- IDEATE-14: Ask-after-validation kickoff prompt for
- MULTI-02: --project flag accepts comma-separated or 'all' in pre-action hook
- MULTI-06: ciagent status shows active_projects and ideation config
- projects list shows all active projects with multi-marker
- projects set updates both active_project and active_projects
This commit is contained in:
@@ -2,7 +2,7 @@ import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import * as os from "node:os";
|
||||
import { IdeationAgent } from "../agents/ideation-agent.js";
|
||||
import { IdeationEngine, resetIdeaCounter } from "../core/ideation.js";
|
||||
import { IdeationEngine, resetIdeaCounter, Idea } from "../core/ideation.js";
|
||||
|
||||
describe("IdeationAgent", () => {
|
||||
let tempDir: string;
|
||||
@@ -158,4 +158,90 @@ describe("IdeationEngine", () => {
|
||||
expect(result).toHaveProperty("summary");
|
||||
expect(result).toHaveProperty("project");
|
||||
});
|
||||
|
||||
describe("acceptIdea", () => {
|
||||
let acceptDir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
resetIdeaCounter();
|
||||
acceptDir = fs.mkdtempSync(path.join(os.tmpdir(), "ciagent-accept-test-"));
|
||||
const ciagentDir = path.join(acceptDir, ".ciagent");
|
||||
fs.mkdirSync(ciagentDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(ciagentDir, "config.json"),
|
||||
JSON.stringify({ projects: [], active_project: "default" })
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(ciagentDir, "REQUIREMENTS.md"),
|
||||
"# Requirements\n\n## v1 Requirements\n\n### Core\n\n- **CORE-01**: Test core requirement\n\n## Traceability\n\n| Requirement | Phase | Status |\n|-------------|-------|--------|\n| CORE-01 | Phase 1 | pending |\n"
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(ciagentDir, "ROADMAP.md"),
|
||||
"# Roadmap\n\n## Overview\n\nTest roadmap.\n\n## Phases\n\n- [x] **Phase 1: Init** - Starting\n\n## Phase Details\n\n### Phase 1: Init\n\n**Goal.**: Start\n**Status**: complete\n**Requirements**: CORE-01\n**Depends on**: Nothing\n**Success Criteria**:\n1. Project initialized\n"
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(ciagentDir, "PROJECT.md"),
|
||||
"# Test\n\n## What This Is\n\nTest\n\n## Requirements\n\n### Validated\n\n\n### Active\n\n\n## Constraints\n\n- None\n\n## Key Decisions\n\n| Decision | Rationale | Outcome |\n|----------|-----------|--------|\n"
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(ciagentDir, "ARCHITECTURE.md"),
|
||||
"# Architecture\n\n## Overview\n\nTest\n\n## Components\n\n## Data Flow\n\nTest\n\n## Build Order\n\n1. Test\n"
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(acceptDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("accepts an idea and updates REQUIREMENTS.md and ROADMAP.md", () => {
|
||||
const engine = new IdeationEngine(acceptDir);
|
||||
const idea: Idea = {
|
||||
id: "IDEATE-01",
|
||||
source: "uncovered_requirement",
|
||||
category: "coverage",
|
||||
title: "Add rate limiting to cloud backends",
|
||||
rationale: "No rate limiting REQ exists for cloud backends.",
|
||||
confidence: 0.92,
|
||||
actions: ["add_requirement", "update_roadmap"],
|
||||
tier: "mechanical",
|
||||
};
|
||||
|
||||
const result = engine.acceptIdea(idea);
|
||||
|
||||
expect(result.addedToRequirements).toBe(true);
|
||||
expect(result.addedToRoadmap).toBe(true);
|
||||
expect(result.reqId).toBe("IDEATE-01");
|
||||
});
|
||||
|
||||
it("acceptIdeas accepts multiple ideas", () => {
|
||||
const engine = new IdeationEngine(acceptDir);
|
||||
const ideas: Idea[] = [
|
||||
{
|
||||
id: "IDEATE-01",
|
||||
source: "uncovered_requirement",
|
||||
category: "coverage",
|
||||
title: "Add rate limiting",
|
||||
rationale: "No rate limiting.",
|
||||
confidence: 0.9,
|
||||
actions: ["add_requirement"],
|
||||
tier: "mechanical",
|
||||
},
|
||||
{
|
||||
id: "IDEATE-02",
|
||||
source: "architecture_drift",
|
||||
category: "architecture",
|
||||
title: "Fix architecture drift",
|
||||
rationale: "Component documented but missing.",
|
||||
confidence: 0.8,
|
||||
actions: ["update_architecture"],
|
||||
tier: "mechanical",
|
||||
},
|
||||
];
|
||||
|
||||
const { accepted, results } = engine.acceptIdeas(ideas);
|
||||
expect(accepted.length).toBe(2);
|
||||
expect(results.length).toBe(2);
|
||||
expect(results.every((r) => r.addedToRequirements || r.addedToRoadmap)).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user