auq-mcp-server 0.1.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 (66) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +176 -0
  3. package/dist/__tests__/schema-validation.test.js +137 -0
  4. package/dist/__tests__/server.integration.test.js +263 -0
  5. package/dist/add.js +1 -0
  6. package/dist/add.test.js +5 -0
  7. package/dist/bin/auq.js +245 -0
  8. package/dist/bin/test-session-menu.js +28 -0
  9. package/dist/bin/test-tabbar.js +42 -0
  10. package/dist/file-utils.js +59 -0
  11. package/dist/format/ResponseFormatter.js +206 -0
  12. package/dist/format/__tests__/ResponseFormatter.test.js +380 -0
  13. package/dist/package.json +74 -0
  14. package/dist/server.js +107 -0
  15. package/dist/session/ResponseFormatter.js +130 -0
  16. package/dist/session/SessionManager.js +474 -0
  17. package/dist/session/__tests__/ResponseFormatter.test.js +417 -0
  18. package/dist/session/__tests__/SessionManager.test.js +553 -0
  19. package/dist/session/__tests__/atomic-operations.test.js +345 -0
  20. package/dist/session/__tests__/file-watcher.test.js +311 -0
  21. package/dist/session/__tests__/workflow.integration.test.js +334 -0
  22. package/dist/session/atomic-operations.js +307 -0
  23. package/dist/session/file-watcher.js +218 -0
  24. package/dist/session/index.js +7 -0
  25. package/dist/session/types.js +20 -0
  26. package/dist/session/utils.js +125 -0
  27. package/dist/session-manager.js +171 -0
  28. package/dist/session-watcher.js +110 -0
  29. package/dist/src/__tests__/schema-validation.test.js +170 -0
  30. package/dist/src/__tests__/server.integration.test.js +274 -0
  31. package/dist/src/add.js +1 -0
  32. package/dist/src/add.test.js +5 -0
  33. package/dist/src/server.js +163 -0
  34. package/dist/src/session/ResponseFormatter.js +163 -0
  35. package/dist/src/session/SessionManager.js +572 -0
  36. package/dist/src/session/__tests__/ResponseFormatter.test.js +741 -0
  37. package/dist/src/session/__tests__/SessionManager.test.js +593 -0
  38. package/dist/src/session/__tests__/atomic-operations.test.js +346 -0
  39. package/dist/src/session/__tests__/file-watcher.test.js +311 -0
  40. package/dist/src/session/atomic-operations.js +307 -0
  41. package/dist/src/session/file-watcher.js +227 -0
  42. package/dist/src/session/index.js +7 -0
  43. package/dist/src/session/types.js +20 -0
  44. package/dist/src/session/utils.js +180 -0
  45. package/dist/src/tui/__tests__/session-watcher.test.js +368 -0
  46. package/dist/src/tui/components/AnimatedGradient.js +45 -0
  47. package/dist/src/tui/components/ConfirmationDialog.js +89 -0
  48. package/dist/src/tui/components/CustomInput.js +14 -0
  49. package/dist/src/tui/components/Footer.js +55 -0
  50. package/dist/src/tui/components/Header.js +35 -0
  51. package/dist/src/tui/components/MultiLineTextInput.js +65 -0
  52. package/dist/src/tui/components/OptionsList.js +115 -0
  53. package/dist/src/tui/components/QuestionDisplay.js +36 -0
  54. package/dist/src/tui/components/ReviewScreen.js +57 -0
  55. package/dist/src/tui/components/SessionSelectionMenu.js +151 -0
  56. package/dist/src/tui/components/StepperView.js +166 -0
  57. package/dist/src/tui/components/TabBar.js +42 -0
  58. package/dist/src/tui/components/Toast.js +19 -0
  59. package/dist/src/tui/components/WaitingScreen.js +20 -0
  60. package/dist/src/tui/session-watcher.js +195 -0
  61. package/dist/src/tui/theme.js +114 -0
  62. package/dist/src/tui/utils/gradientText.js +24 -0
  63. package/dist/tui/__tests__/session-watcher.test.js +368 -0
  64. package/dist/tui/session-watcher.js +183 -0
  65. package/package.json +78 -0
  66. package/scripts/postinstall.cjs +51 -0
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Response Formatter
3
+ *
4
+ * Formats user answers according to PRD specification for returning to AI models
5
+ */
6
+ /**
7
+ * ResponseFormatter - Formats session answers into human-readable text
8
+ * according to the PRD specification
9
+ */
10
+ export class ResponseFormatter {
11
+ /**
12
+ * Format user answers into PRD-compliant text response
13
+ *
14
+ * Format specification:
15
+ * - Header: "Here are the user's answers:"
16
+ * - Numbered questions: "1. {prompt}"
17
+ * - Arrow symbol for answers: "→ {label} — {description}"
18
+ * - Custom text: "→ Other: '{customText}'"
19
+ * - Double newline separation between questions
20
+ *
21
+ * @param answers - Session answer data containing user responses
22
+ * @param questions - Original questions asked to the user
23
+ * @returns Formatted text response ready to send to AI model
24
+ */
25
+ static formatUserResponse(answers, questions) {
26
+ // Validate that we have matching questions and answers
27
+ if (answers.answers.length === 0) {
28
+ throw new Error("No answers provided in session");
29
+ }
30
+ if (questions.length === 0) {
31
+ throw new Error("No questions provided");
32
+ }
33
+ // Start with header
34
+ const lines = ["Here are the user's answers:", ""];
35
+ // Format each question and its answer
36
+ const formattedQuestions = [];
37
+ for (let i = 0; i < questions.length; i++) {
38
+ const question = questions[i];
39
+ const answer = answers.answers.find((a) => a.questionIndex === i);
40
+ if (!answer) {
41
+ // If no answer found for this question, skip it
42
+ // (This shouldn't happen in normal operation, but handle gracefully)
43
+ continue;
44
+ }
45
+ // Format the question and answer
46
+ const formattedQA = this.formatQuestion(question, answer, i + 1);
47
+ formattedQuestions.push(formattedQA);
48
+ }
49
+ // Join formatted questions with blank lines between them
50
+ lines.push(formattedQuestions.join("\n\n"));
51
+ return lines.join("\n");
52
+ }
53
+ /**
54
+ * Validate that answers match the questions
55
+ *
56
+ * @param answers - Session answer data
57
+ * @param questions - Original questions
58
+ * @throws Error if validation fails
59
+ */
60
+ static validateAnswers(answers, questions) {
61
+ // Check that we have answers
62
+ if (!answers || !answers.answers || answers.answers.length === 0) {
63
+ throw new Error("No answers provided");
64
+ }
65
+ // Check that we have questions
66
+ if (!questions || questions.length === 0) {
67
+ throw new Error("No questions provided");
68
+ }
69
+ // Check each answer references a valid question
70
+ for (const answer of answers.answers) {
71
+ if (answer.questionIndex < 0 ||
72
+ answer.questionIndex >= questions.length) {
73
+ throw new Error(`Answer references invalid question index: ${answer.questionIndex}`);
74
+ }
75
+ // Check that answer has either selectedOption, selectedOptions, or customText
76
+ if (!answer.selectedOption && !answer.customText && !answer.selectedOptions) {
77
+ throw new Error(`Answer for question ${answer.questionIndex} has neither selectedOption, selectedOptions, nor customText`);
78
+ }
79
+ // If selectedOption is provided, verify it exists in the question's options
80
+ if (answer.selectedOption) {
81
+ const question = questions[answer.questionIndex];
82
+ const optionExists = question.options.some((opt) => opt.label === answer.selectedOption);
83
+ if (!optionExists) {
84
+ throw new Error(`Answer for question ${answer.questionIndex} references non-existent option: ${answer.selectedOption}`);
85
+ }
86
+ }
87
+ // Validate multi-select options
88
+ if (answer.selectedOptions) {
89
+ const question = questions[answer.questionIndex];
90
+ for (const selectedOpt of answer.selectedOptions) {
91
+ const optionExists = question.options.some((opt) => opt.label === selectedOpt);
92
+ if (!optionExists) {
93
+ throw new Error(`Answer for question ${answer.questionIndex} references non-existent option: ${selectedOpt}`);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ }
99
+ /**
100
+ * Format a single question and its answer
101
+ *
102
+ * @param question - The question data
103
+ * @param answer - The user's answer
104
+ * @param index - Question number (1-indexed for display)
105
+ * @returns Formatted string for this question/answer pair
106
+ */
107
+ static formatQuestion(question, answer, index) {
108
+ const lines = [];
109
+ // Add question with number
110
+ lines.push(`${index}. ${question.prompt}`);
111
+ // Track if any answer was provided
112
+ let hasAnswer = false;
113
+ // Format multi-select options (if present)
114
+ if (answer.selectedOptions && answer.selectedOptions.length > 0) {
115
+ hasAnswer = true;
116
+ for (const selectedLabel of answer.selectedOptions) {
117
+ const option = question.options.find((opt) => opt.label === selectedLabel);
118
+ if (option) {
119
+ if (option.description) {
120
+ lines.push(`→ ${option.label} — ${option.description}`);
121
+ }
122
+ else {
123
+ lines.push(`→ ${option.label}`);
124
+ }
125
+ }
126
+ }
127
+ }
128
+ else if (answer.selectedOptions && answer.selectedOptions.length === 0 && !answer.customText) {
129
+ // Multi-select with no selections and no custom text
130
+ hasAnswer = true;
131
+ lines.push("→ (No selection)");
132
+ }
133
+ // Format single-select option (if present and no multi-select)
134
+ if (answer.selectedOption && !answer.selectedOptions) {
135
+ hasAnswer = true;
136
+ const option = question.options.find((opt) => opt.label === answer.selectedOption);
137
+ if (option) {
138
+ // Format with description if available
139
+ if (option.description) {
140
+ lines.push(`→ ${option.label} — ${option.description}`);
141
+ }
142
+ else {
143
+ lines.push(`→ ${option.label}`);
144
+ }
145
+ }
146
+ else {
147
+ // Option not found - shouldn't happen, but handle gracefully
148
+ lines.push(`→ ${answer.selectedOption}`);
149
+ }
150
+ }
151
+ // Format custom text (if present) - can coexist with selectedOptions in multi-select
152
+ if (answer.customText) {
153
+ hasAnswer = true;
154
+ const escapedText = answer.customText.replace(/'/g, "\\'");
155
+ lines.push(`→ Other: '${escapedText}'`);
156
+ }
157
+ // If no answer at all
158
+ if (!hasAnswer) {
159
+ lines.push("→ No answer provided");
160
+ }
161
+ return lines.join("\n");
162
+ }
163
+ }