auq-mcp-server 3.3.0 → 3.3.2

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/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auq-mcp-server",
3
- "version": "3.3.0",
3
+ "version": "3.3.2",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "auq": "bin/auq"
@@ -244,7 +244,10 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
244
244
  return (React.createElement(Text, { backgroundColor: rowBg, bold: isCustomInputFocused || isSelected, color: rowColor }, fitRow(mainLine)));
245
245
  })(),
246
246
  isCustomInputFocused && onCustomChange && (React.createElement(Box, { borderColor: theme.components.input.borderFocused, borderStyle: "round", marginBottom: 1, marginLeft: 2, marginTop: 0, paddingX: 1, paddingY: 0 },
247
- React.createElement(MultiLineTextInput, { isFocused: true, onChange: onCustomChange, onSubmit: onAdvance, placeholder: t("input.placeholder"), value: customValue }))),
247
+ React.createElement(MultiLineTextInput, { isFocused: true, onChange: onCustomChange, onSubmit: () => {
248
+ onCustomChange?.(customValue);
249
+ onAdvance?.();
250
+ }, placeholder: t("input.placeholder"), value: customValue }))),
248
251
  !isCustomInputFocused && customValue && (React.createElement(Box, { marginLeft: 2, marginTop: 0 },
249
252
  React.createElement(Text, { color: theme.components.options.hint, dimColor: true },
250
253
  customLines.slice(0, 3).map((line, idx) => (React.createElement(React.Fragment, { key: idx },
@@ -275,6 +278,7 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
275
278
  })(),
276
279
  isElaborateFocused && onElaborateTextChange && (React.createElement(Box, { borderColor: theme.components.input.borderFocused, borderStyle: "round", marginBottom: 1, marginLeft: 2, marginTop: 0, paddingX: 1, paddingY: 0 },
277
280
  React.createElement(MultiLineTextInput, { enterSubmits: true, isFocused: true, onChange: onElaborateTextChange, onSubmit: () => {
281
+ onElaborateTextChange?.(elaborateText);
278
282
  // Enter/Tab submits and advance
279
283
  // Only call onElaborateSelect if no text (to toggle mark on)
280
284
  // If text exists, mark is already set via onElaborateTextChange
@@ -174,4 +174,24 @@ describe("StepperView SessionUIState boundary", () => {
174
174
  expect(snapshotState.answers.get(0)?.selectedOption).toBe("Python");
175
175
  expect(snapshotState.answers.get(0)?.selectedOption).not.toBe("TypeScript");
176
176
  });
177
+ it("custom text is preserved in answers when advancing via Tab", async () => {
178
+ const onStateSnapshot = vi.fn();
179
+ const initialState = {
180
+ currentQuestionIndex: 0,
181
+ answers: new Map([[0, { customText: "my custom answer" }]]),
182
+ elaborateMarks: new Map(),
183
+ focusContext: "option",
184
+ focusedOptionIndex: 0,
185
+ showReview: false,
186
+ };
187
+ const instance = renderStepper({ onStateSnapshot, initialState });
188
+ instance.stdin.write("\t");
189
+ await vi.waitFor(() => {
190
+ expect(onStateSnapshot).toHaveBeenCalled();
191
+ const lastCall = onStateSnapshot.mock.calls[onStateSnapshot.mock.calls.length - 1];
192
+ const [, snapshotState] = lastCall;
193
+ expect(snapshotState.answers.get(0)?.customText).toBe("my custom answer");
194
+ expect(snapshotState.currentQuestionIndex).toBe(1);
195
+ });
196
+ });
177
197
  });
@@ -21,6 +21,7 @@ import { SessionPicker as _SessionPicker } from "./components/SessionPicker.js";
21
21
  import { UpdateOverlay as _UpdateOverlay } from "./components/UpdateOverlay.js";
22
22
  import { Toast as _Toast } from "./components/Toast.js";
23
23
  import { ThemeIndicator as _ThemeIndicator } from "./components/ThemeIndicator.js";
24
+ import { createNotificationBatcher, } from "../tui/notifications/index.js";
24
25
  // Cast to FC to avoid React class component type mismatch between @opentui/react
25
26
  // bundled React version and the project's @types/react (structural type incompatibility).
26
27
  // ErrorBoundary is still a valid class component at runtime.
@@ -54,6 +55,14 @@ function AppInner({ config }) {
54
55
  const [changelogContent, setChangelogContent] = useState(null);
55
56
  const [updateDismissed, setUpdateDismissed] = useState(false);
56
57
  const [isCheckingUpdate, setIsCheckingUpdate] = useState(false);
58
+ // Notification configuration from config
59
+ const notificationConfig = useMemo(() => config?.notifications ?? { enabled: true, sound: true }, [config?.notifications]);
60
+ // Create notification batcher (memoized to persist across renders)
61
+ const notificationBatcherRef = useRef(null);
62
+ if (!notificationBatcherRef.current) {
63
+ notificationBatcherRef.current =
64
+ createNotificationBatcher(notificationConfig);
65
+ }
57
66
  const sessionDir = getSessionDirectory();
58
67
  // ── Show toast helper ────────────────────────────────────────
59
68
  const showToast = useCallback((message, type = "success", title) => {
@@ -95,6 +104,10 @@ function AppInner({ config }) {
95
104
  setSessionQueue((prev) => {
96
105
  if (prev.some((s) => s.sessionId === event.sessionId))
97
106
  return prev;
107
+ // Queue notification for new session (batched)
108
+ if (notificationBatcherRef.current) {
109
+ notificationBatcherRef.current.queue(event.sessionId);
110
+ }
98
111
  return [
99
112
  ...prev,
100
113
  {
@@ -115,6 +128,9 @@ function AppInner({ config }) {
115
128
  return () => {
116
129
  if (watcherInstance)
117
130
  watcherInstance.stop();
131
+ if (notificationBatcherRef.current) {
132
+ notificationBatcherRef.current.flush();
133
+ }
118
134
  };
119
135
  // eslint-disable-next-line react-hooks/exhaustive-deps
120
136
  }, []);
@@ -89,6 +89,7 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
89
89
  setFocusedIndex(Math.max(0, options.length - 1));
90
90
  }
91
91
  else if (key.name === "tab" && !key.shift) {
92
+ onCustomChange?.(customValue);
92
93
  onAdvance?.();
93
94
  }
94
95
  else if (key.name === "return") {
@@ -99,6 +100,7 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
99
100
  }
100
101
  else {
101
102
  // Enter: advance to next question
103
+ onCustomChange?.(customValue);
102
104
  onAdvance?.();
103
105
  }
104
106
  }
@@ -116,6 +118,10 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
116
118
  setFocusedIndex(customInputIndex);
117
119
  }
118
120
  else if (key.name === "tab" && !key.shift) {
121
+ onElaborateTextChange?.(elaborateText);
122
+ if (!elaborateText.trim()) {
123
+ onElaborateSelect?.();
124
+ }
119
125
  onAdvance?.();
120
126
  }
121
127
  else if (key.name === "return") {
@@ -126,6 +132,7 @@ export const OptionsList = ({ isFocused, onSelect, options, selectedOption, show
126
132
  }
127
133
  else {
128
134
  // Enter: advance to next question
135
+ onElaborateTextChange?.(elaborateText);
129
136
  if (!elaborateText.trim()) {
130
137
  onElaborateSelect?.();
131
138
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auq-mcp-server",
3
- "version": "3.3.0",
3
+ "version": "3.3.2",
4
4
  "main": "dist/index.js",
5
5
  "bin": {
6
6
  "auq": "bin/auq"