sdd-mcp-server 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/application/services/AnswerValidator.d.ts +7 -0
  2. package/dist/application/services/AnswerValidator.js +52 -0
  3. package/dist/application/services/AnswerValidator.js.map +1 -0
  4. package/dist/application/services/DescriptionAnalyzer.d.ts +28 -0
  5. package/dist/application/services/DescriptionAnalyzer.js +184 -0
  6. package/dist/application/services/DescriptionAnalyzer.js.map +1 -0
  7. package/dist/application/services/DescriptionEnricher.d.ts +15 -0
  8. package/dist/application/services/DescriptionEnricher.js +77 -0
  9. package/dist/application/services/DescriptionEnricher.js.map +1 -0
  10. package/dist/application/services/QuestionGenerator.d.ts +7 -0
  11. package/dist/application/services/QuestionGenerator.js +30 -0
  12. package/dist/application/services/QuestionGenerator.js.map +1 -0
  13. package/dist/application/services/RequirementsClarificationService.d.ts +22 -51
  14. package/dist/application/services/RequirementsClarificationService.js +44 -419
  15. package/dist/application/services/RequirementsClarificationService.js.map +1 -1
  16. package/dist/application/services/SteeringContextLoader.d.ts +11 -0
  17. package/dist/application/services/SteeringContextLoader.js +90 -0
  18. package/dist/application/services/SteeringContextLoader.js.map +1 -0
  19. package/dist/application/services/clarification-questions.d.ts +15 -0
  20. package/dist/application/services/clarification-questions.js +99 -0
  21. package/dist/application/services/clarification-questions.js.map +1 -0
  22. package/dist/domain/types.d.ts +17 -0
  23. package/dist/infrastructure/di/container.js +18 -0
  24. package/dist/infrastructure/di/container.js.map +1 -1
  25. package/dist/infrastructure/di/types.d.ts +5 -0
  26. package/dist/infrastructure/di/types.js +5 -0
  27. package/dist/infrastructure/di/types.js.map +1 -1
  28. package/package.json +1 -1
@@ -0,0 +1,7 @@
1
+ import { ClarificationQuestion, ClarificationAnswers, AnswerValidationResult } from "../../domain/types.js";
2
+ export declare class AnswerValidator {
3
+ /**
4
+ * Validate user-provided clarification answers
5
+ */
6
+ validate(questions: ClarificationQuestion[], answers: ClarificationAnswers): AnswerValidationResult;
7
+ }
@@ -0,0 +1,52 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { injectable } from "inversify";
8
+ import { ANSWER_VALIDATION } from "./clarification-constants.js";
9
+ let AnswerValidator = class AnswerValidator {
10
+ /**
11
+ * Validate user-provided clarification answers
12
+ */
13
+ validate(questions, answers) {
14
+ const missingRequired = [];
15
+ const tooShort = [];
16
+ const containsInvalidContent = [];
17
+ for (const question of questions) {
18
+ const answer = answers[question.id]?.trim() || "";
19
+ // Check for missing required answers
20
+ if (question.required && !answer) {
21
+ missingRequired.push(question.question);
22
+ continue;
23
+ }
24
+ // Check for too-short answers
25
+ if (answer && answer.length < ANSWER_VALIDATION.MIN_ANSWER_LENGTH) {
26
+ tooShort.push({
27
+ question: question.question,
28
+ minLength: ANSWER_VALIDATION.MIN_ANSWER_LENGTH,
29
+ currentLength: answer.length,
30
+ });
31
+ }
32
+ // Check for potentially malicious content
33
+ if (answer && ANSWER_VALIDATION.INVALID_CONTENT_PATTERN.test(answer)) {
34
+ containsInvalidContent.push(question.question);
35
+ }
36
+ }
37
+ const valid = missingRequired.length === 0 &&
38
+ tooShort.length === 0 &&
39
+ containsInvalidContent.length === 0;
40
+ return {
41
+ valid,
42
+ missingRequired,
43
+ tooShort,
44
+ containsInvalidContent,
45
+ };
46
+ }
47
+ };
48
+ AnswerValidator = __decorate([
49
+ injectable()
50
+ ], AnswerValidator);
51
+ export { AnswerValidator };
52
+ //# sourceMappingURL=AnswerValidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnswerValidator.js","sourceRoot":"","sources":["../../../src/application/services/AnswerValidator.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAMvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAG1D,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B;;OAEG;IACH,QAAQ,CACN,SAAkC,EAClC,OAA6B;QAE7B,MAAM,eAAe,GAAa,EAAE,CAAC;QACrC,MAAM,QAAQ,GAIT,EAAE,CAAC;QACR,MAAM,sBAAsB,GAAa,EAAE,CAAC;QAE5C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAElD,qCAAqC;YACrC,IAAI,QAAQ,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACxC,SAAS;YACX,CAAC;YAED,8BAA8B;YAC9B,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,iBAAiB,CAAC,iBAAiB,EAAE,CAAC;gBAClE,QAAQ,CAAC,IAAI,CAAC;oBACZ,QAAQ,EAAE,QAAQ,CAAC,QAAQ;oBAC3B,SAAS,EAAE,iBAAiB,CAAC,iBAAiB;oBAC9C,aAAa,EAAE,MAAM,CAAC,MAAM;iBAC7B,CAAC,CAAC;YACL,CAAC;YAED,0CAA0C;YAC1C,IAAI,MAAM,IAAI,iBAAiB,CAAC,uBAAuB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrE,sBAAsB,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GACT,eAAe,CAAC,MAAM,KAAK,CAAC;YAC5B,QAAQ,CAAC,MAAM,KAAK,CAAC;YACrB,sBAAsB,CAAC,MAAM,KAAK,CAAC,CAAC;QAEtC,OAAO;YACL,KAAK;YACL,eAAe;YACf,QAAQ;YACR,sBAAsB;SACvB,CAAC;IACJ,CAAC;CACF,CAAA;AApDY,eAAe;IAD3B,UAAU,EAAE;GACA,eAAe,CAoD3B"}
@@ -0,0 +1,28 @@
1
+ import { ClarificationAnalysis, SteeringContext } from "../../domain/types.js";
2
+ export declare class DescriptionAnalyzer {
3
+ /**
4
+ * Analyzes a project description for completeness using scored semantic detection
5
+ */
6
+ analyze(description: string, context: SteeringContext): ClarificationAnalysis;
7
+ /**
8
+ * Score semantic presence using keyword density approach
9
+ * Returns 0-100 based on presence and density of matching patterns
10
+ */
11
+ private scoreSemanticPresence;
12
+ /**
13
+ * Detect ambiguous terms in the description
14
+ */
15
+ private detectAmbiguousTerms;
16
+ /**
17
+ * Calculate overall quality score based on presence of elements
18
+ */
19
+ private calculateQualityScore;
20
+ /**
21
+ * Identify which elements are missing considering steering context
22
+ */
23
+ private identifyMissingElements;
24
+ /**
25
+ * Extract context around a matched term for better clarity
26
+ */
27
+ private extractContext;
28
+ }
@@ -0,0 +1,184 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { injectable } from "inversify";
8
+ import { QUALITY_SCORE_WEIGHTS, PATTERN_DETECTION, AMBIGUOUS_TERMS, } from "./clarification-constants.js";
9
+ let DescriptionAnalyzer = class DescriptionAnalyzer {
10
+ /**
11
+ * Analyzes a project description for completeness using scored semantic detection
12
+ */
13
+ analyze(description, context) {
14
+ // Handle empty descriptions
15
+ if (!description || description.trim().length === 0) {
16
+ return {
17
+ qualityScore: 0,
18
+ whyScore: 0,
19
+ whoScore: 0,
20
+ whatScore: 0,
21
+ successScore: 0,
22
+ hasWhy: false,
23
+ hasWho: false,
24
+ hasWhat: false,
25
+ hasSuccessCriteria: false,
26
+ missingElements: ["WHY", "WHO", "WHAT", "Success Criteria"],
27
+ ambiguousTerms: [],
28
+ needsClarification: true,
29
+ };
30
+ }
31
+ // Calculate semantic scores (0-100 each)
32
+ const whyScore = this.scoreSemanticPresence(description, PATTERN_DETECTION.WHY_PATTERNS);
33
+ const whoScore = this.scoreSemanticPresence(description, PATTERN_DETECTION.WHO_PATTERNS);
34
+ const whatScore = this.scoreSemanticPresence(description, PATTERN_DETECTION.WHAT_PATTERNS);
35
+ const successScore = this.scoreSemanticPresence(description, PATTERN_DETECTION.SUCCESS_PATTERNS);
36
+ // Derive boolean presence (threshold: 30%)
37
+ const hasWhy = whyScore > 30;
38
+ const hasWho = whoScore > 30;
39
+ const hasWhat = whatScore > 30;
40
+ const hasSuccessCriteria = successScore > 30;
41
+ // Detect ambiguous terms
42
+ const ambiguousTerms = this.detectAmbiguousTerms(description);
43
+ // Calculate overall quality score
44
+ const qualityScore = this.calculateQualityScore({
45
+ hasWhy,
46
+ hasWho,
47
+ hasWhat,
48
+ hasSuccessCriteria,
49
+ ambiguousTermCount: ambiguousTerms.length,
50
+ descriptionLength: description.length,
51
+ });
52
+ // Determine missing elements considering steering context
53
+ const missingElements = this.identifyMissingElements({ hasWhy, hasWho, hasWhat, hasSuccessCriteria }, context);
54
+ // Need clarification if score below threshold or missing critical elements
55
+ const needsClarification = qualityScore < QUALITY_SCORE_WEIGHTS.MIN_ACCEPTABLE_SCORE ||
56
+ missingElements.length > 0;
57
+ return {
58
+ qualityScore,
59
+ whyScore,
60
+ whoScore,
61
+ whatScore,
62
+ successScore,
63
+ hasWhy,
64
+ hasWho,
65
+ hasWhat,
66
+ hasSuccessCriteria,
67
+ missingElements,
68
+ ambiguousTerms,
69
+ needsClarification,
70
+ };
71
+ }
72
+ /**
73
+ * Score semantic presence using keyword density approach
74
+ * Returns 0-100 based on presence and density of matching patterns
75
+ */
76
+ scoreSemanticPresence(description, patterns) {
77
+ const words = description
78
+ .toLowerCase()
79
+ .split(/\s+/)
80
+ .filter((w) => w.length > 0);
81
+ if (words.length === 0)
82
+ return 0;
83
+ const matchedWords = words.filter((word) => patterns.some((pattern) => pattern.test(word)));
84
+ if (matchedWords.length === 0)
85
+ return 0;
86
+ // Base score for any presence
87
+ const coverage = 50;
88
+ // Density score based on percentage of matched words
89
+ const density = (matchedWords.length / words.length) * 100;
90
+ // Total score capped at 100
91
+ return Math.min(100, coverage + density);
92
+ }
93
+ /**
94
+ * Detect ambiguous terms in the description
95
+ */
96
+ detectAmbiguousTerms(description) {
97
+ const ambiguousTerms = [];
98
+ for (const { pattern, suggestion } of AMBIGUOUS_TERMS) {
99
+ const matches = description.match(pattern);
100
+ if (matches) {
101
+ for (const match of matches) {
102
+ const context = this.extractContext(description, match);
103
+ ambiguousTerms.push({
104
+ term: match,
105
+ context,
106
+ suggestion,
107
+ });
108
+ }
109
+ }
110
+ }
111
+ return ambiguousTerms;
112
+ }
113
+ /**
114
+ * Calculate overall quality score based on presence of elements
115
+ */
116
+ calculateQualityScore(metrics) {
117
+ let score = 0;
118
+ // WHY is most important
119
+ if (metrics.hasWhy)
120
+ score += QUALITY_SCORE_WEIGHTS.HAS_WHY;
121
+ // WHO is critical
122
+ if (metrics.hasWho)
123
+ score += QUALITY_SCORE_WEIGHTS.HAS_WHO;
124
+ // WHAT is essential
125
+ if (metrics.hasWhat)
126
+ score += QUALITY_SCORE_WEIGHTS.HAS_WHAT;
127
+ // Success criteria
128
+ if (metrics.hasSuccessCriteria)
129
+ score += QUALITY_SCORE_WEIGHTS.HAS_SUCCESS;
130
+ // Penalize ambiguous terms
131
+ const ambiguityPenalty = Math.min(QUALITY_SCORE_WEIGHTS.MAX_AMBIGUITY_PENALTY, metrics.ambiguousTermCount * QUALITY_SCORE_WEIGHTS.AMBIGUITY_PENALTY);
132
+ score -= ambiguityPenalty;
133
+ // Length bonus - adequate detail
134
+ if (metrics.descriptionLength > QUALITY_SCORE_WEIGHTS.LENGTH_BONUS_THRESHOLD_1)
135
+ score += QUALITY_SCORE_WEIGHTS.LENGTH_BONUS_POINTS;
136
+ if (metrics.descriptionLength > QUALITY_SCORE_WEIGHTS.LENGTH_BONUS_THRESHOLD_2)
137
+ score += QUALITY_SCORE_WEIGHTS.LENGTH_BONUS_POINTS;
138
+ if (metrics.descriptionLength > QUALITY_SCORE_WEIGHTS.LENGTH_BONUS_THRESHOLD_3)
139
+ score += QUALITY_SCORE_WEIGHTS.LENGTH_BONUS_POINTS;
140
+ return Math.max(0, Math.min(100, score));
141
+ }
142
+ /**
143
+ * Identify which elements are missing considering steering context
144
+ */
145
+ identifyMissingElements(presence, context) {
146
+ const missing = [];
147
+ // WHY is required unless product context exists
148
+ if (!presence.hasWhy && !context.hasProductContext) {
149
+ missing.push("Business justification (WHY)");
150
+ }
151
+ // WHO is required unless target users documented
152
+ if (!presence.hasWho && !context.hasTargetUsers) {
153
+ missing.push("Target users (WHO)");
154
+ }
155
+ // WHAT is always required
156
+ if (!presence.hasWhat) {
157
+ missing.push("Core features (WHAT)");
158
+ }
159
+ // Success criteria always required
160
+ if (!presence.hasSuccessCriteria) {
161
+ missing.push("Success criteria");
162
+ }
163
+ return missing;
164
+ }
165
+ /**
166
+ * Extract context around a matched term for better clarity
167
+ */
168
+ extractContext(description, term) {
169
+ const index = description.toLowerCase().indexOf(term.toLowerCase());
170
+ if (index === -1)
171
+ return "";
172
+ const start = Math.max(0, index - 30);
173
+ const end = Math.min(description.length, index + term.length + 30);
174
+ const context = description.substring(start, end);
175
+ return ((start > 0 ? "..." : "") +
176
+ context +
177
+ (end < description.length ? "..." : ""));
178
+ }
179
+ };
180
+ DescriptionAnalyzer = __decorate([
181
+ injectable()
182
+ ], DescriptionAnalyzer);
183
+ export { DescriptionAnalyzer };
184
+ //# sourceMappingURL=DescriptionAnalyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DescriptionAnalyzer.js","sourceRoot":"","sources":["../../../src/application/services/DescriptionAnalyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { ClarificationQuestion, ClarificationAnswers, EnrichedProjectDescription } from "../../domain/types.js";
2
+ export declare class DescriptionEnricher {
3
+ /**
4
+ * Synthesize enriched project description from original + clarification answers
5
+ */
6
+ synthesize(originalDescription: string, questions: ClarificationQuestion[], answers: ClarificationAnswers): EnrichedProjectDescription;
7
+ /**
8
+ * Extract all answers for a specific question category
9
+ */
10
+ private extractAnswersByCategory;
11
+ /**
12
+ * Build enriched description with 5W1H structure
13
+ */
14
+ private buildEnrichedDescription;
15
+ }
@@ -0,0 +1,77 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { injectable } from "inversify";
8
+ import { QuestionCategory, } from "../../domain/types.js";
9
+ let DescriptionEnricher = class DescriptionEnricher {
10
+ /**
11
+ * Synthesize enriched project description from original + clarification answers
12
+ */
13
+ synthesize(originalDescription, questions, answers) {
14
+ const why = this.extractAnswersByCategory(questions, answers, QuestionCategory.WHY);
15
+ const who = this.extractAnswersByCategory(questions, answers, QuestionCategory.WHO);
16
+ const what = this.extractAnswersByCategory(questions, answers, QuestionCategory.WHAT);
17
+ const how = this.extractAnswersByCategory(questions, answers, QuestionCategory.HOW);
18
+ const successCriteria = this.extractAnswersByCategory(questions, answers, QuestionCategory.SUCCESS);
19
+ const enriched = this.buildEnrichedDescription({
20
+ original: originalDescription,
21
+ why,
22
+ who,
23
+ what,
24
+ how,
25
+ successCriteria,
26
+ });
27
+ return {
28
+ original: originalDescription,
29
+ why,
30
+ who,
31
+ what,
32
+ how,
33
+ successCriteria,
34
+ enriched,
35
+ };
36
+ }
37
+ /**
38
+ * Extract all answers for a specific question category
39
+ */
40
+ extractAnswersByCategory(questions, answers, category) {
41
+ const categoryQuestions = questions.filter((q) => q.category === category);
42
+ const categoryAnswers = categoryQuestions
43
+ .map((q) => answers[q.id])
44
+ .filter((a) => a && a.trim().length > 0);
45
+ return categoryAnswers.join(" ");
46
+ }
47
+ /**
48
+ * Build enriched description with 5W1H structure
49
+ */
50
+ buildEnrichedDescription(components) {
51
+ const parts = [];
52
+ if (components.original) {
53
+ parts.push(`## Original Description\n${components.original}`);
54
+ }
55
+ if (components.why) {
56
+ parts.push(`## Business Justification (Why)\n${components.why}`);
57
+ }
58
+ if (components.who) {
59
+ parts.push(`## Target Users (Who)\n${components.who}`);
60
+ }
61
+ if (components.what) {
62
+ parts.push(`## Core Features (What)\n${components.what}`);
63
+ }
64
+ if (components.how) {
65
+ parts.push(`## Technical Approach (How)\n${components.how}`);
66
+ }
67
+ if (components.successCriteria) {
68
+ parts.push(`## Success Criteria\n${components.successCriteria}`);
69
+ }
70
+ return parts.join("\n\n");
71
+ }
72
+ };
73
+ DescriptionEnricher = __decorate([
74
+ injectable()
75
+ ], DescriptionEnricher);
76
+ export { DescriptionEnricher };
77
+ //# sourceMappingURL=DescriptionEnricher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DescriptionEnricher.js","sourceRoot":"","sources":["../../../src/application/services/DescriptionEnricher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { ClarificationQuestion, ClarificationAnalysis, SteeringContext } from "../../domain/types.js";
2
+ export declare class QuestionGenerator {
3
+ /**
4
+ * Generate clarification questions based on analysis and steering context
5
+ */
6
+ generateQuestions(analysis: ClarificationAnalysis, context: SteeringContext): ClarificationQuestion[];
7
+ }
@@ -0,0 +1,30 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { injectable } from "inversify";
8
+ import { CLARIFICATION_QUESTIONS } from "./clarification-questions.js";
9
+ let QuestionGenerator = class QuestionGenerator {
10
+ /**
11
+ * Generate clarification questions based on analysis and steering context
12
+ */
13
+ generateQuestions(analysis, context) {
14
+ return Object.values(CLARIFICATION_QUESTIONS)
15
+ .filter((template) => template.condition(analysis, context))
16
+ .map((template) => ({
17
+ id: template.id,
18
+ category: template.category,
19
+ question: template.question,
20
+ why: template.rationale,
21
+ examples: template.examples,
22
+ required: template.required,
23
+ }));
24
+ }
25
+ };
26
+ QuestionGenerator = __decorate([
27
+ injectable()
28
+ ], QuestionGenerator);
29
+ export { QuestionGenerator };
30
+ //# sourceMappingURL=QuestionGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuestionGenerator.js","sourceRoot":"","sources":["../../../src/application/services/QuestionGenerator.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAMvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,IAAM,iBAAiB,GAAvB,MAAM,iBAAiB;IAC5B;;OAEG;IACH,iBAAiB,CACf,QAA+B,EAC/B,OAAwB;QAExB,OAAO,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC;aAC1C,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;aAC3D,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAClB,EAAE,EAAE,QAAQ,CAAC,EAAE;YACf,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,GAAG,EAAE,QAAQ,CAAC,SAAS;YACvB,QAAQ,EAAE,QAAQ,CAAC,QAAQ;YAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;SAC5B,CAAC,CAAC,CAAC;IACR,CAAC;CACF,CAAA;AAnBY,iBAAiB;IAD7B,UAAU,EAAE;GACA,iBAAiB,CAmB7B"}
@@ -1,9 +1,28 @@
1
- import { FileSystemPort, LoggerPort } from "../../domain/ports.js";
1
+ import { LoggerPort } from "../../domain/ports.js";
2
2
  import { ClarificationQuestion, EnrichedProjectDescription, ClarificationResult, ClarificationAnswers, AnswerValidationResult } from "../../domain/types.js";
3
+ import { SteeringContextLoader } from "./SteeringContextLoader.js";
4
+ import { DescriptionAnalyzer } from "./DescriptionAnalyzer.js";
5
+ import { QuestionGenerator } from "./QuestionGenerator.js";
6
+ import { AnswerValidator } from "./AnswerValidator.js";
7
+ import { DescriptionEnricher } from "./DescriptionEnricher.js";
8
+ /**
9
+ * Orchestrator service for requirements clarification workflow
10
+ *
11
+ * Delegates to specialized services:
12
+ * - SteeringContextLoader: Loads steering documents
13
+ * - DescriptionAnalyzer: Analyzes description quality
14
+ * - QuestionGenerator: Generates clarification questions
15
+ * - AnswerValidator: Validates user answers
16
+ * - DescriptionEnricher: Synthesizes enriched descriptions
17
+ */
3
18
  export declare class RequirementsClarificationService {
4
- private readonly fileSystem;
5
19
  private readonly logger;
6
- constructor(fileSystem: FileSystemPort, logger: LoggerPort);
20
+ private readonly steeringLoader;
21
+ private readonly analyzer;
22
+ private readonly questionGenerator;
23
+ private readonly answerValidator;
24
+ private readonly enricher;
25
+ constructor(logger: LoggerPort, steeringLoader: SteeringContextLoader, analyzer: DescriptionAnalyzer, questionGenerator: QuestionGenerator, answerValidator: AnswerValidator, enricher: DescriptionEnricher);
7
26
  /**
8
27
  * Analyzes a project description to determine if clarification is needed
9
28
  */
@@ -16,52 +35,4 @@ export declare class RequirementsClarificationService {
16
35
  * Synthesizes an enriched project description from original + answers
17
36
  */
18
37
  synthesizeDescription(originalDescription: string, questions: ClarificationQuestion[], answers: ClarificationAnswers): EnrichedProjectDescription;
19
- /**
20
- * Performs the core analysis of the description
21
- */
22
- private performAnalysis;
23
- /**
24
- * Generates targeted clarification questions based on analysis
25
- */
26
- private generateQuestions;
27
- /**
28
- * Load steering documents for context
29
- */
30
- private loadSteeringContext;
31
- /**
32
- * Detects if description contains WHY (business justification)
33
- */
34
- private detectWhy;
35
- /**
36
- * Detects if description contains WHO (target users)
37
- */
38
- private detectWho;
39
- /**
40
- * Detects if description contains WHAT (features, scope)
41
- */
42
- private detectWhat;
43
- /**
44
- * Detects if description contains success criteria
45
- */
46
- private detectSuccessCriteria;
47
- /**
48
- * Detects ambiguous terms that need clarification
49
- */
50
- private detectAmbiguousTerms;
51
- /**
52
- * Extracts surrounding context for an ambiguous term
53
- */
54
- private extractContext;
55
- /**
56
- * Calculates quality score based on completeness and clarity
57
- */
58
- private calculateQualityScore;
59
- /**
60
- * Extracts answers for a specific category
61
- */
62
- private extractAnswersByCategory;
63
- /**
64
- * Builds the enriched description from all components
65
- */
66
- private buildEnrichedDescription;
67
38
  }