ask-user-question-plus 1.0.1 → 1.0.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/README.md CHANGED
@@ -60,6 +60,9 @@ pm2 start "npx ask-user-question-plus -- --port=3456 --timeout=600000" --name as
60
60
 
61
61
  # 停止服务
62
62
  pm2 stop ask-user-question-plus-service
63
+
64
+ # Windows
65
+ pm2 start cmd --name ask-user-question-plus-service -- /c npx ask-user-question-plus
63
66
  ```
64
67
 
65
68
  #### 使用 Docker
@@ -268,6 +271,9 @@ pm2 start "npx ask-user-question-plus -- --port=3456 --timeout=600000" --name as
268
271
 
269
272
  # Stop service
270
273
  pm2 stop ask-user-question-plus-service
274
+
275
+ # Windows
276
+ pm2 start cmd --name ask-user-question-plus-service -- /c npx ask-user-question-plu
271
277
  ```
272
278
 
273
279
  #### Using Docker
@@ -39,6 +39,11 @@ export class WebSocketService {
39
39
  clearTimeout(session.timeout);
40
40
  session.timeout = null;
41
41
  }
42
+ // Send session meta first so the client can start countdown when it receives NEW_QUESTION.
43
+ this.sendMessage(ws, {
44
+ type: "SESSION_META",
45
+ payload: { timeoutMs: this.sessionTimeoutMs },
46
+ });
42
47
  // Send questions to client
43
48
  this.sendMessage(ws, {
44
49
  type: "NEW_QUESTION",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ask-user-question-plus",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "A TUI-style MCP server for asking user questions via a web interface.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/public/index.html CHANGED
@@ -601,11 +601,57 @@
601
601
  let activeReviewIndex = 0;
602
602
  let shouldFocusOther = false;
603
603
  let ws = null;
604
+ let sessionTimeoutMs = null;
605
+ let countdownInterval = null;
606
+ let countdownEndsAt = null;
607
+ let hasReceivedQuestions = false;
604
608
  let sessionId =
605
609
  new URLSearchParams(window.location.search).get("sessionId") ||
606
610
  "default";
607
611
  const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
608
612
 
613
+ function formatMmSs(ms) {
614
+ const totalSeconds = Math.max(0, Math.floor(ms / 1000));
615
+ const minutes = String(Math.floor(totalSeconds / 60)).padStart(2, "0");
616
+ const seconds = String(totalSeconds % 60).padStart(2, "0");
617
+ return `${minutes}:${seconds}`;
618
+ }
619
+
620
+ function setSessionInfo(statusText) {
621
+ document.getElementById("session-info").textContent = statusText;
622
+ }
623
+
624
+ function setSessionInfoConnected() {
625
+ const base = `Session: ${sessionId} (Connected)`;
626
+ if (countdownEndsAt) {
627
+ const remaining = countdownEndsAt - Date.now();
628
+ setSessionInfo(`${base} | Timeout in ${formatMmSs(remaining)}`);
629
+ } else {
630
+ setSessionInfo(base);
631
+ }
632
+ }
633
+
634
+ function stopCountdown() {
635
+ if (countdownInterval) {
636
+ clearInterval(countdownInterval);
637
+ countdownInterval = null;
638
+ }
639
+ countdownEndsAt = null;
640
+ }
641
+
642
+ function startCountdown(timeoutMs) {
643
+ stopCountdown();
644
+ countdownEndsAt = Date.now() + timeoutMs;
645
+
646
+ // Tick immediately to avoid showing stale text for up to 1s.
647
+ setSessionInfoConnected();
648
+ countdownInterval = setInterval(() => {
649
+ const remaining = countdownEndsAt - Date.now();
650
+ setSessionInfoConnected();
651
+ if (remaining <= 0) stopCountdown();
652
+ }, 1000);
653
+ }
654
+
609
655
  // --- WebSocket Logic ---
610
656
  function connectWS() {
611
657
  // Robust WS URL construction
@@ -628,9 +674,7 @@
628
674
 
629
675
  ws.onopen = () => {
630
676
  console.error("WS Open");
631
- document.getElementById(
632
- "session-info"
633
- ).textContent = `Session: ${sessionId} (Connected)`;
677
+ setSessionInfoConnected();
634
678
  document.getElementById("session-info").style.color =
635
679
  "var(--green-color)";
636
680
  ws.send(JSON.stringify({ type: "GET_STATE" }));
@@ -649,6 +693,19 @@
649
693
  try {
650
694
  const message = JSON.parse(event.data);
651
695
 
696
+ if (message.type === "SESSION_META" && message.payload) {
697
+ sessionTimeoutMs =
698
+ typeof message.payload.timeoutMs === "number"
699
+ ? message.payload.timeoutMs
700
+ : null;
701
+
702
+ // For B: start countdown when we have received the questions.
703
+ if (hasReceivedQuestions && sessionTimeoutMs) {
704
+ startCountdown(sessionTimeoutMs);
705
+ }
706
+ return;
707
+ }
708
+
652
709
  if (
653
710
  message.type === "SYNC_STATE" ||
654
711
  message.type === "NEW_QUESTION"
@@ -660,6 +717,8 @@
660
717
 
661
718
  if (questions && questions.length > 0) {
662
719
  QUESTIONS_DATA = questions;
720
+ hasReceivedQuestions = true;
721
+ if (sessionTimeoutMs) startCountdown(sessionTimeoutMs);
663
722
  initAnswers();
664
723
  activeQuestionIndex = 0;
665
724
  activeOptionIndex = 0;
@@ -675,6 +734,7 @@
675
734
  };
676
735
 
677
736
  ws.onclose = () => {
737
+ stopCountdown();
678
738
  document.getElementById(
679
739
  "session-info"
680
740
  ).textContent = `Disconnected. Reconnecting...`;