auq-mcp-server 1.2.8 β†’ 1.3.1

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.
package/README.md CHANGED
@@ -1,18 +1,22 @@
1
1
  ![AUQ Demo](media/demo.png)
2
2
 
3
- # AUQ - ask-user-questions MCP
3
+ # AUQ - Ask User Questions
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/auq-mcp-server.svg)](https://www.npmjs.com/package/auq-mcp-server)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
  [![Install MCP Server](https://cursor.com/deeplink/mcp-install-light.svg)](https://cursor.com/en-US/install-mcp?name=ask-user-questions&config=eyJlbnYiOnt9LCJjb21tYW5kIjoibnB4IC15IGF1cS1tY3Atc2VydmVyIHNlcnZlciJ9)
8
8
 
9
- **A lightweight MCP server & CLI tool that allows your LLMs to ask questions to you in a clean, separate space with great terminal UX. Made for multi-agent parallel coding workflows.**
9
+ **A lightweight CLI tool that allows your LLMs to ask questions to you in a separate space with clean terminal UX. Supports both MCP server and official OpenCode plugin integration. Made for multi-agent parallel coding workflows.**
10
+
11
+ πŸ€” [Why do I need it when I already have question tool in CC/OC?](#-why-auq-vs-built-in-ask-tools)
12
+
13
+ [Setup](#setup-instructions) β€’ [Features](#-features)
10
14
 
11
15
  ---
12
16
 
13
17
  ## What does it do?
14
18
 
15
- This MCP server lets your AI assistants generate clarifying questions consisting of multiple-choice/single-choice questions (with an "Other" option for custom input) while coding or working, and wait for your answers through a separate CLI tool without messing up your workflow.
19
+ AUQ lets your AI assistants generate clarifying questions consisting of multiple-choice/single-choice questions (with an "Other" option for custom input) while coding or working, and wait for your answers through a separate CLI tool without messing up your workflow.
16
20
 
17
21
  You can keep the CLI running in advance, or start it when questions are pending. With simple arrow key navigation, you can select answers and send them back to the AIβ€”all within a clean terminal interface.
18
22
 
@@ -22,7 +26,7 @@ In AI-assisted coding, guiding LLMs to ask **clarifying questions** have been wi
22
26
 
23
27
  On October 18th, Claude Code 2.0.21 introduced an internal `ask-user-question` tool. Inspired by it, I decided to build a similar tool that is:
24
28
 
25
- - **Tool-agnostic** - Works with any MCP client (Claude Desktop, Cursor, etc.)
29
+ - **Integration-flexible** - Works with MCP clients (Claude Desktop, Cursor, etc.) and has official OpenCode plugin support
26
30
  - **Non-invasive** - Doesn't heavily integrate with your coding CLI workflow or occupy UI space
27
31
  - **Multi-agent friendly** - Supports receiving questions from multiple agents simultaneously in parallel workflows
28
32
 
@@ -56,9 +60,35 @@ Recent AI workflows often use parallel sub-agents for concurrent coding. AUQ han
56
60
 
57
61
  ---
58
62
 
63
+ ## πŸ€” Why AUQ vs. Built-in Ask Tools?
64
+
65
+ **Why should I use AUQ instead of the built-in "Question" tools in OpenCode, Claude Code, or other coding agents?**
66
+
67
+ AUQ is designed for the era of parallel multi-agent workflows, with several key advantages:
68
+
69
+ ### πŸš€ Non-Blocking Parallel Operation
70
+
71
+ Unlike built-in ask tools that halt the entire AI workflow until you respond, AUQ **doesn't block the AI from continuing work**. Questions are queued asynchronously, allowing your AI assistants to keep coding while you review and answer questions at your own pace.
72
+
73
+ ### 🎯 Multi-Agent Question Set Support
74
+
75
+ AUQ can handle question sets from **multiple agents simultaneously**. In modern AI coding workflows, you often have several sub-agents working in parallelβ€”each might need clarification on different aspects of your codebase. With AUQ:
76
+
77
+ - **No more screen switching** between different agent conversations
78
+ - **Unified queue** for all agent questions, regardless of which AI tool they're coming from
79
+ - **Sequential processing** of questions from multiple sources in one interface
80
+
81
+ ### 🌐 Question Set Rejection Support
82
+
83
+ **Skip irrelevant question sets entirely** - reject whole question batches that don't apply to your current context, saving time and maintaining focus on relevant AI-agent questions.
84
+
85
+ ---
86
+
59
87
  # Setup Instructions
60
88
 
61
- ## πŸš€ Step 1: Setup CLI
89
+ ## πŸš€ Install CLI Tool
90
+
91
+ First, install the AUQ CLI tool:
62
92
 
63
93
  ### Global Installation (Recommended)
64
94
 
@@ -66,8 +96,6 @@ Recent AI workflows often use parallel sub-agents for concurrent coding. AUQ han
66
96
  # Install globally
67
97
  npm install -g auq-mcp-server
68
98
 
69
- # Start the TUI
70
- auq
71
99
  ```
72
100
 
73
101
  ### Local Installation (Project-specific)
@@ -76,8 +104,6 @@ auq
76
104
  # Install in your project
77
105
  npm install auq-mcp-server
78
106
 
79
- # Start the TUI from project directory
80
- npx auq
81
107
  ```
82
108
 
83
109
  **Session Storage:**
@@ -87,7 +113,11 @@ npx auq
87
113
 
88
114
  ---
89
115
 
90
- ## πŸ”Œ Step 2: Setup MCP Server
116
+ ## πŸ”Œ Choose Your Integration Method
117
+
118
+ AUQ supports multiple AI coding environments. Choose the one that fits your workflow:
119
+
120
+ ### Option A: MCP Server
91
121
 
92
122
  ### Cursor
93
123
 
@@ -168,29 +198,22 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
168
198
 
169
199
  **Restart Claude Desktop** after saving.
170
200
 
171
- ---
201
+ ### Option B: Official OpenCode Plugin
172
202
 
173
- ## πŸ”Œ OpenCode Plugin (Optional)
203
+ We now have **official OpenCode plugin support**! We support OpenCode because OpenCode's MCP server seems to have some limitations (timeout), so we created an OpenCode-specific plugin that works perfectly together with OpenCode.
174
204
 
175
- If you want the OpenCode tool to call `auq ask` directly (without MCP), install
176
- the plugin package and add it to your OpenCode config.
205
+ The OpenCode plugin allows OpenCode to call `auq ask` directly (without MCP), providing seamless integration with OpenCode's workflow.
177
206
 
178
- ```bash
179
- npm install -g auq-mcp-server
180
- npm install -g @paulp-o/opencode-auq
181
- ```
207
+ #### Configuration
182
208
 
183
209
  Add to `opencode.json`:
184
210
 
185
211
  ```json
186
212
  {
187
- "$schema": "https://opencode.ai/config.json",
188
213
  "plugin": ["@paulp-o/opencode-auq"]
189
214
  }
190
215
  ```
191
216
 
192
- The plugin assumes `auq` is available on `PATH` (global install or equivalent).
193
-
194
217
  ---
195
218
 
196
219
  ## πŸ’» Usage
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auq-mcp-server",
3
- "version": "1.2.8",
3
+ "version": "1.3.1",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "auq": "dist/bin/auq.js"
@@ -19,6 +19,7 @@
19
19
  "prepare": "npm run build",
20
20
  "postinstall": "node scripts/postinstall.cjs",
21
21
  "deploy": "node scripts/deploy.mjs",
22
+ "semantic-release": "semantic-release",
22
23
  "server": "node dist/src/server.js",
23
24
  "start": "tsx src/server.ts",
24
25
  "dev": "fastmcp dev src/server.ts",
@@ -3,7 +3,7 @@
3
3
  * Tests the most common edge cases to catch obvious bugs
4
4
  */
5
5
  import { describe, expect, it } from "vitest";
6
- import { QuestionSchema, QuestionsSchema, } from "../core/ask-user-questions.js";
6
+ import { QuestionSchema, QuestionsSchema } from "../core/ask-user-questions.js";
7
7
  describe("Schema Validation - Edge Cases", () => {
8
8
  describe("Invalid Input (should reject)", () => {
9
9
  it("should reject missing title field", () => {
@@ -1,7 +1,7 @@
1
1
  import { Box, Text, useInput } from "ink";
2
2
  import React, { useState } from "react";
3
3
  import { theme } from "../theme.js";
4
- import { MultiLineTextInput } from "./MultiLineTextInput.js";
4
+ import { SingleLineTextInput } from "./SingleLineTextInput.js";
5
5
  /**
6
6
  * ConfirmationDialog shows a 3-option prompt for session rejection
7
7
  * Options: Reject & inform AI, Cancel, or Quit CLI
@@ -64,9 +64,9 @@ export const ConfirmationDialog = ({ message, onReject, onCancel, onQuit, }) =>
64
64
  React.createElement(Box, { marginBottom: 1 },
65
65
  React.createElement(Text, { dimColor: true }, "(Optional - helps the AI improve)")),
66
66
  React.createElement(Box, { marginBottom: 1 },
67
- React.createElement(MultiLineTextInput, { isFocused: true, onChange: setRejectionReason, onSubmit: handleReasonSubmit, placeholder: "Type your reason here...", value: rejectionReason })),
67
+ React.createElement(SingleLineTextInput, { isFocused: true, onChange: setRejectionReason, onSubmit: handleReasonSubmit, placeholder: "Type your reason here...", value: rejectionReason })),
68
68
  React.createElement(Box, { marginTop: 1 },
69
- React.createElement(Text, { dimColor: true }, "Enter Submit | Shift+Enter Newline | Esc Skip"))));
69
+ React.createElement(Text, { dimColor: true }, "Enter Submit | Esc Skip"))));
70
70
  }
71
71
  // Step 1: Confirmation options
72
72
  return (React.createElement(Box, { borderColor: theme.borders.warning, borderStyle: "single", flexDirection: "column", padding: 1 },
@@ -16,25 +16,23 @@ export const Footer = ({ focusContext, multiSelect, isReviewScreen = false, cust
16
16
  }
17
17
  // Custom input focused
18
18
  if (focusContext === "custom-input") {
19
- const hasContent = customInputValue.trim().length > 0;
20
- const bindings = [
19
+ return [
21
20
  { key: "↑↓", action: "Options" },
22
- { key: "Tab", action: "Next" },
21
+ { key: "←→", action: "Cursor" },
22
+ { key: "Tab/S+Tab", action: "Questions" },
23
+ { key: "Enter", action: "Newline" },
24
+ { key: "Esc", action: "Reject" },
23
25
  ];
24
- if (hasContent) {
25
- bindings.push({ key: "Enter", action: "Submit" });
26
- }
27
- bindings.push({ key: "Shift+Enter", action: "Newline" }, { key: "Esc", action: "Reject" });
28
- return bindings;
29
26
  }
30
27
  // Option focused
31
28
  if (focusContext === "option") {
32
29
  const bindings = [
33
30
  { key: "↑↓", action: "Options" },
34
31
  { key: "←→", action: "Questions" },
32
+ { key: "Tab/S+Tab", action: "Questions" },
35
33
  ];
36
34
  if (multiSelect) {
37
- bindings.push({ key: "Space", action: "Toggle" }, { key: "Tab", action: "Submit" });
35
+ bindings.push({ key: "Space", action: "Toggle" });
38
36
  }
39
37
  else {
40
38
  bindings.push({ key: "Enter", action: "Select" });
@@ -4,7 +4,7 @@ import { theme } from "../theme.js";
4
4
  /**
5
5
  * Multi-line text input component for Ink with cursor positioning
6
6
  * Supports left/right arrow keys for cursor movement
7
- * Shift+Enter for newlines, Enter to submit
7
+ * Enter for newlines, Tab to submit (portable across terminals)
8
8
  */
9
9
  export const MultiLineTextInput = ({ isFocused = true, onChange, onSubmit, placeholder = "Type your answer...", value, }) => {
10
10
  const [cursorPosition, setCursorPosition] = useState(value.length);
@@ -17,33 +17,22 @@ export const MultiLineTextInput = ({ isFocused = true, onChange, onSubmit, place
17
17
  useInput((input, key) => {
18
18
  if (!isFocused)
19
19
  return;
20
- // Normalize Enter key sequences that may arrive as raw input ("\r"/"\n").
21
- // Prevent accidental carriage return insertion which causes line overwrite in terminals.
22
- if (input === "\r" || input === "\n") {
23
- if (key.shift) {
24
- const newValue = value.slice(0, cursorPosition) + "\n" + value.slice(cursorPosition);
25
- onChange(newValue);
26
- setCursorPosition(cursorPosition + 1);
27
- }
28
- else if (onSubmit) {
29
- onSubmit();
30
- }
20
+ // Tab: Submit (also triggers question navigation via parent)
21
+ if (key.tab && !key.shift) {
22
+ onSubmit?.();
23
+ return;
24
+ }
25
+ // Shift+Tab: Let parent handle for previous question navigation
26
+ if (key.tab && key.shift) {
31
27
  return;
32
28
  }
33
- // Shift+Enter: Add newline
34
- if (key.return && key.shift) {
29
+ // Enter: Always add newline (portable behavior)
30
+ if (input === "\r" || input === "\n" || key.return) {
35
31
  const newValue = value.slice(0, cursorPosition) + "\n" + value.slice(cursorPosition);
36
32
  onChange(newValue);
37
33
  setCursorPosition(cursorPosition + 1);
38
34
  return;
39
35
  }
40
- // Enter: Submit (empty input allowed)
41
- if (key.return) {
42
- if (onSubmit) {
43
- onSubmit();
44
- }
45
- return;
46
- }
47
36
  // Left arrow: Move cursor left
48
37
  if (key.leftArrow) {
49
38
  setCursorPosition(Math.max(0, cursorPosition - 1));
@@ -75,13 +64,11 @@ export const MultiLineTextInput = ({ isFocused = true, onChange, onSubmit, place
75
64
  setCursorPosition(cursorPosition + 1);
76
65
  }
77
66
  }, { isActive: isFocused });
78
- // Normalize any carriage returns that might already be present in value
79
67
  const normalizedValue = value.replace(/\r\n?/g, "\n");
80
68
  const hasContent = normalizedValue.length > 0;
81
69
  const lines = hasContent ? normalizedValue.split("\n") : [placeholder];
82
- // Calculate which line and position the cursor is on
83
70
  const cursorLineIndex = normalizedValue.slice(0, cursorPosition).split("\n").length - 1;
84
- const cursorLineStart = normalizedValue.split("\n").slice(0, cursorLineIndex).join("\n").length + (cursorLineIndex > 0 ? cursorLineIndex : 0);
71
+ const cursorLineStart = normalizedValue.lastIndexOf("\n", cursorPosition - 1) + 1;
85
72
  const cursorPositionInLine = cursorPosition - cursorLineStart;
86
73
  return (React.createElement(Box, { flexDirection: "column" }, lines.map((line, index) => {
87
74
  const isCursorLine = isFocused && index === cursorLineIndex && hasContent;
@@ -22,6 +22,15 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
22
22
  useInput((input, key) => {
23
23
  if (!isFocused)
24
24
  return;
25
+ // Handle up/down navigation even when custom input is focused
26
+ if (key.upArrow) {
27
+ setFocusedIndex((prev) => Math.max(0, prev - 1));
28
+ return;
29
+ }
30
+ if (key.downArrow) {
31
+ setFocusedIndex((prev) => Math.min(maxIndex, prev + 1));
32
+ return;
33
+ }
25
34
  // When custom input is focused, only handle escape to exit, let MultiLineTextInput handle other keys
26
35
  if (isCustomInputFocused) {
27
36
  if (key.escape) {
@@ -30,12 +39,6 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
30
39
  }
31
40
  return;
32
41
  }
33
- if (key.upArrow) {
34
- setFocusedIndex((prev) => Math.max(0, prev - 1));
35
- }
36
- if (key.downArrow) {
37
- setFocusedIndex((prev) => Math.min(maxIndex, prev + 1));
38
- }
39
42
  if (multiSelect) {
40
43
  // Multi-select mode
41
44
  if (input === " ") {
@@ -44,8 +47,9 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
44
47
  onToggle?.(options[focusedIndex].label);
45
48
  }
46
49
  }
47
- if (key.return || key.tab) {
48
- // Enter OR Tab: Advance to next question (don't toggle)
50
+ if (key.return) {
51
+ // Enter: Advance to next question (don't toggle)
52
+ // Note: Tab is handled globally in StepperView for question navigation
49
53
  if (!isCustomInputFocused && onAdvance) {
50
54
  onAdvance();
51
55
  }
@@ -114,7 +118,7 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
114
118
  customValue ? "●" : "β—‹",
115
119
  " Other (custom answer)"),
116
120
  isCustomInputFocused && onCustomChange && (React.createElement(Box, { marginLeft: 2, marginTop: 0.5 },
117
- React.createElement(MultiLineTextInput, { isFocused: true, onChange: onCustomChange, onSubmit: onAdvance, placeholder: "Type your answer... (Shift+Enter for newline)", value: customValue }))),
121
+ React.createElement(MultiLineTextInput, { isFocused: true, onChange: onCustomChange, onSubmit: onAdvance, placeholder: "Type your answer... (Enter for newline, Tab to submit)", value: customValue }))),
118
122
  !isCustomInputFocused && customValue && (React.createElement(Box, { marginLeft: 2, marginTop: 0.5 },
119
123
  React.createElement(Text, { dimColor: true }, customLines.map((line, idx) => (React.createElement(React.Fragment, { key: idx },
120
124
  idx === 0 ? "❯ " : " ",
@@ -7,9 +7,12 @@ import { TabBar } from "./TabBar.js";
7
7
  * QuestionDisplay shows a single question with its options
8
8
  * Includes TabBar, question prompt, options list, and footer
9
9
  */
10
- export const QuestionDisplay = ({ currentQuestion, currentQuestionIndex, customAnswer = "", elapsedLabel, onChangeCustomAnswer, onSelectOption, questions, selectedOption, onAdvanceToNext, answers, onToggleOption, multiSelect, }) => {
11
- // Track focus context for Footer component
10
+ export const QuestionDisplay = ({ currentQuestion, currentQuestionIndex, customAnswer = "", elapsedLabel, onChangeCustomAnswer, onSelectOption, questions, selectedOption, onAdvanceToNext, answers, onToggleOption, multiSelect, onFocusContextChange, }) => {
12
11
  const [focusContext, setFocusContext] = useState("option");
12
+ const handleFocusContextChange = (context) => {
13
+ setFocusContext(context);
14
+ onFocusContextChange?.(context);
15
+ };
13
16
  // Handle option selection - clears custom answer only in single-select mode
14
17
  const handleSelectOption = (label) => {
15
18
  onSelectOption(label);
@@ -35,6 +38,6 @@ export const QuestionDisplay = ({ currentQuestion, currentQuestionIndex, customA
35
38
  React.createElement(Text, { dimColor: true },
36
39
  "Elapsed ",
37
40
  elapsedLabel)),
38
- React.createElement(OptionsList, { customValue: customAnswer, isFocused: true, onAdvance: onAdvanceToNext, onCustomChange: handleCustomAnswerChange, onSelect: handleSelectOption, options: currentQuestion.options, selectedOption: selectedOption, showCustomInput: true, onToggle: onToggleOption, multiSelect: multiSelect, selectedOptions: answers.get(currentQuestionIndex)?.selectedOptions, onFocusContextChange: setFocusContext }),
41
+ React.createElement(OptionsList, { customValue: customAnswer, isFocused: true, onAdvance: onAdvanceToNext, onCustomChange: handleCustomAnswerChange, onSelect: handleSelectOption, options: currentQuestion.options, selectedOption: selectedOption, showCustomInput: true, onToggle: onToggleOption, multiSelect: multiSelect, selectedOptions: answers.get(currentQuestionIndex)?.selectedOptions, onFocusContextChange: handleFocusContextChange }),
39
42
  React.createElement(Footer, { focusContext: focusContext, multiSelect: multiSelect ?? false, customInputValue: customAnswer })));
40
43
  };
@@ -0,0 +1,59 @@
1
+ import { Text, useInput } from "ink";
2
+ import React, { useState } from "react";
3
+ import { theme } from "../theme.js";
4
+ export const SingleLineTextInput = ({ isFocused = true, onChange, onSubmit, placeholder = "Type here...", value, }) => {
5
+ const [cursorPosition, setCursorPosition] = useState(value.length);
6
+ React.useEffect(() => {
7
+ if (cursorPosition > value.length) {
8
+ setCursorPosition(value.length);
9
+ }
10
+ }, [value.length, cursorPosition]);
11
+ useInput((input, key) => {
12
+ if (!isFocused)
13
+ return;
14
+ if (key.return) {
15
+ onSubmit?.();
16
+ return;
17
+ }
18
+ if (key.leftArrow) {
19
+ setCursorPosition(Math.max(0, cursorPosition - 1));
20
+ return;
21
+ }
22
+ if (key.rightArrow) {
23
+ setCursorPosition(Math.min(value.length, cursorPosition + 1));
24
+ return;
25
+ }
26
+ if (key.backspace || key.delete) {
27
+ if (cursorPosition > 0) {
28
+ const newValue = value.slice(0, cursorPosition - 1) + value.slice(cursorPosition);
29
+ onChange(newValue);
30
+ setCursorPosition(cursorPosition - 1);
31
+ }
32
+ return;
33
+ }
34
+ if (input &&
35
+ !key.ctrl &&
36
+ !key.meta &&
37
+ !key.escape &&
38
+ !key.tab &&
39
+ input !== "\r" &&
40
+ input !== "\n") {
41
+ const newValue = value.slice(0, cursorPosition) + input + value.slice(cursorPosition);
42
+ onChange(newValue);
43
+ setCursorPosition(cursorPosition + 1);
44
+ }
45
+ }, { isActive: isFocused });
46
+ const hasContent = value.length > 0;
47
+ const displayText = hasContent ? value : placeholder;
48
+ if (hasContent && isFocused) {
49
+ const beforeCursor = value.slice(0, cursorPosition);
50
+ const afterCursor = value.slice(cursorPosition);
51
+ return (React.createElement(Text, null,
52
+ beforeCursor,
53
+ React.createElement(Text, { color: theme.colors.focused, dimColor: true }, "\u258C"),
54
+ afterCursor));
55
+ }
56
+ return (React.createElement(Text, { dimColor: !hasContent },
57
+ displayText,
58
+ isFocused && !hasContent && (React.createElement(Text, { color: theme.colors.focused, dimColor: true }, "\u258C"))));
59
+ };
@@ -18,6 +18,7 @@ export const StepperView = ({ onComplete, sessionId, sessionRequest, }) => {
18
18
  const [submitting, setSubmitting] = useState(false);
19
19
  const [showRejectionConfirm, setShowRejectionConfirm] = useState(false);
20
20
  const [elapsedSeconds, setElapsedSeconds] = useState(0);
21
+ const [focusContext, setFocusContext] = useState("option");
21
22
  const currentQuestion = sessionRequest.questions[currentQuestionIndex];
22
23
  const sessionCreatedAt = useMemo(() => {
23
24
  const parsed = Date.parse(sessionRequest.timestamp);
@@ -163,11 +164,23 @@ export const StepperView = ({ onComplete, sessionId, sessionRequest, }) => {
163
164
  setShowRejectionConfirm(true);
164
165
  return;
165
166
  }
166
- // Question navigation with arrow keys
167
- if (key.leftArrow && currentQuestionIndex > 0) {
167
+ // Tab/Shift+Tab: Global question navigation (works in all contexts)
168
+ if (key.tab && key.shift && currentQuestionIndex > 0) {
169
+ setCurrentQuestionIndex((prev) => prev - 1);
170
+ return;
171
+ }
172
+ if (key.tab &&
173
+ !key.shift &&
174
+ currentQuestionIndex < sessionRequest.questions.length - 1) {
175
+ setCurrentQuestionIndex((prev) => prev + 1);
176
+ return;
177
+ }
178
+ const shouldNavigate = focusContext !== "custom-input";
179
+ if (shouldNavigate && key.leftArrow && currentQuestionIndex > 0) {
168
180
  setCurrentQuestionIndex((prev) => prev - 1);
169
181
  }
170
- if (key.rightArrow &&
182
+ if (shouldNavigate &&
183
+ key.rightArrow &&
171
184
  currentQuestionIndex < sessionRequest.questions.length - 1) {
172
185
  setCurrentQuestionIndex((prev) => prev + 1);
173
186
  }
@@ -189,5 +202,5 @@ export const StepperView = ({ onComplete, sessionId, sessionRequest, }) => {
189
202
  return (React.createElement(ReviewScreen, { answers: answers, elapsedLabel: elapsedLabel, onConfirm: handleConfirm, onGoBack: handleGoBack, questions: sessionRequest.questions, sessionId: sessionId }));
190
203
  }
191
204
  // Show question display (default)
192
- return (React.createElement(QuestionDisplay, { currentQuestion: currentQuestion, currentQuestionIndex: currentQuestionIndex, customAnswer: currentAnswer?.customText, elapsedLabel: elapsedLabel, onAdvanceToNext: handleAdvanceToNext, onChangeCustomAnswer: handleChangeCustomAnswer, onSelectOption: handleSelectOption, onToggleOption: handleToggleOption, multiSelect: currentQuestion.multiSelect, questions: sessionRequest.questions, selectedOption: currentAnswer?.selectedOption, answers: answers }));
205
+ return (React.createElement(QuestionDisplay, { currentQuestion: currentQuestion, currentQuestionIndex: currentQuestionIndex, customAnswer: currentAnswer?.customText, elapsedLabel: elapsedLabel, onAdvanceToNext: handleAdvanceToNext, onChangeCustomAnswer: handleChangeCustomAnswer, onSelectOption: handleSelectOption, onToggleOption: handleToggleOption, multiSelect: currentQuestion.multiSelect, questions: sessionRequest.questions, selectedOption: currentAnswer?.selectedOption, answers: answers, onFocusContextChange: setFocusContext }));
193
206
  };
@@ -19,7 +19,7 @@ export const WaitingScreen = ({ queueCount }) => {
19
19
  }, [startTime]);
20
20
  // Handle 'q' key to quit
21
21
  useInput((input, key) => {
22
- if (input === 'q') {
22
+ if (input === "q") {
23
23
  process.exit(0);
24
24
  }
25
25
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auq-mcp-server",
3
- "version": "1.2.8",
3
+ "version": "1.3.1",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "auq": "dist/bin/auq.js"
@@ -19,6 +19,7 @@
19
19
  "prepare": "npm run build",
20
20
  "postinstall": "node scripts/postinstall.cjs",
21
21
  "deploy": "node scripts/deploy.mjs",
22
+ "semantic-release": "semantic-release",
22
23
  "server": "node dist/src/server.js",
23
24
  "start": "tsx src/server.ts",
24
25
  "dev": "fastmcp dev src/server.ts",