opencode-conductor-cdd-plugin 1.0.0-beta.17 → 1.0.0-beta.19

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 (55) hide show
  1. package/dist/prompts/agent/cdd.md +16 -16
  2. package/dist/prompts/agent/implementer.md +5 -5
  3. package/dist/prompts/agent.md +7 -7
  4. package/dist/prompts/cdd/implement.json +1 -1
  5. package/dist/prompts/cdd/revert.json +1 -1
  6. package/dist/prompts/cdd/setup.json +2 -2
  7. package/dist/prompts/cdd/setup.test.js +40 -118
  8. package/dist/prompts/cdd/setup.test.ts +40 -143
  9. package/dist/test/integration/rebrand.test.js +15 -14
  10. package/dist/utils/agentMapping.js +2 -0
  11. package/dist/utils/archive-tracks.d.ts +28 -0
  12. package/dist/utils/archive-tracks.js +154 -1
  13. package/dist/utils/archive-tracks.test.d.ts +1 -0
  14. package/dist/utils/archive-tracks.test.js +495 -0
  15. package/dist/utils/codebaseAnalysis.d.ts +61 -0
  16. package/dist/utils/codebaseAnalysis.js +429 -0
  17. package/dist/utils/codebaseAnalysis.test.d.ts +1 -0
  18. package/dist/utils/codebaseAnalysis.test.js +556 -0
  19. package/dist/utils/documentGeneration.d.ts +97 -0
  20. package/dist/utils/documentGeneration.js +301 -0
  21. package/dist/utils/documentGeneration.test.d.ts +1 -0
  22. package/dist/utils/documentGeneration.test.js +380 -0
  23. package/dist/utils/interactiveMenu.d.ts +56 -0
  24. package/dist/utils/interactiveMenu.js +144 -0
  25. package/dist/utils/interactiveMenu.test.d.ts +1 -0
  26. package/dist/utils/interactiveMenu.test.js +231 -0
  27. package/dist/utils/interactiveSetup.d.ts +43 -0
  28. package/dist/utils/interactiveSetup.js +131 -0
  29. package/dist/utils/interactiveSetup.test.d.ts +1 -0
  30. package/dist/utils/interactiveSetup.test.js +124 -0
  31. package/dist/utils/metadataTracker.d.ts +39 -0
  32. package/dist/utils/metadataTracker.js +105 -0
  33. package/dist/utils/metadataTracker.test.d.ts +1 -0
  34. package/dist/utils/metadataTracker.test.js +265 -0
  35. package/dist/utils/planParser.d.ts +25 -0
  36. package/dist/utils/planParser.js +107 -0
  37. package/dist/utils/planParser.test.d.ts +1 -0
  38. package/dist/utils/planParser.test.js +119 -0
  39. package/dist/utils/projectMaturity.d.ts +53 -0
  40. package/dist/utils/projectMaturity.js +179 -0
  41. package/dist/utils/projectMaturity.test.d.ts +1 -0
  42. package/dist/utils/projectMaturity.test.js +298 -0
  43. package/dist/utils/questionGenerator.d.ts +51 -0
  44. package/dist/utils/questionGenerator.js +535 -0
  45. package/dist/utils/questionGenerator.test.d.ts +1 -0
  46. package/dist/utils/questionGenerator.test.js +328 -0
  47. package/dist/utils/setupIntegration.d.ts +72 -0
  48. package/dist/utils/setupIntegration.js +179 -0
  49. package/dist/utils/setupIntegration.test.d.ts +1 -0
  50. package/dist/utils/setupIntegration.test.js +344 -0
  51. package/dist/utils/statusDisplay.d.ts +35 -0
  52. package/dist/utils/statusDisplay.js +81 -0
  53. package/dist/utils/statusDisplay.test.d.ts +1 -0
  54. package/dist/utils/statusDisplay.test.js +102 -0
  55. package/package.json +1 -1
@@ -0,0 +1,56 @@
1
+ import { Question, QuestionType } from './questionGenerator.js';
2
+ /**
3
+ * Interactive Menu System
4
+ *
5
+ * Provides menu rendering and input validation for the CDD setup process.
6
+ * Adapts to LLM-based interaction pattern (no terminal UI library required).
7
+ *
8
+ * Features:
9
+ * - Format questions with lettered options (A-E)
10
+ * - Validate single/multiple selections
11
+ * - Parse user input into selection arrays
12
+ * - Render complete menus with instructions
13
+ *
14
+ * Based on reference implementations:
15
+ * - derekbar90/opencode-conductor
16
+ * - gemini-cli-extensions/conductor
17
+ */
18
+ export interface MenuOptions {
19
+ showInstructions?: boolean;
20
+ }
21
+ /**
22
+ * Format a question with numbered display and lettered options
23
+ *
24
+ * Example output:
25
+ * Question 1: What are the key features? (Select all that apply)
26
+ * A) User authentication
27
+ * B) Real-time updates
28
+ * C) Data analytics
29
+ * D) Enter custom features
30
+ * E) Auto-generate from codebase
31
+ */
32
+ export declare function formatQuestionWithOptions(question: Question, questionNumber: number): string;
33
+ /**
34
+ * Validate user selection input
35
+ *
36
+ * Rules:
37
+ * - Exclusive: Single letter A-E
38
+ * - Additive: Single letter or comma-separated (A,B,C)
39
+ * - Option E cannot be combined with others in additive
40
+ * - No duplicates allowed
41
+ * - Case insensitive
42
+ */
43
+ export declare function validateSelection(input: string, questionType: QuestionType): boolean;
44
+ /**
45
+ * Parse user selection input into array of letters
46
+ *
47
+ * Returns empty array if invalid
48
+ * Normalizes to uppercase, removes duplicates, and sorts for additive
49
+ */
50
+ export declare function parseSelection(input: string, questionType: QuestionType): string[];
51
+ /**
52
+ * Render complete interactive menu with question and instructions
53
+ *
54
+ * Generates LLM-compatible menu display suitable for text-based interaction
55
+ */
56
+ export declare function renderMenu(question: Question, questionNumber: number, options?: MenuOptions): string;
@@ -0,0 +1,144 @@
1
+ const VALID_OPTIONS = ['A', 'B', 'C', 'D', 'E'];
2
+ const MAX_OPTION_LENGTH = 80;
3
+ /**
4
+ * Format a question with numbered display and lettered options
5
+ *
6
+ * Example output:
7
+ * Question 1: What are the key features? (Select all that apply)
8
+ * A) User authentication
9
+ * B) Real-time updates
10
+ * C) Data analytics
11
+ * D) Enter custom features
12
+ * E) Auto-generate from codebase
13
+ */
14
+ export function formatQuestionWithOptions(question, questionNumber) {
15
+ const lines = [];
16
+ // Question header with number
17
+ const suffix = question.type === 'additive' ? ' (Select all that apply)' : '';
18
+ lines.push(`Question ${questionNumber}: ${question.text}${suffix}`);
19
+ lines.push('');
20
+ // Format options A-E
21
+ question.options.forEach((option, index) => {
22
+ const letter = VALID_OPTIONS[index];
23
+ // Truncate option text: if > 80, cut to fit "..." within 80 char limit
24
+ // Target: 80 max, so truncate to 75 + "..." (3) = 78 total
25
+ const truncated = option.length > MAX_OPTION_LENGTH
26
+ ? option.substring(0, 75) + '...'
27
+ : option;
28
+ lines.push(`${letter}) ${truncated}`);
29
+ });
30
+ return lines.join('\n');
31
+ }
32
+ /**
33
+ * Validate user selection input
34
+ *
35
+ * Rules:
36
+ * - Exclusive: Single letter A-E
37
+ * - Additive: Single letter or comma-separated (A,B,C)
38
+ * - Option E cannot be combined with others in additive
39
+ * - No duplicates allowed
40
+ * - Case insensitive
41
+ */
42
+ export function validateSelection(input, questionType) {
43
+ const trimmed = input.trim();
44
+ if (!trimmed) {
45
+ return false;
46
+ }
47
+ // Parse selections
48
+ const selections = trimmed
49
+ .split(',')
50
+ .map(s => s.trim().toUpperCase())
51
+ .filter(s => s.length > 0);
52
+ // Check for empty selections after split
53
+ if (selections.length === 0) {
54
+ return false;
55
+ }
56
+ // All selections must be valid letters (A-E)
57
+ for (const selection of selections) {
58
+ if (!VALID_OPTIONS.includes(selection)) {
59
+ return false;
60
+ }
61
+ }
62
+ // Check for duplicates using Set
63
+ const uniqueSelections = new Set(selections);
64
+ if (uniqueSelections.size !== selections.length) {
65
+ return false;
66
+ }
67
+ // Exclusive: Only one selection allowed
68
+ if (questionType === 'exclusive' && uniqueSelections.size > 1) {
69
+ return false;
70
+ }
71
+ // Option E (auto-generate) cannot be combined with others in additive
72
+ if (questionType === 'additive' && uniqueSelections.size > 1 && uniqueSelections.has('E')) {
73
+ return false;
74
+ }
75
+ return true;
76
+ }
77
+ /**
78
+ * Parse user selection input into array of letters
79
+ *
80
+ * Returns empty array if invalid
81
+ * Normalizes to uppercase, removes duplicates, and sorts for additive
82
+ */
83
+ export function parseSelection(input, questionType) {
84
+ const trimmed = input.trim();
85
+ if (!trimmed) {
86
+ return [];
87
+ }
88
+ // Parse and normalize
89
+ const selections = trimmed
90
+ .split(',')
91
+ .map(s => s.trim().toUpperCase())
92
+ .filter(s => s.length > 0);
93
+ // Remove duplicates
94
+ const uniqueSelections = [...new Set(selections)];
95
+ // Now validate the unique selections
96
+ const validationInput = uniqueSelections.join(',');
97
+ if (!validateSelection(validationInput, questionType)) {
98
+ return [];
99
+ }
100
+ // Sort additive selections for consistency
101
+ if (questionType === 'additive') {
102
+ return uniqueSelections.sort();
103
+ }
104
+ return uniqueSelections;
105
+ }
106
+ /**
107
+ * Get section-specific instruction text for the menu
108
+ */
109
+ function getSectionInstructions(question) {
110
+ const instructions = [];
111
+ if (question.type === 'additive') {
112
+ instructions.push('- You can select multiple options by separating them with commas (e.g., "A,B,C")');
113
+ instructions.push('- Or select a single option (e.g., "A")');
114
+ }
115
+ else {
116
+ instructions.push('- Select one option (e.g., "A")');
117
+ }
118
+ instructions.push('- Option D: Enter custom text when prompted');
119
+ instructions.push(`- Option E: Auto-generate this section from your codebase`);
120
+ if (question.type === 'additive') {
121
+ instructions.push('- Note: Option E cannot be combined with other options');
122
+ }
123
+ return instructions.join('\n');
124
+ }
125
+ /**
126
+ * Render complete interactive menu with question and instructions
127
+ *
128
+ * Generates LLM-compatible menu display suitable for text-based interaction
129
+ */
130
+ export function renderMenu(question, questionNumber, options = {}) {
131
+ const { showInstructions = true } = options;
132
+ const lines = [];
133
+ // Add formatted question with options
134
+ lines.push(formatQuestionWithOptions(question, questionNumber));
135
+ // Add instructions if enabled
136
+ if (showInstructions) {
137
+ lines.push('');
138
+ lines.push('Instructions:');
139
+ lines.push('Enter your selection (e.g., "A,B,C" for multiple or "A" for single)');
140
+ lines.push('');
141
+ lines.push(getSectionInstructions(question));
142
+ }
143
+ return lines.join('\n');
144
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,231 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { renderMenu, validateSelection, parseSelection, formatQuestionWithOptions, } from './interactiveMenu.js';
3
+ describe('interactiveMenu', () => {
4
+ describe('formatQuestionWithOptions', () => {
5
+ it('should format additive question with lettered options', () => {
6
+ const question = {
7
+ id: 'product-1',
8
+ text: 'What are the key features?',
9
+ type: 'additive',
10
+ section: 'product',
11
+ options: [
12
+ 'User authentication',
13
+ 'Real-time updates',
14
+ 'Data analytics',
15
+ 'Enter custom features',
16
+ 'Auto-generate from codebase',
17
+ ],
18
+ };
19
+ const result = formatQuestionWithOptions(question, 1);
20
+ expect(result).toContain('Question 1:');
21
+ expect(result).toContain('What are the key features? (Select all that apply)');
22
+ expect(result).toContain('A) User authentication');
23
+ expect(result).toContain('B) Real-time updates');
24
+ expect(result).toContain('C) Data analytics');
25
+ expect(result).toContain('D) Enter custom features');
26
+ expect(result).toContain('E) Auto-generate from codebase');
27
+ });
28
+ it('should format exclusive question without suffix', () => {
29
+ const question = {
30
+ id: 'product-2',
31
+ text: 'What is the primary platform?',
32
+ type: 'exclusive',
33
+ section: 'product',
34
+ options: ['Web', 'Mobile', 'Desktop', 'Custom', 'Auto-generate'],
35
+ };
36
+ const result = formatQuestionWithOptions(question, 2);
37
+ expect(result).toContain('Question 2:');
38
+ expect(result).toContain('What is the primary platform?');
39
+ expect(result).not.toContain('(Select all that apply)');
40
+ expect(result).toContain('A) Web');
41
+ expect(result).toContain('B) Mobile');
42
+ });
43
+ it('should truncate long options to 80 characters', () => {
44
+ const question = {
45
+ id: 'test-1',
46
+ text: 'Test question',
47
+ type: 'exclusive',
48
+ section: 'product',
49
+ options: [
50
+ 'This is a very long option text that exceeds the eighty character limit and should be truncated with ellipsis',
51
+ 'Short',
52
+ 'Custom',
53
+ 'Auto-generate',
54
+ 'Another option',
55
+ ],
56
+ };
57
+ const result = formatQuestionWithOptions(question, 1);
58
+ expect(result).toContain('A) This is a very long option text that exceeds the eighty character limit and...');
59
+ expect(result).toContain('B) Short');
60
+ });
61
+ it('should number questions starting from provided index', () => {
62
+ const question = {
63
+ id: 'test-1',
64
+ text: 'Test question',
65
+ type: 'exclusive',
66
+ section: 'product',
67
+ options: ['A', 'B', 'C', 'D', 'E'],
68
+ };
69
+ const result1 = formatQuestionWithOptions(question, 1);
70
+ const result5 = formatQuestionWithOptions(question, 5);
71
+ expect(result1).toContain('Question 1:');
72
+ expect(result5).toContain('Question 5:');
73
+ });
74
+ });
75
+ describe('validateSelection', () => {
76
+ it('should accept valid single letter for exclusive choice', () => {
77
+ expect(validateSelection('A', 'exclusive')).toBe(true);
78
+ expect(validateSelection('B', 'exclusive')).toBe(true);
79
+ expect(validateSelection('C', 'exclusive')).toBe(true);
80
+ expect(validateSelection('D', 'exclusive')).toBe(true);
81
+ expect(validateSelection('E', 'exclusive')).toBe(true);
82
+ });
83
+ it('should accept lowercase letters for exclusive choice', () => {
84
+ expect(validateSelection('a', 'exclusive')).toBe(true);
85
+ expect(validateSelection('e', 'exclusive')).toBe(true);
86
+ });
87
+ it('should reject invalid letters for exclusive choice', () => {
88
+ expect(validateSelection('F', 'exclusive')).toBe(false);
89
+ expect(validateSelection('Z', 'exclusive')).toBe(false);
90
+ expect(validateSelection('1', 'exclusive')).toBe(false);
91
+ });
92
+ it('should reject multiple selections for exclusive choice', () => {
93
+ expect(validateSelection('A,B', 'exclusive')).toBe(false);
94
+ expect(validateSelection('A,B,C', 'exclusive')).toBe(false);
95
+ });
96
+ it('should accept valid single letter for additive choice', () => {
97
+ expect(validateSelection('A', 'additive')).toBe(true);
98
+ expect(validateSelection('E', 'additive')).toBe(true);
99
+ });
100
+ it('should accept multiple comma-separated letters for additive choice', () => {
101
+ expect(validateSelection('A,B', 'additive')).toBe(true);
102
+ expect(validateSelection('A,B,C', 'additive')).toBe(true);
103
+ expect(validateSelection('A,C,D', 'additive')).toBe(true);
104
+ });
105
+ it('should accept multiple letters with spaces for additive choice', () => {
106
+ expect(validateSelection('A, B', 'additive')).toBe(true);
107
+ expect(validateSelection('A, B, C', 'additive')).toBe(true);
108
+ expect(validateSelection(' A , B , C ', 'additive')).toBe(true);
109
+ });
110
+ it('should reject if any letter is invalid in additive choice', () => {
111
+ expect(validateSelection('A,F', 'additive')).toBe(false);
112
+ expect(validateSelection('A,B,Z', 'additive')).toBe(false);
113
+ expect(validateSelection('A,1', 'additive')).toBe(false);
114
+ });
115
+ it('should reject duplicate selections in additive choice', () => {
116
+ expect(validateSelection('A,A', 'additive')).toBe(false);
117
+ expect(validateSelection('A,B,A', 'additive')).toBe(false);
118
+ });
119
+ it('should reject empty input', () => {
120
+ expect(validateSelection('', 'exclusive')).toBe(false);
121
+ expect(validateSelection('', 'additive')).toBe(false);
122
+ expect(validateSelection(' ', 'exclusive')).toBe(false);
123
+ });
124
+ it('should reject option E in combination with others for additive', () => {
125
+ expect(validateSelection('A,E', 'additive')).toBe(false);
126
+ expect(validateSelection('E,A', 'additive')).toBe(false);
127
+ expect(validateSelection('A,B,E', 'additive')).toBe(false);
128
+ });
129
+ it('should accept option E alone for additive', () => {
130
+ expect(validateSelection('E', 'additive')).toBe(true);
131
+ });
132
+ });
133
+ describe('parseSelection', () => {
134
+ it('should parse single exclusive selection', () => {
135
+ expect(parseSelection('A', 'exclusive')).toEqual(['A']);
136
+ expect(parseSelection('E', 'exclusive')).toEqual(['E']);
137
+ });
138
+ it('should normalize to uppercase', () => {
139
+ expect(parseSelection('a', 'exclusive')).toEqual(['A']);
140
+ expect(parseSelection('e', 'exclusive')).toEqual(['E']);
141
+ });
142
+ it('should parse single additive selection', () => {
143
+ expect(parseSelection('A', 'additive')).toEqual(['A']);
144
+ });
145
+ it('should parse multiple additive selections', () => {
146
+ expect(parseSelection('A,B', 'additive')).toEqual(['A', 'B']);
147
+ expect(parseSelection('A,B,C', 'additive')).toEqual(['A', 'B', 'C']);
148
+ });
149
+ it('should parse multiple selections with spaces', () => {
150
+ expect(parseSelection('A, B', 'additive')).toEqual(['A', 'B']);
151
+ expect(parseSelection(' A , B , C ', 'additive')).toEqual(['A', 'B', 'C']);
152
+ });
153
+ it('should parse lowercase multiple selections', () => {
154
+ expect(parseSelection('a,b,c', 'additive')).toEqual(['A', 'B', 'C']);
155
+ });
156
+ it('should return empty array for invalid input', () => {
157
+ expect(parseSelection('', 'exclusive')).toEqual([]);
158
+ expect(parseSelection('F', 'exclusive')).toEqual([]);
159
+ expect(parseSelection('A,F', 'additive')).toEqual([]);
160
+ });
161
+ it('should remove duplicates and sort for additive', () => {
162
+ expect(parseSelection('C,A,B', 'additive')).toEqual(['A', 'B', 'C']);
163
+ expect(parseSelection('B,A,C,A', 'additive')).toEqual(['A', 'B', 'C']);
164
+ });
165
+ });
166
+ describe('renderMenu', () => {
167
+ it('should render complete menu with instructions', () => {
168
+ const question = {
169
+ id: 'product-1',
170
+ text: 'What are the key features?',
171
+ type: 'additive',
172
+ section: 'product',
173
+ options: ['Auth', 'Real-time', 'Analytics', 'Custom', 'Auto-generate'],
174
+ };
175
+ const options = {
176
+ showInstructions: true,
177
+ };
178
+ const result = renderMenu(question, 1, options);
179
+ expect(result).toContain('Question 1:');
180
+ expect(result).toContain('What are the key features?');
181
+ expect(result).toContain('A) Auth');
182
+ expect(result).toContain('Instructions:');
183
+ expect(result).toContain('Enter your selection (e.g., "A,B,C" for multiple or "A" for single)');
184
+ });
185
+ it('should render menu without instructions when disabled', () => {
186
+ const question = {
187
+ id: 'product-1',
188
+ text: 'Test',
189
+ type: 'exclusive',
190
+ section: 'product',
191
+ options: ['A', 'B', 'C', 'D', 'E'],
192
+ };
193
+ const options = {
194
+ showInstructions: false,
195
+ };
196
+ const result = renderMenu(question, 1, options);
197
+ expect(result).not.toContain('Instructions:');
198
+ });
199
+ it('should include section-specific autogenerate text for option E', () => {
200
+ const productQuestion = {
201
+ id: 'product-1',
202
+ text: 'Test',
203
+ type: 'exclusive',
204
+ section: 'product',
205
+ options: ['A', 'B', 'C', 'D', 'Auto-generate product guide from codebase'],
206
+ };
207
+ const result = renderMenu(productQuestion, 1, { showInstructions: false });
208
+ expect(result).toContain('E) Auto-generate product guide from codebase');
209
+ });
210
+ it('should show different instructions for additive vs exclusive', () => {
211
+ const additiveQuestion = {
212
+ id: 'test-1',
213
+ text: 'Test additive',
214
+ type: 'additive',
215
+ section: 'product',
216
+ options: ['A', 'B', 'C', 'D', 'E'],
217
+ };
218
+ const exclusiveQuestion = {
219
+ id: 'test-2',
220
+ text: 'Test exclusive',
221
+ type: 'exclusive',
222
+ section: 'product',
223
+ options: ['A', 'B', 'C', 'D', 'E'],
224
+ };
225
+ const additiveResult = renderMenu(additiveQuestion, 1, { showInstructions: true });
226
+ const exclusiveResult = renderMenu(exclusiveQuestion, 1, { showInstructions: true });
227
+ expect(additiveResult).toContain('Select all that apply');
228
+ expect(exclusiveResult).not.toContain('Select all that apply');
229
+ });
230
+ });
231
+ });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Interactive Setup Command Handler
3
+ *
4
+ * This module provides the entry point for the interactive CDD setup experience.
5
+ * It replaces the static JSON-based setup prompt with a dynamic, code-driven workflow.
6
+ *
7
+ * Features:
8
+ * - Auto-detects project maturity (greenfield vs brownfield)
9
+ * - Generates context-aware questions based on codebase analysis
10
+ * - Interactive menu with 5 options per question (A-C contextual, D custom, E auto-generate)
11
+ * - Creates all 5 CDD documents: product.md, guidelines.md, tech-stack.md, styleguides.md, workflow.md
12
+ * - Resume functionality via setup_state.json checkpoints
13
+ * - Approval/revision loops for each document
14
+ */
15
+ /**
16
+ * Interactive Setup Configuration
17
+ */
18
+ export interface InteractiveSetupConfig {
19
+ projectPath: string;
20
+ outputDir?: string;
21
+ maxRevisions?: number;
22
+ resume?: boolean;
23
+ language?: 'en' | 'es';
24
+ }
25
+ /**
26
+ * Setup Result for API consumers
27
+ */
28
+ export interface InteractiveSetupResult {
29
+ success: boolean;
30
+ message: string;
31
+ documentsCreated: string[];
32
+ errors?: string[];
33
+ resumed?: boolean;
34
+ resumedFrom?: string;
35
+ }
36
+ /**
37
+ * Main entry point for interactive setup
38
+ */
39
+ export declare function executeInteractiveSetup(config: InteractiveSetupConfig): Promise<InteractiveSetupResult>;
40
+ /**
41
+ * Generate setup summary message
42
+ */
43
+ export declare function generateSetupSummary(result: InteractiveSetupResult): string;
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Interactive Setup Command Handler
3
+ *
4
+ * This module provides the entry point for the interactive CDD setup experience.
5
+ * It replaces the static JSON-based setup prompt with a dynamic, code-driven workflow.
6
+ *
7
+ * Features:
8
+ * - Auto-detects project maturity (greenfield vs brownfield)
9
+ * - Generates context-aware questions based on codebase analysis
10
+ * - Interactive menu with 5 options per question (A-C contextual, D custom, E auto-generate)
11
+ * - Creates all 5 CDD documents: product.md, guidelines.md, tech-stack.md, styleguides.md, workflow.md
12
+ * - Resume functionality via setup_state.json checkpoints
13
+ * - Approval/revision loops for each document
14
+ */
15
+ import * as path from 'path';
16
+ import { runFullSetup } from './setupIntegration.js';
17
+ /**
18
+ * Default responder for interactive CLI
19
+ * This is a placeholder - the actual implementation should use
20
+ * the OpenCode CLI input tools for interactive prompts
21
+ *
22
+ * For testing: Returns option 'E' (auto-generate) to avoid hanging
23
+ */
24
+ async function defaultResponder(question, questionNumber) {
25
+ // In production, this would use OpenCode CLI input
26
+ // For now, auto-select option E to enable testing
27
+ return ['E'];
28
+ }
29
+ /**
30
+ * Default approval flow for document review
31
+ * This is a placeholder - the actual implementation should use
32
+ * the OpenCode CLI input tools for approval prompts
33
+ */
34
+ async function defaultApprovalFlow(draft) {
35
+ // TODO: Replace with actual OpenCode CLI approval prompt
36
+ console.log('\n[Document Draft Generated]');
37
+ console.log(`Word count: ${draft.wordCount}`);
38
+ console.log(`Sections included: ${draft.sectionsIncluded.length}`);
39
+ // For now, auto-approve
40
+ // This will be replaced when integrated with OpenCode CLI
41
+ return {
42
+ approved: true,
43
+ };
44
+ }
45
+ /**
46
+ * Main entry point for interactive setup
47
+ */
48
+ export async function executeInteractiveSetup(config) {
49
+ try {
50
+ const outputDir = config.outputDir || path.join(config.projectPath, 'conductor-cdd');
51
+ const setupOptions = {
52
+ projectPath: config.projectPath,
53
+ outputDir,
54
+ responder: defaultResponder,
55
+ approvalFlow: defaultApprovalFlow,
56
+ maxRevisions: config.maxRevisions || 3,
57
+ resume: config.resume || false,
58
+ };
59
+ const result = await runFullSetup(setupOptions);
60
+ if (result.success) {
61
+ return {
62
+ success: true,
63
+ message: `Successfully created ${result.documentsCreated.length} CDD documents`,
64
+ documentsCreated: result.documentsCreated,
65
+ resumed: result.resumed,
66
+ resumedFrom: result.resumedFrom,
67
+ };
68
+ }
69
+ else {
70
+ return {
71
+ success: false,
72
+ message: result.error || 'Setup failed',
73
+ documentsCreated: result.documentsCreated || [],
74
+ errors: result.error ? [result.error] : [],
75
+ };
76
+ }
77
+ }
78
+ catch (error) {
79
+ return {
80
+ success: false,
81
+ message: 'Interactive setup failed with an unexpected error',
82
+ documentsCreated: [],
83
+ errors: [error instanceof Error ? error.message : String(error)],
84
+ };
85
+ }
86
+ }
87
+ /**
88
+ * Generate setup summary message
89
+ */
90
+ export function generateSetupSummary(result) {
91
+ const lines = [];
92
+ if (result.success) {
93
+ lines.push('✅ CDD Setup Complete!');
94
+ lines.push('');
95
+ if (result.resumed) {
96
+ lines.push(`📋 Resumed from checkpoint: ${result.resumedFrom}`);
97
+ lines.push('');
98
+ }
99
+ lines.push('📄 Documents created:');
100
+ result.documentsCreated.forEach(doc => {
101
+ lines.push(` • ${path.basename(doc)}`);
102
+ });
103
+ lines.push('');
104
+ lines.push('🎯 Next steps:');
105
+ lines.push(' 1. Review the generated documents in conductor-cdd/');
106
+ lines.push(' 2. Customize them to match your project needs');
107
+ lines.push(' 3. Start your first track with: cdd:new-track');
108
+ }
109
+ else {
110
+ lines.push('❌ CDD Setup Failed');
111
+ lines.push('');
112
+ lines.push(`Error: ${result.message}`);
113
+ if (result.documentsCreated.length > 0) {
114
+ lines.push('');
115
+ lines.push('⚠️ Partially completed documents:');
116
+ result.documentsCreated.forEach(doc => {
117
+ lines.push(` • ${path.basename(doc)}`);
118
+ });
119
+ lines.push('');
120
+ lines.push('💡 You can resume setup by running cdd:setup again');
121
+ }
122
+ if (result.errors && result.errors.length > 0) {
123
+ lines.push('');
124
+ lines.push('🔍 Error details:');
125
+ result.errors.forEach(err => {
126
+ lines.push(` • ${err}`);
127
+ });
128
+ }
129
+ }
130
+ return lines.join('\n');
131
+ }
@@ -0,0 +1 @@
1
+ export {};