clavix 2.7.0 → 2.8.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 (165) hide show
  1. package/README.md +22 -8
  2. package/bin/clavix.js +12 -5
  3. package/dist/cli/commands/archive.d.ts +5 -4
  4. package/dist/cli/commands/archive.js +135 -161
  5. package/dist/cli/commands/config.d.ts +4 -4
  6. package/dist/cli/commands/config.js +66 -105
  7. package/dist/cli/commands/deep.d.ts +3 -3
  8. package/dist/cli/commands/deep.js +97 -103
  9. package/dist/cli/commands/execute.d.ts +4 -4
  10. package/dist/cli/commands/execute.js +57 -63
  11. package/dist/cli/commands/fast.d.ts +3 -3
  12. package/dist/cli/commands/fast.js +122 -128
  13. package/dist/cli/commands/implement.d.ts +4 -4
  14. package/dist/cli/commands/implement.js +84 -148
  15. package/dist/cli/commands/init.js +87 -126
  16. package/dist/cli/commands/list.d.ts +5 -5
  17. package/dist/cli/commands/list.js +72 -111
  18. package/dist/cli/commands/plan.d.ts +7 -7
  19. package/dist/cli/commands/plan.js +92 -131
  20. package/dist/cli/commands/prd.d.ts +4 -4
  21. package/dist/cli/commands/prd.js +76 -111
  22. package/dist/cli/commands/prompts/clear.d.ts +6 -6
  23. package/dist/cli/commands/prompts/clear.js +70 -76
  24. package/dist/cli/commands/prompts/list.js +37 -43
  25. package/dist/cli/commands/show.d.ts +4 -4
  26. package/dist/cli/commands/show.js +72 -111
  27. package/dist/cli/commands/start.d.ts +3 -3
  28. package/dist/cli/commands/start.js +63 -101
  29. package/dist/cli/commands/summarize.d.ts +4 -4
  30. package/dist/cli/commands/summarize.js +81 -120
  31. package/dist/cli/commands/task-complete.d.ts +4 -4
  32. package/dist/cli/commands/task-complete.js +86 -123
  33. package/dist/cli/commands/update.d.ts +3 -3
  34. package/dist/cli/commands/update.js +97 -130
  35. package/dist/cli/commands/version.js +13 -48
  36. package/dist/core/adapters/agents-md-generator.js +17 -50
  37. package/dist/core/adapters/amp-adapter.d.ts +1 -1
  38. package/dist/core/adapters/amp-adapter.js +13 -21
  39. package/dist/core/adapters/augment-adapter.d.ts +2 -2
  40. package/dist/core/adapters/augment-adapter.js +16 -56
  41. package/dist/core/adapters/base-adapter.d.ts +1 -1
  42. package/dist/core/adapters/base-adapter.js +11 -47
  43. package/dist/core/adapters/claude-code-adapter.d.ts +2 -2
  44. package/dist/core/adapters/claude-code-adapter.js +19 -60
  45. package/dist/core/adapters/cline-adapter.d.ts +1 -1
  46. package/dist/core/adapters/cline-adapter.js +13 -21
  47. package/dist/core/adapters/codebuddy-adapter.d.ts +2 -2
  48. package/dist/core/adapters/codebuddy-adapter.js +17 -57
  49. package/dist/core/adapters/codex-adapter.d.ts +2 -2
  50. package/dist/core/adapters/codex-adapter.js +16 -56
  51. package/dist/core/adapters/copilot-instructions-generator.js +18 -51
  52. package/dist/core/adapters/crush-adapter.d.ts +2 -2
  53. package/dist/core/adapters/crush-adapter.js +13 -20
  54. package/dist/core/adapters/cursor-adapter.d.ts +1 -1
  55. package/dist/core/adapters/cursor-adapter.js +12 -20
  56. package/dist/core/adapters/droid-adapter.d.ts +2 -2
  57. package/dist/core/adapters/droid-adapter.js +14 -21
  58. package/dist/core/adapters/gemini-adapter.d.ts +2 -2
  59. package/dist/core/adapters/gemini-adapter.js +16 -52
  60. package/dist/core/adapters/kilocode-adapter.d.ts +1 -1
  61. package/dist/core/adapters/kilocode-adapter.js +12 -20
  62. package/dist/core/adapters/octo-md-generator.js +17 -50
  63. package/dist/core/adapters/opencode-adapter.d.ts +2 -2
  64. package/dist/core/adapters/opencode-adapter.js +14 -21
  65. package/dist/core/adapters/qwen-adapter.d.ts +2 -2
  66. package/dist/core/adapters/qwen-adapter.js +16 -52
  67. package/dist/core/adapters/roocode-adapter.d.ts +2 -2
  68. package/dist/core/adapters/roocode-adapter.js +12 -19
  69. package/dist/core/adapters/warp-md-generator.js +17 -50
  70. package/dist/core/adapters/windsurf-adapter.d.ts +1 -1
  71. package/dist/core/adapters/windsurf-adapter.js +12 -20
  72. package/dist/core/agent-manager.d.ts +1 -1
  73. package/dist/core/agent-manager.js +34 -38
  74. package/dist/core/archive-manager.js +10 -46
  75. package/dist/core/config-manager.d.ts +2 -2
  76. package/dist/core/config-manager.js +3 -40
  77. package/dist/core/conversation-analyzer.d.ts +1 -1
  78. package/dist/core/conversation-analyzer.js +1 -5
  79. package/dist/core/doc-injector.js +23 -60
  80. package/dist/core/git-manager.js +11 -48
  81. package/dist/core/prd-generator.js +16 -51
  82. package/dist/core/prompt-manager.js +6 -42
  83. package/dist/core/prompt-optimizer.js +1 -5
  84. package/dist/core/question-engine.js +6 -45
  85. package/dist/core/session-manager.d.ts +1 -1
  86. package/dist/core/session-manager.js +11 -49
  87. package/dist/core/task-manager.d.ts +26 -0
  88. package/dist/core/task-manager.js +243 -101
  89. package/dist/index.d.ts +2 -1
  90. package/dist/index.js +8 -12
  91. package/dist/templates/agents/agents.md +31 -2
  92. package/dist/templates/agents/copilot-instructions.md +1 -1
  93. package/dist/templates/agents/octo.md +20 -1
  94. package/dist/templates/agents/warp.md +1 -1
  95. package/dist/templates/slash-commands/_canonical/implement.md +33 -11
  96. package/dist/types/agent.js +1 -2
  97. package/dist/types/config.js +3 -8
  98. package/dist/types/errors.js +7 -13
  99. package/dist/types/session.js +1 -2
  100. package/dist/utils/agent-error-messages.js +1 -5
  101. package/dist/utils/error-utils.js +5 -12
  102. package/dist/utils/file-system.js +20 -57
  103. package/dist/utils/legacy-command-cleanup.d.ts +1 -1
  104. package/dist/utils/legacy-command-cleanup.js +9 -45
  105. package/dist/utils/template-loader.d.ts +1 -1
  106. package/dist/utils/template-loader.js +9 -41
  107. package/dist/utils/toml-templates.js +1 -4
  108. package/package.json +12 -7
  109. package/dist/core/adapters 2/agents-md-generator.d.ts +0 -26
  110. package/dist/core/adapters 2/agents-md-generator.js +0 -102
  111. package/dist/core/adapters 2/amp-adapter.d.ts +0 -27
  112. package/dist/core/adapters 2/amp-adapter.js +0 -42
  113. package/dist/core/adapters 2/augment-adapter.d.ts +0 -22
  114. package/dist/core/adapters 2/augment-adapter.js +0 -77
  115. package/dist/core/adapters 2/base-adapter.d.ts +0 -45
  116. package/dist/core/adapters 2/base-adapter.js +0 -142
  117. package/dist/core/adapters 2/claude-code-adapter.d.ts +0 -32
  118. package/dist/core/adapters 2/claude-code-adapter.js +0 -116
  119. package/dist/core/adapters 2/cline-adapter.d.ts +0 -34
  120. package/dist/core/adapters 2/cline-adapter.js +0 -52
  121. package/dist/core/adapters 2/codebuddy-adapter.d.ts +0 -24
  122. package/dist/core/adapters 2/codebuddy-adapter.js +0 -82
  123. package/dist/core/adapters 2/codex-adapter.d.ts +0 -24
  124. package/dist/core/adapters 2/codex-adapter.js +0 -79
  125. package/dist/core/adapters 2/copilot-instructions-generator.d.ts +0 -26
  126. package/dist/core/adapters 2/copilot-instructions-generator.js +0 -104
  127. package/dist/core/adapters 2/crush-adapter.d.ts +0 -35
  128. package/dist/core/adapters 2/crush-adapter.js +0 -49
  129. package/dist/core/adapters 2/cursor-adapter.d.ts +0 -25
  130. package/dist/core/adapters 2/cursor-adapter.js +0 -40
  131. package/dist/core/adapters 2/droid-adapter.d.ts +0 -33
  132. package/dist/core/adapters 2/droid-adapter.js +0 -57
  133. package/dist/core/adapters 2/gemini-adapter.d.ts +0 -27
  134. package/dist/core/adapters 2/gemini-adapter.js +0 -90
  135. package/dist/core/adapters 2/kilocode-adapter.d.ts +0 -34
  136. package/dist/core/adapters 2/kilocode-adapter.js +0 -49
  137. package/dist/core/adapters 2/octo-md-generator.d.ts +0 -26
  138. package/dist/core/adapters 2/octo-md-generator.js +0 -102
  139. package/dist/core/adapters 2/opencode-adapter.d.ts +0 -33
  140. package/dist/core/adapters 2/opencode-adapter.js +0 -56
  141. package/dist/core/adapters 2/qwen-adapter.d.ts +0 -27
  142. package/dist/core/adapters 2/qwen-adapter.js +0 -90
  143. package/dist/core/adapters 2/roocode-adapter.d.ts +0 -40
  144. package/dist/core/adapters 2/roocode-adapter.js +0 -68
  145. package/dist/core/adapters 2/warp-md-generator.d.ts +0 -17
  146. package/dist/core/adapters 2/warp-md-generator.js +0 -88
  147. package/dist/core/adapters 2/windsurf-adapter.d.ts +0 -34
  148. package/dist/core/adapters 2/windsurf-adapter.js +0 -49
  149. package/dist/core/agent-manager 2.js +0 -126
  150. package/dist/core/agent-manager.d 2.ts +0 -51
  151. package/dist/core/archive-manager 2.js +0 -338
  152. package/dist/core/archive-manager.d 2.ts +0 -100
  153. package/dist/core/conversation-analyzer.d 2.ts +0 -86
  154. package/dist/core/doc-injector 2.js +0 -236
  155. package/dist/core/doc-injector.d 2.ts +0 -51
  156. package/dist/core/git-manager 2.js +0 -214
  157. package/dist/core/git-manager.d 2.ts +0 -100
  158. package/dist/core/prompt-optimizer 2.js +0 -963
  159. package/dist/core/prompt-optimizer.d 2.ts +0 -268
  160. package/dist/core/question-engine 2.js +0 -395
  161. package/dist/core/question-engine.d 2.ts +0 -167
  162. package/dist/core/session-manager 2.js +0 -403
  163. package/dist/core/session-manager.d 2.ts +0 -139
  164. package/dist/core/task-manager 2.js +0 -689
  165. package/dist/core/task-manager.d 2.ts +0 -155
@@ -1,268 +0,0 @@
1
- /**
2
- * PromptOptimizer - Analyzes and improves prompts using the CLEAR Framework
3
- * CLEAR Framework: Concise, Logical, Explicit, Adaptive, Reflective
4
- * Developed by Dr. Leo Lo, University of New Mexico
5
- * Reference: https://guides.library.tamucc.edu/prompt-engineering/clear
6
- */
7
- export type OptimizerMode = 'fast' | 'deep';
8
- export interface PromptAnalysis {
9
- gaps: string[];
10
- ambiguities: string[];
11
- strengths: string[];
12
- suggestions: string[];
13
- }
14
- export interface ConciseAnalysis {
15
- score: number;
16
- verbosityCount: number;
17
- pleasantriesCount: number;
18
- signalToNoiseRatio: number;
19
- issues: string[];
20
- suggestions: string[];
21
- }
22
- export interface LogicAnalysis {
23
- score: number;
24
- hasCoherentFlow: boolean;
25
- sequencingIssues: string[];
26
- suggestedOrder: string[];
27
- issues: string[];
28
- suggestions: string[];
29
- }
30
- export interface ExplicitAnalysis {
31
- score: number;
32
- hasPersona: boolean;
33
- hasOutputFormat: boolean;
34
- hasToneStyle: boolean;
35
- hasSuccessCriteria: boolean;
36
- hasExamples: boolean;
37
- issues: string[];
38
- suggestions: string[];
39
- }
40
- export interface AdaptiveAnalysis {
41
- score: number;
42
- alternativePhrasings: string[];
43
- alternativeStructures: Array<{
44
- name: string;
45
- structure: string;
46
- benefits: string;
47
- }>;
48
- temperatureRecommendation: number;
49
- issues: string[];
50
- suggestions: string[];
51
- }
52
- export interface ReflectiveAnalysis {
53
- score: number;
54
- validationChecklist: string[];
55
- edgeCases: string[];
56
- potentialIssues: string[];
57
- factCheckingSteps: string[];
58
- qualityCriteria: string[];
59
- issues: string[];
60
- suggestions: string[];
61
- }
62
- export interface CLEARResult {
63
- conciseness: ConciseAnalysis;
64
- logic: LogicAnalysis;
65
- explicitness: ExplicitAnalysis;
66
- adaptiveness?: AdaptiveAnalysis;
67
- reflectiveness?: ReflectiveAnalysis;
68
- overallScore: number;
69
- improvedPrompt: string;
70
- changesSummary: Array<{
71
- component: 'C' | 'L' | 'E' | 'A' | 'R';
72
- change: string;
73
- }>;
74
- }
75
- export interface CLEARScore {
76
- overall: number;
77
- conciseness: number;
78
- logic: number;
79
- explicitness: number;
80
- adaptiveness?: number;
81
- reflectiveness?: number;
82
- rating: 'excellent' | 'good' | 'needs-improvement' | 'poor';
83
- }
84
- export interface TriageResult {
85
- needsDeepAnalysis: boolean;
86
- reasons: string[];
87
- }
88
- export interface QualityAssessment {
89
- isAlreadyGood: boolean;
90
- criteriaMetCount: number;
91
- totalCriteria: number;
92
- criteriaResults: {
93
- clearGoal: boolean;
94
- sufficientContext: boolean;
95
- actionableLanguage: boolean;
96
- reasonableScope: boolean;
97
- };
98
- }
99
- export interface ChangesSummary {
100
- changes: string[];
101
- }
102
- export interface ImprovedPrompt {
103
- original: string;
104
- analysis: PromptAnalysis;
105
- improved: string;
106
- changesSummary?: ChangesSummary;
107
- triageResult?: TriageResult;
108
- qualityAssessment?: QualityAssessment;
109
- alternativePhrasings?: string[];
110
- edgeCases?: string[];
111
- implementationExamples?: {
112
- good: string[];
113
- bad: string[];
114
- };
115
- alternativeStructures?: Array<{
116
- structure: string;
117
- benefits: string;
118
- }>;
119
- potentialIssues?: string[];
120
- }
121
- export declare class PromptOptimizer {
122
- /**
123
- * Analyze a prompt and identify issues
124
- */
125
- analyze(prompt: string): PromptAnalysis;
126
- /**
127
- * Perform smart triage to determine if deep analysis is recommended
128
- */
129
- performTriage(prompt: string): TriageResult;
130
- /**
131
- * Assess prompt quality
132
- */
133
- assessQuality(prompt: string): QualityAssessment;
134
- /**
135
- * Generate an improved version of the prompt
136
- */
137
- improve(prompt: string, mode?: OptimizerMode): ImprovedPrompt;
138
- /**
139
- * Apply CLEAR Framework analysis to a prompt
140
- * C = Concise, L = Logical, E = Explicit, A = Adaptive (deep only), R = Reflective (deep only)
141
- */
142
- applyCLEARFramework(prompt: string, mode?: OptimizerMode): CLEARResult;
143
- /**
144
- * Analyze Conciseness (C): Brevity and clarity
145
- */
146
- analyzeConciseness(prompt: string): ConciseAnalysis;
147
- /**
148
- * Analyze Logic (L): Structured and coherent prompts
149
- */
150
- analyzeLogic(prompt: string): LogicAnalysis;
151
- /**
152
- * Analyze Explicitness (E): Clear output specifications
153
- */
154
- analyzeExplicitness(prompt: string): ExplicitAnalysis;
155
- /**
156
- * Analyze Adaptiveness (A): Flexibility and customization
157
- */
158
- analyzeAdaptiveness(prompt: string): AdaptiveAnalysis;
159
- /**
160
- * Analyze Reflectiveness (R): Continuous evaluation and improvement
161
- */
162
- analyzeReflectiveness(prompt: string): ReflectiveAnalysis;
163
- /**
164
- * Calculate overall CLEAR score with weighted components
165
- */
166
- calculateCLEARScore(analysis: {
167
- conciseness: ConciseAnalysis;
168
- logic: LogicAnalysis;
169
- explicitness: ExplicitAnalysis;
170
- adaptiveness?: AdaptiveAnalysis;
171
- reflectiveness?: ReflectiveAnalysis;
172
- }): CLEARScore;
173
- /**
174
- * Generate improved prompt using CLEAR framework insights
175
- */
176
- private generateCLEARImprovedPrompt;
177
- /**
178
- * Generate CLEAR-labeled changes summary
179
- */
180
- private generateCLEARChangesSummary;
181
- /**
182
- * Map CLEAR result to legacy PromptAnalysis format for backward compatibility
183
- */
184
- mapCLEARToLegacy(clearResult: CLEARResult): PromptAnalysis;
185
- /**
186
- * Extract strengths from CLEAR analysis
187
- */
188
- private extractCLEARStrengths;
189
- /**
190
- * Find gaps in the prompt
191
- */
192
- private findGaps;
193
- /**
194
- * Find ambiguities in the prompt
195
- */
196
- private findAmbiguities;
197
- /**
198
- * Find strengths in the prompt
199
- */
200
- private findStrengths;
201
- /**
202
- * Generate improvement suggestions
203
- */
204
- private generateSuggestions;
205
- /**
206
- * Generate improved prompt with structure
207
- */
208
- private generateImprovedPrompt;
209
- private hasContext;
210
- private hasSuccessCriteria;
211
- private hasTechnicalDetails;
212
- private hasUserNeeds;
213
- private hasExpectedOutput;
214
- private extractOrInferObjective;
215
- private extractOrInferRequirements;
216
- private extractOrInferTechnical;
217
- private extractOrInferOutput;
218
- private extractOrInferSuccess;
219
- /**
220
- * Count missing critical elements
221
- */
222
- private countMissingCriticalElements;
223
- /**
224
- * Check for vague scope words without sufficient context
225
- */
226
- private hasVagueScopeWithoutContext;
227
- /**
228
- * Check if prompt has a clear goal
229
- */
230
- private hasClearGoal;
231
- /**
232
- * Check if prompt uses actionable language
233
- */
234
- private hasActionableLanguage;
235
- /**
236
- * Check if prompt has reasonable scope
237
- */
238
- private hasReasonableScope;
239
- /**
240
- * Generate changes summary
241
- */
242
- private generateChangesSummary;
243
- /**
244
- * Generate alternative phrasings (deep mode)
245
- */
246
- private generateAlternativePhrasings;
247
- /**
248
- * Identify edge cases in requirements (deep mode)
249
- */
250
- private identifyEdgeCases;
251
- /**
252
- * Generate implementation examples (deep mode)
253
- */
254
- private generateImplementationExamples;
255
- /**
256
- * Suggest alternative prompt structures (deep mode)
257
- */
258
- private suggestAlternativeStructures;
259
- /**
260
- * Identify potential issues with the prompt (deep mode)
261
- */
262
- private identifyPotentialIssues;
263
- /**
264
- * Extract core requirement from prompt
265
- */
266
- private extractCoreRequirement;
267
- }
268
- //# sourceMappingURL=prompt-optimizer.d.ts.map
@@ -1,395 +0,0 @@
1
- "use strict";
2
- /**
3
- * QuestionEngine - Manages Socratic questioning flows for PRD generation
4
- *
5
- * This class handles:
6
- * - Loading question templates
7
- * - Sequential and conditional question flows
8
- * - Answer collection and validation
9
- * - Progress tracking
10
- */
11
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
- if (k2 === undefined) k2 = k;
13
- var desc = Object.getOwnPropertyDescriptor(m, k);
14
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
- desc = { enumerable: true, get: function() { return m[k]; } };
16
- }
17
- Object.defineProperty(o, k2, desc);
18
- }) : (function(o, m, k, k2) {
19
- if (k2 === undefined) k2 = k;
20
- o[k2] = m[k];
21
- }));
22
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
- Object.defineProperty(o, "default", { enumerable: true, value: v });
24
- }) : function(o, v) {
25
- o["default"] = v;
26
- });
27
- var __importStar = (this && this.__importStar) || (function () {
28
- var ownKeys = function(o) {
29
- ownKeys = Object.getOwnPropertyNames || function (o) {
30
- var ar = [];
31
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
- return ar;
33
- };
34
- return ownKeys(o);
35
- };
36
- return function (mod) {
37
- if (mod && mod.__esModule) return mod;
38
- var result = {};
39
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
- __setModuleDefault(result, mod);
41
- return result;
42
- };
43
- })();
44
- Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.QuestionEngine = void 0;
46
- const fs = __importStar(require("fs-extra"));
47
- const path = __importStar(require("path"));
48
- /**
49
- * QuestionEngine class
50
- *
51
- * Manages the flow of questions, answer collection, and validation
52
- */
53
- class QuestionEngine {
54
- constructor() {
55
- this.currentFlow = null;
56
- this.answers = {};
57
- this.currentQuestionIndex = 0;
58
- }
59
- /**
60
- * Load a question flow from a template file
61
- *
62
- * @param templatePath - Path to the question template
63
- * @returns The loaded question flow
64
- */
65
- async loadFlow(templatePath) {
66
- const fullPath = path.resolve(templatePath);
67
- if (!await fs.pathExists(fullPath)) {
68
- throw new Error(`Question template not found: ${templatePath}`);
69
- }
70
- const content = await fs.readFile(fullPath, 'utf-8');
71
- const flow = this.parseTemplate(content);
72
- this.currentFlow = flow;
73
- this.answers = {};
74
- this.currentQuestionIndex = 0;
75
- return flow;
76
- }
77
- /**
78
- * Parse a question template into a QuestionFlow
79
- *
80
- * Template format:
81
- * ```markdown
82
- * # Flow Name
83
- *
84
- * Flow description
85
- *
86
- * ## Question 1
87
- *
88
- * **text:** What problem are you solving?
89
- * **type:** text
90
- * **required:** true
91
- * **validation:** minLength:10
92
- *
93
- * ## Question 2
94
- *
95
- * **text:** Select your technology stack
96
- * **type:** list
97
- * **choices:** React, Vue, Angular, Other
98
- * ```
99
- *
100
- * @param template - Template content
101
- * @returns Parsed QuestionFlow
102
- */
103
- parseTemplate(template) {
104
- const lines = template.split('\n');
105
- const questions = [];
106
- let name = 'Default Flow';
107
- let description = '';
108
- let currentQuestion = null;
109
- for (let i = 0; i < lines.length; i++) {
110
- const line = lines[i].trim();
111
- // Skip empty lines
112
- if (!line) {
113
- continue;
114
- }
115
- // Extract flow name from first h1
116
- if (line.startsWith('# ') && name === 'Default Flow') {
117
- name = line.substring(2).trim();
118
- continue;
119
- }
120
- // Extract description (first non-heading paragraph)
121
- if (line && !line.startsWith('#') && !line.startsWith('**') && !description) {
122
- description = line;
123
- continue;
124
- }
125
- // Start new question on h2
126
- if (line.startsWith('## ')) {
127
- // Save previous question if exists
128
- if (currentQuestion && currentQuestion.text) {
129
- questions.push(this.finalizeQuestion(currentQuestion, questions.length));
130
- }
131
- // Start new question
132
- currentQuestion = {};
133
- continue;
134
- }
135
- // Parse question metadata: **key:** value
136
- const metadataMatch = line.match(/^\*\*(\w+):\*\*\s*(.+)$/);
137
- if (metadataMatch && currentQuestion) {
138
- const [, key, value] = metadataMatch;
139
- this.parseQuestionMetadata(currentQuestion, key, value);
140
- }
141
- }
142
- // Save last question
143
- if (currentQuestion && currentQuestion.text) {
144
- questions.push(this.finalizeQuestion(currentQuestion, questions.length));
145
- }
146
- return { name, description, questions };
147
- }
148
- /**
149
- * Parse a single metadata field for a question
150
- */
151
- parseQuestionMetadata(question, key, value) {
152
- switch (key.toLowerCase()) {
153
- case 'text':
154
- question.text = value;
155
- break;
156
- case 'type':
157
- if (value === 'text' || value === 'list' || value === 'confirm') {
158
- question.type = value;
159
- }
160
- break;
161
- case 'required':
162
- question.required = value.toLowerCase() === 'true';
163
- break;
164
- case 'choices':
165
- question.choices = value.split(',').map((c) => c.trim());
166
- break;
167
- case 'default':
168
- if (question.type === 'confirm') {
169
- question.default = value.toLowerCase() === 'true';
170
- }
171
- else {
172
- question.default = value;
173
- }
174
- break;
175
- case 'validation':
176
- question.validate = this.createValidator(value);
177
- break;
178
- case 'condition':
179
- question.condition = this.createCondition(value);
180
- break;
181
- }
182
- }
183
- /**
184
- * Finalize a question by setting defaults and generating ID
185
- */
186
- finalizeQuestion(partial, index) {
187
- return {
188
- id: `q${index + 1}`,
189
- text: partial.text || '',
190
- type: partial.type || 'text',
191
- required: partial.required !== undefined ? partial.required : true,
192
- choices: partial.choices,
193
- default: partial.default,
194
- validate: partial.validate,
195
- condition: partial.condition,
196
- };
197
- }
198
- /**
199
- * Create a validation function from a validation string
200
- *
201
- * Supported formats:
202
- * - minLength:10 - Minimum length
203
- * - maxLength:100 - Maximum length
204
- * - pattern:^[a-z]+$ - Regex pattern
205
- * - email - Email validation
206
- * - url - URL validation
207
- */
208
- createValidator(validationStr) {
209
- const parts = validationStr.split(':');
210
- const type = parts[0].toLowerCase();
211
- const param = parts[1];
212
- return (answer) => {
213
- switch (type) {
214
- case 'minlength':
215
- if (answer.length < parseInt(param, 10)) {
216
- return `Minimum length is ${param} characters`;
217
- }
218
- break;
219
- case 'maxlength':
220
- if (answer.length > parseInt(param, 10)) {
221
- return `Maximum length is ${param} characters`;
222
- }
223
- break;
224
- case 'pattern':
225
- if (!new RegExp(param).test(answer)) {
226
- return 'Answer does not match required format';
227
- }
228
- break;
229
- case 'email':
230
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(answer)) {
231
- return 'Please enter a valid email address';
232
- }
233
- break;
234
- case 'url':
235
- try {
236
- new URL(answer);
237
- }
238
- catch {
239
- return 'Please enter a valid URL';
240
- }
241
- break;
242
- }
243
- return true;
244
- };
245
- }
246
- /**
247
- * Create a condition function from a condition string
248
- *
249
- * Supported formats:
250
- * - q1=true - Question 1 answer equals true
251
- * - q2=JWT - Question 2 answer equals "JWT"
252
- * - q3!=None - Question 3 answer not equals "None"
253
- */
254
- createCondition(conditionStr) {
255
- const match = conditionStr.match(/^(\w+)\s*(=|!=)\s*(.+)$/);
256
- if (!match) {
257
- return () => true;
258
- }
259
- const [, questionId, operator, expectedValue] = match;
260
- return (answers) => {
261
- const actualValue = answers[questionId];
262
- // Convert expected value to proper type
263
- let expected = expectedValue;
264
- if (expectedValue.toLowerCase() === 'true') {
265
- expected = true;
266
- }
267
- else if (expectedValue.toLowerCase() === 'false') {
268
- expected = false;
269
- }
270
- if (operator === '=') {
271
- return actualValue === expected;
272
- }
273
- else {
274
- return actualValue !== expected;
275
- }
276
- };
277
- }
278
- /**
279
- * Get the next question in the flow
280
- *
281
- * @returns The next question, or null if flow is complete
282
- */
283
- getNextQuestion() {
284
- if (!this.currentFlow) {
285
- throw new Error('No question flow loaded');
286
- }
287
- // Find the next unanswered question that meets its condition
288
- while (this.currentQuestionIndex < this.currentFlow.questions.length) {
289
- const question = this.currentFlow.questions[this.currentQuestionIndex];
290
- // Skip if already answered
291
- if (question.id in this.answers) {
292
- this.currentQuestionIndex++;
293
- continue;
294
- }
295
- // Check if question condition is met (if it has one)
296
- if (question.condition && !question.condition(this.answers)) {
297
- this.currentQuestionIndex++;
298
- continue;
299
- }
300
- return question;
301
- }
302
- return null;
303
- }
304
- /**
305
- * Submit an answer to the current question
306
- *
307
- * @param questionId - ID of the question being answered
308
- * @param answer - The answer
309
- * @returns Validation result (true if valid, error message if invalid)
310
- */
311
- submitAnswer(questionId, answer) {
312
- if (!this.currentFlow) {
313
- throw new Error('No question flow loaded');
314
- }
315
- const question = this.currentFlow.questions.find((q) => q.id === questionId);
316
- if (!question) {
317
- throw new Error(`Question not found: ${questionId}`);
318
- }
319
- // Validate required fields (but allow false for boolean answers)
320
- if (question.required && (answer === '' || answer === null || answer === undefined)) {
321
- return 'This question is required';
322
- }
323
- // Run custom validation if provided
324
- if (question.validate) {
325
- const validationResult = question.validate(String(answer));
326
- if (validationResult !== true) {
327
- return validationResult;
328
- }
329
- }
330
- // Store the answer
331
- this.answers[questionId] = answer;
332
- this.currentQuestionIndex++;
333
- return true;
334
- }
335
- /**
336
- * Get all collected answers
337
- *
338
- * @returns All answers collected so far
339
- */
340
- getAnswers() {
341
- return { ...this.answers };
342
- }
343
- /**
344
- * Get current progress through the question flow
345
- *
346
- * @returns Progress information
347
- */
348
- getProgress() {
349
- if (!this.currentFlow) {
350
- return { current: 0, total: 0, percentage: 0 };
351
- }
352
- const total = this.currentFlow.questions.length;
353
- const current = Object.keys(this.answers).length;
354
- const percentage = total > 0 ? Math.round((current / total) * 100) : 0;
355
- return { current, total, percentage };
356
- }
357
- /**
358
- * Check if the question flow is complete
359
- *
360
- * @returns True if all required questions are answered
361
- */
362
- isComplete() {
363
- if (!this.currentFlow) {
364
- return false;
365
- }
366
- // Check if all required questions have answers
367
- for (const question of this.currentFlow.questions) {
368
- // Skip if condition not met
369
- if (question.condition && !question.condition(this.answers)) {
370
- continue;
371
- }
372
- if (question.required && !(question.id in this.answers)) {
373
- return false;
374
- }
375
- }
376
- return true;
377
- }
378
- /**
379
- * Reset the question flow
380
- */
381
- reset() {
382
- this.answers = {};
383
- this.currentQuestionIndex = 0;
384
- }
385
- /**
386
- * Get the current question flow
387
- *
388
- * @returns The loaded question flow, or null if none loaded
389
- */
390
- getCurrentFlow() {
391
- return this.currentFlow;
392
- }
393
- }
394
- exports.QuestionEngine = QuestionEngine;
395
- //# sourceMappingURL=question-engine.js.map