@compilr-dev/cli 0.4.0 → 0.5.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.
- package/README.md +30 -12
- package/dist/agent.d.ts +74 -1
- package/dist/agent.js +259 -76
- package/dist/anchors/index.d.ts +9 -0
- package/dist/anchors/index.js +9 -0
- package/dist/anchors/project-anchors.d.ts +79 -0
- package/dist/anchors/project-anchors.js +202 -0
- package/dist/commands/handler-types.d.ts +68 -0
- package/dist/commands/handler-types.js +8 -0
- package/dist/commands/handlers/agent-commands.d.ts +13 -0
- package/dist/commands/handlers/agent-commands.js +305 -0
- package/dist/commands/handlers/design-commands.d.ts +15 -0
- package/dist/commands/handlers/design-commands.js +334 -0
- package/dist/commands/handlers/index.d.ts +20 -0
- package/dist/commands/handlers/index.js +43 -0
- package/dist/commands/handlers/overlay-commands.d.ts +21 -0
- package/dist/commands/handlers/overlay-commands.js +287 -0
- package/dist/commands/handlers/project-commands.d.ts +11 -0
- package/dist/commands/handlers/project-commands.js +167 -0
- package/dist/commands/handlers/simple-commands.d.ts +19 -0
- package/dist/commands/handlers/simple-commands.js +144 -0
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/registry.d.ts +50 -0
- package/dist/commands/registry.js +75 -0
- package/dist/commands-v2/handlers/context.d.ts +13 -0
- package/dist/commands-v2/handlers/context.js +348 -0
- package/dist/commands-v2/handlers/core.d.ts +13 -0
- package/dist/commands-v2/handlers/core.js +165 -0
- package/dist/commands-v2/handlers/debug.d.ts +11 -0
- package/dist/commands-v2/handlers/debug.js +159 -0
- package/dist/commands-v2/handlers/index.d.ts +12 -0
- package/dist/commands-v2/handlers/index.js +24 -0
- package/dist/commands-v2/handlers/project.d.ts +22 -0
- package/dist/commands-v2/handlers/project.js +814 -0
- package/dist/commands-v2/handlers/settings.d.ts +15 -0
- package/dist/commands-v2/handlers/settings.js +235 -0
- package/dist/commands-v2/index.d.ts +13 -0
- package/dist/commands-v2/index.js +15 -0
- package/dist/commands-v2/registry.d.ts +37 -0
- package/dist/commands-v2/registry.js +80 -0
- package/dist/commands-v2/types.d.ts +75 -0
- package/dist/commands-v2/types.js +7 -0
- package/dist/commands.js +110 -7
- package/dist/index.js +288 -29
- package/dist/input-handlers/index.d.ts +7 -0
- package/dist/input-handlers/index.js +7 -0
- package/dist/input-handlers/memory-handler.d.ts +26 -0
- package/dist/input-handlers/memory-handler.js +68 -0
- package/dist/repl-helpers.d.ts +63 -0
- package/dist/repl-helpers.js +318 -0
- package/dist/repl-v2.d.ts +155 -0
- package/dist/repl-v2.js +774 -0
- package/dist/repl.d.ts +32 -4
- package/dist/repl.js +250 -977
- package/dist/settings/index.d.ts +23 -0
- package/dist/settings/index.js +48 -0
- package/dist/settings/paths.d.ts +110 -0
- package/dist/settings/paths.js +264 -0
- package/dist/templates/compilr-md.js +7 -4
- package/dist/templates/index.js +3 -4
- package/dist/themes/colors.js +3 -1
- package/dist/themes/registry.d.ts +5 -36
- package/dist/themes/registry.js +11 -95
- package/dist/themes/types.d.ts +3 -38
- package/dist/themes/types.js +2 -2
- package/dist/tools/anchor-tools.d.ts +31 -0
- package/dist/tools/anchor-tools.js +255 -0
- package/dist/tools/backlog-wrappers.d.ts +54 -0
- package/dist/tools/backlog-wrappers.js +338 -0
- package/dist/tools/backlog.js +1 -1
- package/dist/tools/db-tools.d.ts +65 -0
- package/dist/tools/db-tools.js +19 -0
- package/dist/tools/document-db.d.ts +43 -0
- package/dist/tools/document-db.js +220 -0
- package/dist/tools/project-db.d.ts +102 -0
- package/dist/tools/project-db.js +370 -0
- package/dist/tools/workitem-db.d.ts +103 -0
- package/dist/tools/workitem-db.js +549 -0
- package/dist/tools.js +13 -3
- package/dist/ui/agents-overlay-v2.d.ts +43 -0
- package/dist/ui/agents-overlay-v2.js +809 -0
- package/dist/ui/agents-overlay.d.ts +5 -5
- package/dist/ui/agents-overlay.js +782 -420
- package/dist/ui/anchors-overlay.d.ts +12 -0
- package/dist/ui/anchors-overlay.js +775 -0
- package/dist/ui/arch-type-overlay.d.ts +1 -6
- package/dist/ui/arch-type-overlay.js +175 -203
- package/dist/ui/ask-user-overlay-v2.d.ts +26 -0
- package/dist/ui/ask-user-overlay-v2.js +555 -0
- package/dist/ui/ask-user-overlay.d.ts +2 -2
- package/dist/ui/ask-user-overlay.js +443 -535
- package/dist/ui/ask-user-simple-overlay-v2.d.ts +25 -0
- package/dist/ui/ask-user-simple-overlay-v2.js +215 -0
- package/dist/ui/ask-user-simple-overlay.d.ts +2 -2
- package/dist/ui/ask-user-simple-overlay.js +182 -209
- package/dist/ui/backlog-overlay.d.ts +16 -1
- package/dist/ui/backlog-overlay.js +525 -659
- package/dist/ui/base/index.d.ts +26 -0
- package/dist/ui/base/index.js +33 -0
- package/dist/ui/base/inline-overlay-utils.d.ts +217 -0
- package/dist/ui/base/inline-overlay-utils.js +320 -0
- package/dist/ui/base/inline-overlay.d.ts +159 -0
- package/dist/ui/base/inline-overlay.js +257 -0
- package/dist/ui/base/key-utils.d.ts +15 -0
- package/dist/ui/base/key-utils.js +30 -0
- package/dist/ui/base/overlay-base-v2.d.ts +193 -0
- package/dist/ui/base/overlay-base-v2.js +246 -0
- package/dist/ui/base/overlay-base.d.ts +156 -0
- package/dist/ui/base/overlay-base.js +238 -0
- package/dist/ui/base/overlay-lifecycle.d.ts +65 -0
- package/dist/ui/base/overlay-lifecycle.js +159 -0
- package/dist/ui/base/overlay-types.d.ts +185 -0
- package/dist/ui/base/overlay-types.js +7 -0
- package/dist/ui/base/render-utils.d.ts +8 -0
- package/dist/ui/base/render-utils.js +11 -0
- package/dist/ui/base/screen-stack.d.ts +148 -0
- package/dist/ui/base/screen-stack.js +184 -0
- package/dist/ui/base/tabbed-list-overlay-v2.d.ts +103 -0
- package/dist/ui/base/tabbed-list-overlay-v2.js +317 -0
- package/dist/ui/base/tabbed-list-overlay.d.ts +153 -0
- package/dist/ui/base/tabbed-list-overlay.js +369 -0
- package/dist/ui/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/commands-overlay-v2.js +441 -0
- package/dist/ui/commands-overlay.d.ts +7 -2
- package/dist/ui/commands-overlay.js +384 -355
- package/dist/ui/config-overlay.d.ts +5 -4
- package/dist/ui/config-overlay.js +243 -513
- package/dist/ui/conversation.d.ts +75 -4
- package/dist/ui/conversation.js +374 -161
- package/dist/ui/docs-overlay.d.ts +17 -0
- package/dist/ui/docs-overlay.js +303 -0
- package/dist/ui/ephemeral.d.ts +1 -1
- package/dist/ui/ephemeral.js +1 -1
- package/dist/ui/features/index.d.ts +34 -0
- package/dist/ui/features/index.js +34 -0
- package/dist/ui/features/input-feature.d.ts +85 -0
- package/dist/ui/features/input-feature.js +238 -0
- package/dist/ui/features/list-feature.d.ts +155 -0
- package/dist/ui/features/list-feature.js +244 -0
- package/dist/ui/features/pagination-feature.d.ts +154 -0
- package/dist/ui/features/pagination-feature.js +238 -0
- package/dist/ui/features/search-feature.d.ts +148 -0
- package/dist/ui/features/search-feature.js +185 -0
- package/dist/ui/features/tab-feature.d.ts +194 -0
- package/dist/ui/features/tab-feature.js +307 -0
- package/dist/ui/footer-v2.d.ts +222 -0
- package/dist/ui/footer-v2.js +1349 -0
- package/dist/ui/footer.d.ts +107 -0
- package/dist/ui/footer.js +359 -67
- package/dist/ui/guardrail-overlay.d.ts +29 -0
- package/dist/ui/guardrail-overlay.js +145 -0
- package/dist/ui/help-overlay-v2.d.ts +34 -0
- package/dist/ui/help-overlay-v2.js +309 -0
- package/dist/ui/help-overlay.d.ts +16 -0
- package/dist/ui/help-overlay.js +316 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -3
- package/dist/ui/init-overlay-v2.d.ts +34 -0
- package/dist/ui/init-overlay-v2.js +600 -0
- package/dist/ui/init-overlay.d.ts +12 -2
- package/dist/ui/init-overlay.js +349 -270
- package/dist/ui/input-prompt-v2.d.ts +1 -0
- package/dist/ui/input-prompt-v2.js +14 -6
- package/dist/ui/input-prompt.d.ts +116 -33
- package/dist/ui/input-prompt.js +536 -337
- package/dist/ui/iteration-limit-overlay-v2.d.ts +21 -0
- package/dist/ui/iteration-limit-overlay-v2.js +114 -0
- package/dist/ui/iteration-limit-overlay.d.ts +2 -2
- package/dist/ui/iteration-limit-overlay.js +92 -128
- package/dist/ui/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/keys-overlay-v2.js +248 -0
- package/dist/ui/keys-overlay.d.ts +1 -0
- package/dist/ui/keys-overlay.js +203 -141
- package/dist/ui/line-utils.d.ts +88 -0
- package/dist/ui/line-utils.js +150 -0
- package/dist/ui/live-region.d.ts +161 -0
- package/dist/ui/live-region.js +387 -0
- package/dist/ui/mascot/expressions.d.ts +32 -0
- package/dist/ui/mascot/expressions.js +213 -0
- package/dist/ui/mascot/index.d.ts +8 -0
- package/dist/ui/mascot/index.js +8 -0
- package/dist/ui/mascot/renderer.d.ts +19 -0
- package/dist/ui/mascot/renderer.js +97 -0
- package/dist/ui/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/mascot-overlay-v2.js +138 -0
- package/dist/ui/mascot-overlay.d.ts +21 -0
- package/dist/ui/mascot-overlay.js +146 -0
- package/dist/ui/model-overlay-v2.d.ts +49 -0
- package/dist/ui/model-overlay-v2.js +118 -0
- package/dist/ui/model-overlay.d.ts +27 -0
- package/dist/ui/model-overlay.js +221 -0
- package/dist/ui/model-warning-overlay.js +3 -5
- package/dist/ui/new-overlay.d.ts +34 -0
- package/dist/ui/new-overlay.js +604 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.js +825 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.js +783 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.d.ts +37 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.js +240 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.d.ts +72 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.js +584 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.js +204 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.js +642 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.js +441 -0
- package/dist/ui/overlay/impl/config-overlay-v2.d.ts +100 -0
- package/dist/ui/overlay/impl/config-overlay-v2.js +654 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +55 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.js +359 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1071 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.d.ts +43 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/help-overlay-v2.d.ts +34 -0
- package/dist/ui/overlay/impl/help-overlay-v2.js +309 -0
- package/dist/ui/overlay/impl/init-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/init-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.d.ts +25 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.js +97 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.d.ts +35 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.js +105 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.js +248 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.js +138 -0
- package/dist/ui/overlay/impl/model-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/model-overlay-v2.js +118 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.js +132 -0
- package/dist/ui/overlay/impl/new-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/new-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.js +380 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.js +499 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.js +135 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.js +218 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +80 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.js +637 -0
- package/dist/ui/overlay/index.d.ts +33 -0
- package/dist/ui/overlay/index.js +35 -0
- package/dist/ui/overlay/key-utils.d.ts +6 -0
- package/dist/ui/overlay/key-utils.js +6 -0
- package/dist/ui/overlay/overlay-types.d.ts +128 -0
- package/dist/ui/overlay/overlay-types.js +22 -0
- package/dist/ui/overlay/types.d.ts +135 -0
- package/dist/ui/overlay/types.js +22 -0
- package/dist/ui/overlays/help-overlay-v2.d.ts +28 -0
- package/dist/ui/overlays/help-overlay-v2.js +198 -0
- package/dist/ui/overlays/index.d.ts +11 -0
- package/dist/ui/overlays/index.js +11 -0
- package/dist/ui/overlays.d.ts +0 -4
- package/dist/ui/overlays.js +0 -444
- package/dist/ui/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/permission-overlay-v2.js +380 -0
- package/dist/ui/permission-overlay.d.ts +1 -1
- package/dist/ui/permission-overlay.js +186 -298
- package/dist/ui/projects-overlay.d.ts +19 -0
- package/dist/ui/projects-overlay.js +484 -0
- package/dist/ui/providers/types.d.ts +178 -0
- package/dist/ui/providers/types.js +9 -0
- package/dist/ui/render-modes.d.ts +36 -0
- package/dist/ui/render-modes.js +44 -0
- package/dist/ui/startup-menu.d.ts +36 -0
- package/dist/ui/startup-menu.js +236 -0
- package/dist/ui/subagent-renderer.d.ts +117 -0
- package/dist/ui/subagent-renderer.js +334 -0
- package/dist/ui/terminal-codes.d.ts +94 -0
- package/dist/ui/terminal-codes.js +124 -0
- package/dist/ui/terminal-renderer.d.ts +221 -0
- package/dist/ui/terminal-renderer.js +751 -0
- package/dist/ui/terminal-ui.d.ts +463 -0
- package/dist/ui/terminal-ui.js +2296 -0
- package/dist/ui/terminal.d.ts +20 -0
- package/dist/ui/terminal.js +72 -0
- package/dist/ui/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/theme-overlay-v2.js +135 -0
- package/dist/ui/theme-overlay.d.ts +24 -0
- package/dist/ui/theme-overlay.js +127 -0
- package/dist/ui/todo-zone.js +53 -25
- package/dist/ui/tool-formatters.d.ts +16 -0
- package/dist/ui/tool-formatters.js +516 -0
- package/dist/ui/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/tools-overlay-v2.js +218 -0
- package/dist/ui/tools-overlay.d.ts +10 -2
- package/dist/ui/tools-overlay.js +172 -220
- package/dist/ui/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/tutorial-overlay.d.ts +1 -0
- package/dist/ui/tutorial-overlay.js +400 -302
- package/dist/ui/workflow-overlay.d.ts +22 -0
- package/dist/ui/workflow-overlay.js +636 -0
- package/dist/utils/debug-log.d.ts +28 -0
- package/dist/utils/debug-log.js +57 -0
- package/dist/utils/model-tiers.js +1 -1
- package/dist/utils/path-safety.d.ts +56 -0
- package/dist/utils/path-safety.js +239 -0
- package/dist/workflow/guided-mode-injector.d.ts +42 -0
- package/dist/workflow/guided-mode-injector.js +191 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.js +8 -0
- package/dist/workflow/step-criteria.d.ts +62 -0
- package/dist/workflow/step-criteria.js +150 -0
- package/dist/workflow/step-tracker.d.ts +92 -0
- package/dist/workflow/step-tracker.js +141 -0
- package/package.json +12 -5
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ask User Overlay
|
|
2
|
+
* Ask User Overlay (Refactored)
|
|
3
3
|
*
|
|
4
4
|
* Modal overlay for presenting multi-question forms to the user.
|
|
5
|
-
*
|
|
5
|
+
* Uses InlineOverlay base class for consistent lifecycle management.
|
|
6
6
|
*
|
|
7
7
|
* Features:
|
|
8
8
|
* - Multiple questions with navigation (←/→ or Tab)
|
|
@@ -12,636 +12,544 @@
|
|
|
12
12
|
* - Progress indicator showing answered questions
|
|
13
13
|
*/
|
|
14
14
|
import chalk from 'chalk';
|
|
15
|
-
import * as terminal from './terminal.js';
|
|
16
15
|
import { getStyles } from '../themes/index.js';
|
|
16
|
+
import { InlineOverlay } from './base/inline-overlay.js';
|
|
17
17
|
// =============================================================================
|
|
18
|
-
//
|
|
18
|
+
// Overlay Implementation
|
|
19
19
|
// =============================================================================
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
20
|
+
class AskUserOverlayImpl extends InlineOverlay {
|
|
21
|
+
questions;
|
|
22
|
+
context;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
super();
|
|
25
|
+
this.questions = options.questions;
|
|
26
|
+
this.context = options.context;
|
|
27
|
+
}
|
|
28
|
+
getInitialState() {
|
|
29
|
+
// Check if first question should auto-start in typing mode
|
|
30
|
+
const firstQ = this.questions[0];
|
|
31
|
+
const firstQAutoType = (firstQ.options?.length ?? 0) === 0 &&
|
|
32
|
+
firstQ.allowCustom !== false &&
|
|
33
|
+
firstQ.multiSelect !== true;
|
|
34
|
+
return {
|
|
35
|
+
currentQuestion: 0,
|
|
36
|
+
selectedIndex: 0,
|
|
37
|
+
inputBuffer: '',
|
|
38
|
+
isTypingCustom: firstQAutoType,
|
|
39
|
+
answers: {},
|
|
40
|
+
multiSelections: new Set(),
|
|
41
|
+
warningMessage: '',
|
|
42
|
+
isOnSubmitTab: false,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
const s = getStyles();
|
|
47
|
+
const lines = [];
|
|
48
|
+
const cols = this.getTerminalWidth();
|
|
49
|
+
const border = s.muted('─'.repeat(Math.max(1, cols - 1)));
|
|
50
|
+
// Header
|
|
51
|
+
lines.push(border);
|
|
52
|
+
lines.push(' ' + s.primaryBold('Questions'));
|
|
53
|
+
lines.push('');
|
|
54
|
+
// Tab bar
|
|
55
|
+
lines.push(...this.renderTabBar());
|
|
56
|
+
lines.push('');
|
|
57
|
+
// Current question or Submit tab
|
|
58
|
+
if (this.state.isOnSubmitTab) {
|
|
59
|
+
lines.push(...this.renderSubmitTab());
|
|
39
60
|
}
|
|
40
61
|
else {
|
|
41
|
-
|
|
42
|
-
|
|
62
|
+
lines.push(...this.renderQuestion());
|
|
63
|
+
}
|
|
64
|
+
// Footer with instructions
|
|
65
|
+
lines.push(...this.renderFooter());
|
|
66
|
+
// Warning message if present
|
|
67
|
+
if (this.state.warningMessage) {
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(s.warning(` ⚠ ${this.state.warningMessage}`));
|
|
43
70
|
}
|
|
71
|
+
// Bottom border
|
|
72
|
+
lines.push(border);
|
|
73
|
+
return lines;
|
|
44
74
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
75
|
+
handleKey(data) {
|
|
76
|
+
// Ctrl+C always cancels
|
|
77
|
+
if (this.isCtrlCKey(data)) {
|
|
78
|
+
return { type: 'close', result: this.getResult() };
|
|
79
|
+
}
|
|
80
|
+
// Handle Submit tab first
|
|
81
|
+
if (this.state.isOnSubmitTab) {
|
|
82
|
+
return this.handleSubmitTabKey(data);
|
|
83
|
+
}
|
|
84
|
+
// Handle typing mode
|
|
85
|
+
if (this.state.isTypingCustom) {
|
|
86
|
+
return this.handleTypingKey(data);
|
|
87
|
+
}
|
|
88
|
+
// Handle navigation mode
|
|
89
|
+
return this.handleNavigationKey(data);
|
|
49
90
|
}
|
|
50
|
-
|
|
51
|
-
|
|
91
|
+
getCleanupSummary(result) {
|
|
92
|
+
const s = getStyles();
|
|
93
|
+
const answeredCount = Object.keys(result.answers).length;
|
|
94
|
+
const skippedCount = result.skipped.length;
|
|
95
|
+
if (answeredCount === 0) {
|
|
96
|
+
return s.muted('Questions: ') + s.warning('Cancelled');
|
|
97
|
+
}
|
|
98
|
+
if (skippedCount > 0) {
|
|
99
|
+
return s.muted('Questions: ') + s.success(`${String(answeredCount)} answered`) + s.muted(`, ${String(skippedCount)} skipped`);
|
|
100
|
+
}
|
|
101
|
+
return s.muted('Questions: ') + s.success(`${String(answeredCount)} answered`);
|
|
52
102
|
}
|
|
53
|
-
|
|
54
|
-
|
|
103
|
+
// ===========================================================================
|
|
104
|
+
// Private: Rendering Helpers
|
|
105
|
+
// ===========================================================================
|
|
106
|
+
renderTabBar() {
|
|
107
|
+
const s = getStyles();
|
|
108
|
+
const lines = [];
|
|
109
|
+
let tabLine = ' ';
|
|
110
|
+
for (let i = 0; i < this.questions.length; i++) {
|
|
111
|
+
const q = this.questions[i];
|
|
112
|
+
const hasAnswer = q.id in this.state.answers;
|
|
113
|
+
const isCurrent = i === this.state.currentQuestion && !this.state.isOnSubmitTab;
|
|
114
|
+
const label = q.header || q.id.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
115
|
+
if (isCurrent) {
|
|
116
|
+
tabLine += s.selected(` ${label} `) + ' ';
|
|
117
|
+
}
|
|
118
|
+
else if (hasAnswer) {
|
|
119
|
+
tabLine += s.success(`✓ ${label}`) + ' ';
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
tabLine += s.muted(` ${label} `) + ' ';
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Add Submit tab
|
|
126
|
+
const allAnswered = this.questions.every((q) => q.id in this.state.answers);
|
|
127
|
+
if (this.state.isOnSubmitTab) {
|
|
128
|
+
tabLine += s.selected(' Submit ');
|
|
129
|
+
}
|
|
130
|
+
else if (allAnswered) {
|
|
131
|
+
tabLine += s.success(' Submit ');
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
tabLine += s.muted(' Submit ');
|
|
135
|
+
}
|
|
136
|
+
lines.push(tabLine);
|
|
137
|
+
return lines;
|
|
55
138
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
139
|
+
renderQuestion() {
|
|
140
|
+
const s = getStyles();
|
|
141
|
+
const lines = [];
|
|
142
|
+
const question = this.questions[this.state.currentQuestion];
|
|
143
|
+
const questionIndex = this.state.currentQuestion;
|
|
144
|
+
const totalQuestions = this.questions.length;
|
|
145
|
+
// Context if provided (only on first question)
|
|
146
|
+
if (this.context && questionIndex === 0) {
|
|
147
|
+
lines.push(s.muted(' ' + this.context));
|
|
148
|
+
lines.push('');
|
|
149
|
+
}
|
|
150
|
+
// Question number and text
|
|
151
|
+
lines.push(chalk.bold(` [${String(questionIndex + 1)}/${String(totalQuestions)}] ${question.question}`));
|
|
65
152
|
lines.push('');
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
153
|
+
// Options
|
|
154
|
+
const options = question.options ?? [];
|
|
155
|
+
const allowCustom = question.allowCustom !== false;
|
|
156
|
+
const isMultiSelect = question.multiSelect === true;
|
|
157
|
+
const customIndex = options.length;
|
|
158
|
+
// Get existing answer info
|
|
159
|
+
const { answeredOptions, customAnswerValue } = this.getAnswerInfo(question);
|
|
160
|
+
for (let i = 0; i < options.length; i++) {
|
|
161
|
+
const isCursor = this.state.selectedIndex === i;
|
|
162
|
+
const isMultiSelected = isMultiSelect && this.state.multiSelections.has(i);
|
|
163
|
+
const isAnswered = answeredOptions.has(i);
|
|
164
|
+
const prefix = isCursor ? ' ❯ ' : ' ';
|
|
165
|
+
let marker = '';
|
|
166
|
+
if (isMultiSelect) {
|
|
167
|
+
marker = isMultiSelected ? '[✓] ' : '[ ] ';
|
|
168
|
+
}
|
|
169
|
+
else if (isAnswered) {
|
|
170
|
+
marker = '● ';
|
|
171
|
+
}
|
|
172
|
+
const label = `${String(i + 1)}. ${options[i]}`;
|
|
173
|
+
if (isCursor) {
|
|
174
|
+
lines.push(s.primary(prefix + marker + label));
|
|
175
|
+
}
|
|
176
|
+
else if (isMultiSelected || isAnswered) {
|
|
177
|
+
lines.push(s.success(prefix + marker + label));
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
lines.push(s.muted(prefix + marker + label));
|
|
89
181
|
}
|
|
90
182
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
183
|
+
// Custom option
|
|
184
|
+
if (allowCustom) {
|
|
185
|
+
const isCursor = this.state.selectedIndex === customIndex;
|
|
186
|
+
const prefix = isCursor ? ' ❯ ' : ' ';
|
|
187
|
+
const hasCustomAnswer = customAnswerValue !== '' || this.state.inputBuffer !== '';
|
|
188
|
+
const displayValue = this.state.inputBuffer || customAnswerValue;
|
|
189
|
+
if (this.state.isTypingCustom) {
|
|
190
|
+
lines.push(s.primary(prefix + 'Custom: ' + this.state.inputBuffer + '▋'));
|
|
191
|
+
}
|
|
192
|
+
else if (hasCustomAnswer) {
|
|
193
|
+
const marker = isMultiSelect ? '[✓] ' : '● ';
|
|
194
|
+
const label = `${String(options.length + 1)}. Custom: "${displayValue}"`;
|
|
195
|
+
lines.push(isCursor ? s.primary(prefix + marker + label) : s.success(prefix + marker + label));
|
|
95
196
|
}
|
|
96
197
|
else {
|
|
97
|
-
|
|
198
|
+
const label = `${String(options.length + 1)}. Type something custom...`;
|
|
199
|
+
lines.push(isCursor ? s.primary(prefix + label) : s.muted(prefix + label));
|
|
98
200
|
}
|
|
99
201
|
}
|
|
202
|
+
return lines;
|
|
100
203
|
}
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
204
|
+
renderSubmitTab() {
|
|
205
|
+
const s = getStyles();
|
|
206
|
+
const lines = [];
|
|
207
|
+
lines.push('');
|
|
208
|
+
lines.push(chalk.bold(' Ready to submit?'));
|
|
209
|
+
lines.push('');
|
|
210
|
+
const answeredCount = Object.keys(this.state.answers).length;
|
|
211
|
+
const totalCount = this.questions.length;
|
|
212
|
+
const allAnswered = answeredCount === totalCount;
|
|
213
|
+
if (allAnswered) {
|
|
214
|
+
lines.push(s.success(` ✓ All ${String(totalCount)} questions answered`));
|
|
215
|
+
lines.push('');
|
|
216
|
+
lines.push(' ' + s.muted('Press Enter to submit your answers.'));
|
|
111
217
|
}
|
|
112
|
-
else
|
|
113
|
-
|
|
218
|
+
else {
|
|
219
|
+
const unansweredCount = totalCount - answeredCount;
|
|
220
|
+
lines.push(s.warning(` ⚠ ${String(unansweredCount)} of ${String(totalCount)} questions not answered`));
|
|
221
|
+
lines.push('');
|
|
222
|
+
lines.push(' ' + s.muted('Unanswered:'));
|
|
223
|
+
for (const q of this.questions) {
|
|
224
|
+
if (!(q.id in this.state.answers)) {
|
|
225
|
+
const label = q.header || q.id.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
226
|
+
lines.push(' ' + s.muted(`• ${label}`));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
lines.push('');
|
|
230
|
+
lines.push(' ' + s.muted('Press ← or Tab to go back and answer.'));
|
|
114
231
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
232
|
+
return lines;
|
|
233
|
+
}
|
|
234
|
+
renderFooter() {
|
|
235
|
+
const s = getStyles();
|
|
236
|
+
const lines = [];
|
|
237
|
+
lines.push('');
|
|
238
|
+
if (this.state.isOnSubmitTab) {
|
|
239
|
+
lines.push(s.muted(' Enter Submit all · ←/Tab Go back · Esc Cancel'));
|
|
118
240
|
}
|
|
119
|
-
else if (
|
|
120
|
-
lines.push(s.
|
|
241
|
+
else if (this.state.isTypingCustom) {
|
|
242
|
+
lines.push(s.muted(' Enter Submit · Esc Cancel custom'));
|
|
121
243
|
}
|
|
122
244
|
else {
|
|
123
|
-
|
|
245
|
+
const currentQ = this.questions[this.state.currentQuestion];
|
|
246
|
+
if (currentQ.multiSelect === true) {
|
|
247
|
+
lines.push(s.muted(' ↑↓ Navigate · Space Toggle · Enter Confirm · Tab Next · Esc Cancel'));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
lines.push(s.muted(' ↑↓ Navigate · Enter Select · Tab Next · Esc Cancel'));
|
|
251
|
+
}
|
|
124
252
|
}
|
|
253
|
+
return lines;
|
|
125
254
|
}
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (state.isTypingCustom) {
|
|
133
|
-
lines.push(s.primary(prefix + 'Custom: ' + state.inputBuffer + '█'));
|
|
134
|
-
}
|
|
135
|
-
else if (hasCustomAnswer) {
|
|
136
|
-
// Show the custom answer value
|
|
137
|
-
const marker = isMultiSelect ? '[✓] ' : '● ';
|
|
138
|
-
const label = `${String(options.length + 1)}. Custom: "${displayValue}"`;
|
|
139
|
-
lines.push(isCursor ? s.primary(prefix + marker + label) : s.success(prefix + marker + label));
|
|
255
|
+
// ===========================================================================
|
|
256
|
+
// Private: Key Handlers
|
|
257
|
+
// ===========================================================================
|
|
258
|
+
handleSubmitTabKey(data) {
|
|
259
|
+
if (this.isEscapeKey(data)) {
|
|
260
|
+
return { type: 'close', result: this.getResult() };
|
|
140
261
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
262
|
+
if (this.isLeftArrowKey(data) || this.isTabKey(data)) {
|
|
263
|
+
this.prevQuestion();
|
|
264
|
+
return { type: 'continue' };
|
|
144
265
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
function renderFooter(isTypingCustom, isMultiSelect, isOnSubmitTab) {
|
|
149
|
-
const s = getStyles();
|
|
150
|
-
const lines = [];
|
|
151
|
-
lines.push('');
|
|
152
|
-
if (isOnSubmitTab) {
|
|
153
|
-
lines.push(s.muted(' Enter Submit all · ←/Tab Go back · Esc Cancel'));
|
|
154
|
-
}
|
|
155
|
-
else if (isTypingCustom) {
|
|
156
|
-
lines.push(s.muted(' Enter Submit · Esc Cancel custom'));
|
|
157
|
-
}
|
|
158
|
-
else if (isMultiSelect) {
|
|
159
|
-
lines.push(s.muted(' ↑↓ Navigate · Space Toggle · Enter Confirm · Tab Next · Esc Cancel'));
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
lines.push(s.muted(' ↑↓ Navigate · Enter Select · Tab Next · Esc Cancel'));
|
|
163
|
-
}
|
|
164
|
-
return lines;
|
|
165
|
-
}
|
|
166
|
-
function renderSubmitTab(questions, answers) {
|
|
167
|
-
const s = getStyles();
|
|
168
|
-
const lines = [];
|
|
169
|
-
lines.push('');
|
|
170
|
-
lines.push(chalk.bold(' Ready to submit?'));
|
|
171
|
-
lines.push('');
|
|
172
|
-
// Show summary of answers
|
|
173
|
-
const answeredCount = Object.keys(answers).length;
|
|
174
|
-
const totalCount = questions.length;
|
|
175
|
-
const allAnswered = answeredCount === totalCount;
|
|
176
|
-
if (allAnswered) {
|
|
177
|
-
lines.push(s.success(` ✓ All ${String(totalCount)} questions answered`));
|
|
178
|
-
lines.push('');
|
|
179
|
-
lines.push(' ' + s.muted('Press Enter to submit your answers.'));
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
const unansweredCount = totalCount - answeredCount;
|
|
183
|
-
lines.push(s.warning(` ⚠ ${String(unansweredCount)} of ${String(totalCount)} questions not answered`));
|
|
184
|
-
lines.push('');
|
|
185
|
-
// List unanswered questions
|
|
186
|
-
lines.push(' ' + s.muted('Unanswered:'));
|
|
187
|
-
for (const q of questions) {
|
|
188
|
-
if (!(q.id in answers)) {
|
|
189
|
-
const label = q.header || q.id.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
190
|
-
lines.push(' ' + s.muted(`• ${label}`));
|
|
266
|
+
if (this.isEnterKey(data)) {
|
|
267
|
+
if (this.tryComplete()) {
|
|
268
|
+
return { type: 'close', result: this.getResult() };
|
|
191
269
|
}
|
|
270
|
+
// tryComplete sets warning and navigates to first unanswered
|
|
192
271
|
}
|
|
193
|
-
|
|
194
|
-
lines.push(' ' + s.muted('Press ← or Tab to go back and answer.'));
|
|
272
|
+
return { type: 'continue' };
|
|
195
273
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
274
|
+
handleTypingKey(data) {
|
|
275
|
+
const currentQ = this.questions[this.state.currentQuestion];
|
|
276
|
+
const options = currentQ.options ?? [];
|
|
277
|
+
if (this.isEscapeKey(data)) {
|
|
278
|
+
this.state.isTypingCustom = false;
|
|
279
|
+
this.state.inputBuffer = '';
|
|
280
|
+
return { type: 'continue' };
|
|
281
|
+
}
|
|
282
|
+
if (this.isUpArrowKey(data) && options.length > 0) {
|
|
283
|
+
this.state.isTypingCustom = false;
|
|
284
|
+
this.state.inputBuffer = '';
|
|
285
|
+
this.state.selectedIndex = Math.max(0, this.state.selectedIndex - 1);
|
|
286
|
+
return { type: 'continue' };
|
|
287
|
+
}
|
|
288
|
+
if (this.isDownArrowKey(data)) {
|
|
289
|
+
// Custom is last option, down arrow does nothing
|
|
290
|
+
return { type: 'continue' };
|
|
291
|
+
}
|
|
292
|
+
if (this.isEnterKey(data)) {
|
|
293
|
+
if (this.submitAnswer()) {
|
|
294
|
+
this.state.warningMessage = '';
|
|
295
|
+
this.nextQuestion();
|
|
296
|
+
}
|
|
297
|
+
return { type: 'continue' };
|
|
298
|
+
}
|
|
299
|
+
if (this.isBackspaceKey(data)) {
|
|
300
|
+
this.state.inputBuffer = this.state.inputBuffer.slice(0, -1);
|
|
301
|
+
return { type: 'continue' };
|
|
302
|
+
}
|
|
303
|
+
// Printable character
|
|
304
|
+
const char = this.getPrintableChar(data);
|
|
305
|
+
if (char) {
|
|
306
|
+
this.state.inputBuffer += char;
|
|
307
|
+
}
|
|
308
|
+
return { type: 'continue' };
|
|
230
309
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
310
|
+
handleNavigationKey(data) {
|
|
311
|
+
const optionCount = this.getOptionCount();
|
|
312
|
+
const currentQ = this.questions[this.state.currentQuestion];
|
|
313
|
+
const isMultiSelect = currentQ.multiSelect === true;
|
|
314
|
+
const options = currentQ.options ?? [];
|
|
315
|
+
const allowCustom = currentQ.allowCustom !== false;
|
|
316
|
+
const customIndex = options.length;
|
|
317
|
+
if (this.isEscapeKey(data)) {
|
|
318
|
+
return { type: 'close', result: this.getResult() };
|
|
319
|
+
}
|
|
320
|
+
if (this.isUpArrowKey(data)) {
|
|
321
|
+
this.state.selectedIndex = Math.max(0, this.state.selectedIndex - 1);
|
|
322
|
+
if (!isMultiSelect && allowCustom && this.state.selectedIndex === customIndex) {
|
|
323
|
+
this.state.isTypingCustom = true;
|
|
324
|
+
}
|
|
325
|
+
return { type: 'continue' };
|
|
326
|
+
}
|
|
327
|
+
if (this.isDownArrowKey(data)) {
|
|
328
|
+
this.state.selectedIndex = Math.min(optionCount - 1, this.state.selectedIndex + 1);
|
|
329
|
+
if (!isMultiSelect && allowCustom && this.state.selectedIndex === customIndex) {
|
|
330
|
+
this.state.isTypingCustom = true;
|
|
331
|
+
}
|
|
332
|
+
return { type: 'continue' };
|
|
333
|
+
}
|
|
334
|
+
if (this.isLeftArrowKey(data)) {
|
|
335
|
+
this.prevQuestion();
|
|
336
|
+
return { type: 'continue' };
|
|
337
|
+
}
|
|
338
|
+
if (this.isRightArrowKey(data) || this.isTabKey(data)) {
|
|
339
|
+
this.nextQuestion();
|
|
340
|
+
return { type: 'continue' };
|
|
341
|
+
}
|
|
342
|
+
if (this.isSpaceKey(data) && isMultiSelect) {
|
|
343
|
+
if (this.state.multiSelections.has(this.state.selectedIndex)) {
|
|
344
|
+
this.state.multiSelections.delete(this.state.selectedIndex);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
this.state.multiSelections.add(this.state.selectedIndex);
|
|
348
|
+
}
|
|
349
|
+
return { type: 'continue' };
|
|
350
|
+
}
|
|
351
|
+
if (this.isEnterKey(data)) {
|
|
352
|
+
if (this.submitAnswer()) {
|
|
353
|
+
this.state.warningMessage = '';
|
|
354
|
+
this.nextQuestion();
|
|
355
|
+
}
|
|
356
|
+
return { type: 'continue' };
|
|
357
|
+
}
|
|
358
|
+
// Number keys 1-9
|
|
359
|
+
if (data.length === 1 && data[0] >= 0x31 && data[0] <= 0x39) {
|
|
360
|
+
const numIndex = data[0] - 0x31;
|
|
361
|
+
if (numIndex < optionCount) {
|
|
362
|
+
this.state.selectedIndex = numIndex;
|
|
363
|
+
if (!isMultiSelect) {
|
|
364
|
+
if (this.submitAnswer()) {
|
|
365
|
+
this.state.warningMessage = '';
|
|
366
|
+
this.nextQuestion();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return { type: 'continue' };
|
|
238
372
|
}
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
|
|
373
|
+
// ===========================================================================
|
|
374
|
+
// Private: Helper Methods
|
|
375
|
+
// ===========================================================================
|
|
376
|
+
getResult() {
|
|
377
|
+
const skipped = this.questions.filter((q) => !(q.id in this.state.answers)).map((q) => q.id);
|
|
378
|
+
return {
|
|
379
|
+
answers: this.state.answers,
|
|
380
|
+
skipped,
|
|
381
|
+
};
|
|
244
382
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
debugLog(`render done: newLines=${String(lines.length)}, optionCount=${String(questions[state.currentQuestion].options?.length ?? 0)}`);
|
|
248
|
-
return lines.length;
|
|
249
|
-
}
|
|
250
|
-
// =============================================================================
|
|
251
|
-
// Main Export
|
|
252
|
-
// =============================================================================
|
|
253
|
-
/**
|
|
254
|
-
* Show the ask user overlay
|
|
255
|
-
*/
|
|
256
|
-
export async function showAskUserOverlay(options) {
|
|
257
|
-
const { questions, context } = options;
|
|
258
|
-
// Check if first question should auto-start in typing mode
|
|
259
|
-
// (no options, custom allowed, single-select)
|
|
260
|
-
const firstQ = questions[0];
|
|
261
|
-
const firstQAutoType = (firstQ.options?.length ?? 0) === 0 &&
|
|
262
|
-
firstQ.allowCustom !== false &&
|
|
263
|
-
firstQ.multiSelect !== true;
|
|
264
|
-
const state = {
|
|
265
|
-
currentQuestion: 0,
|
|
266
|
-
selectedIndex: 0,
|
|
267
|
-
inputBuffer: '',
|
|
268
|
-
isTypingCustom: firstQAutoType,
|
|
269
|
-
answers: {},
|
|
270
|
-
multiSelections: new Set(),
|
|
271
|
-
cancelled: false,
|
|
272
|
-
warningMessage: '',
|
|
273
|
-
isOnSubmitTab: false,
|
|
274
|
-
};
|
|
275
|
-
let lineCount = 0;
|
|
276
|
-
let maxLineCount = 0; // Track max lines ever rendered to ensure full clearing
|
|
277
|
-
// NOTE: Footer is already paused by the caller (index.ts handler calls sharedState.pauseFooter)
|
|
278
|
-
// Do NOT call pauseForOverlay() here - it causes double-pause issues
|
|
279
|
-
// The caller's pause already clears the footer from screen
|
|
280
|
-
// Ensure we start from a fresh line (like config-overlay does)
|
|
281
|
-
terminal.writeLine('');
|
|
282
|
-
terminal.hideCursor();
|
|
283
|
-
const wasRawMode = process.stdin.isRaw;
|
|
284
|
-
terminal.enableRawMode();
|
|
285
|
-
// Initial render (no re-render needed - matches config-overlay pattern)
|
|
286
|
-
lineCount = render(questions, state, context, 0);
|
|
287
|
-
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
288
|
-
// Helper: Get option count for current question
|
|
289
|
-
const getOptionCount = () => {
|
|
290
|
-
const q = questions[state.currentQuestion];
|
|
383
|
+
getOptionCount() {
|
|
384
|
+
const q = this.questions[this.state.currentQuestion];
|
|
291
385
|
const optionCount = q.options?.length ?? 0;
|
|
292
386
|
const allowCustom = q.allowCustom !== false;
|
|
293
387
|
return allowCustom ? optionCount + 1 : optionCount;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const
|
|
388
|
+
}
|
|
389
|
+
getAnswerInfo(question) {
|
|
390
|
+
const options = question.options ?? [];
|
|
391
|
+
const isMultiSelect = question.multiSelect === true;
|
|
392
|
+
const answeredOptions = new Set();
|
|
393
|
+
let customAnswerValue = '';
|
|
394
|
+
if (question.id in this.state.answers) {
|
|
395
|
+
const existingAnswer = this.state.answers[question.id];
|
|
396
|
+
if (isMultiSelect && Array.isArray(existingAnswer)) {
|
|
397
|
+
for (const ans of existingAnswer) {
|
|
398
|
+
const idx = options.indexOf(ans);
|
|
399
|
+
if (idx >= 0) {
|
|
400
|
+
answeredOptions.add(idx);
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
customAnswerValue = ans;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
else if (typeof existingAnswer === 'string') {
|
|
408
|
+
const idx = options.indexOf(existingAnswer);
|
|
409
|
+
if (idx >= 0) {
|
|
410
|
+
answeredOptions.add(idx);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
customAnswerValue = existingAnswer;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return { answeredOptions, customAnswerValue };
|
|
418
|
+
}
|
|
419
|
+
restoreFromAnswer() {
|
|
420
|
+
const q = this.questions[this.state.currentQuestion];
|
|
298
421
|
const options = q.options ?? [];
|
|
299
422
|
const isMultiSelect = q.multiSelect === true;
|
|
300
423
|
const allowCustom = q.allowCustom !== false;
|
|
301
424
|
// Reset state first
|
|
302
|
-
state.selectedIndex = 0;
|
|
303
|
-
state.inputBuffer = '';
|
|
304
|
-
state.isTypingCustom = false;
|
|
305
|
-
state.multiSelections.clear();
|
|
306
|
-
if (!(q.id in state.answers)) {
|
|
425
|
+
this.state.selectedIndex = 0;
|
|
426
|
+
this.state.inputBuffer = '';
|
|
427
|
+
this.state.isTypingCustom = false;
|
|
428
|
+
this.state.multiSelections.clear();
|
|
429
|
+
if (!(q.id in this.state.answers)) {
|
|
307
430
|
// No existing answer - check if we should auto-type
|
|
308
|
-
// (no options, custom allowed, single-select)
|
|
309
431
|
if (options.length === 0 && allowCustom && !isMultiSelect) {
|
|
310
|
-
state.isTypingCustom = true;
|
|
432
|
+
this.state.isTypingCustom = true;
|
|
311
433
|
}
|
|
312
434
|
return;
|
|
313
435
|
}
|
|
314
|
-
const existingAnswer = state.answers[q.id];
|
|
436
|
+
const existingAnswer = this.state.answers[q.id];
|
|
315
437
|
if (isMultiSelect && Array.isArray(existingAnswer)) {
|
|
316
|
-
// Multi-select: restore all selected options
|
|
317
438
|
for (const answer of existingAnswer) {
|
|
318
439
|
const idx = options.indexOf(answer);
|
|
319
440
|
if (idx >= 0) {
|
|
320
|
-
state.multiSelections.add(idx);
|
|
441
|
+
this.state.multiSelections.add(idx);
|
|
321
442
|
}
|
|
322
443
|
else {
|
|
323
|
-
|
|
324
|
-
state.
|
|
325
|
-
state.inputBuffer = answer;
|
|
444
|
+
this.state.multiSelections.add(options.length);
|
|
445
|
+
this.state.inputBuffer = answer;
|
|
326
446
|
}
|
|
327
447
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
state.selectedIndex = Math.min(...state.multiSelections);
|
|
448
|
+
if (this.state.multiSelections.size > 0) {
|
|
449
|
+
this.state.selectedIndex = Math.min(...this.state.multiSelections);
|
|
331
450
|
}
|
|
332
451
|
}
|
|
333
452
|
else if (typeof existingAnswer === 'string') {
|
|
334
|
-
// Single select: find which option was selected
|
|
335
453
|
const idx = options.indexOf(existingAnswer);
|
|
336
454
|
if (idx >= 0) {
|
|
337
|
-
state.selectedIndex = idx;
|
|
455
|
+
this.state.selectedIndex = idx;
|
|
338
456
|
}
|
|
339
457
|
else {
|
|
340
|
-
|
|
341
|
-
state.
|
|
342
|
-
state.inputBuffer = existingAnswer;
|
|
343
|
-
// Don't enter typing mode - just show the value
|
|
458
|
+
this.state.selectedIndex = options.length;
|
|
459
|
+
this.state.inputBuffer = existingAnswer;
|
|
344
460
|
}
|
|
345
461
|
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (state.isOnSubmitTab) {
|
|
350
|
-
// Already on Submit tab, do nothing
|
|
462
|
+
}
|
|
463
|
+
nextQuestion() {
|
|
464
|
+
if (this.state.isOnSubmitTab) {
|
|
351
465
|
return;
|
|
352
466
|
}
|
|
353
|
-
if (state.currentQuestion < questions.length - 1) {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
state.currentQuestion++;
|
|
357
|
-
restoreFromAnswer();
|
|
467
|
+
if (this.state.currentQuestion < this.questions.length - 1) {
|
|
468
|
+
this.state.currentQuestion++;
|
|
469
|
+
this.restoreFromAnswer();
|
|
358
470
|
}
|
|
359
471
|
else {
|
|
360
472
|
// On last question - move to Submit tab
|
|
361
|
-
|
|
362
|
-
state.
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const prevQuestion = () => {
|
|
371
|
-
if (state.isOnSubmitTab) {
|
|
372
|
-
// Move from Submit tab back to last question
|
|
373
|
-
debugLog(`prevQuestion: leaving Submit tab to question ${String(questions.length - 1)}`);
|
|
374
|
-
state.isOnSubmitTab = false;
|
|
375
|
-
restoreFromAnswer();
|
|
473
|
+
this.state.isOnSubmitTab = true;
|
|
474
|
+
this.state.isTypingCustom = false;
|
|
475
|
+
this.state.inputBuffer = '';
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
prevQuestion() {
|
|
479
|
+
if (this.state.isOnSubmitTab) {
|
|
480
|
+
this.state.isOnSubmitTab = false;
|
|
481
|
+
this.restoreFromAnswer();
|
|
376
482
|
return;
|
|
377
483
|
}
|
|
378
|
-
if (state.currentQuestion > 0) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const getUnansweredIndices = () => {
|
|
386
|
-
const unanswered = [];
|
|
387
|
-
for (let i = 0; i < questions.length; i++) {
|
|
388
|
-
if (!(questions[i].id in state.answers)) {
|
|
389
|
-
unanswered.push(i);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return unanswered;
|
|
393
|
-
};
|
|
394
|
-
// Helper: Check if all questions are answered and either complete or navigate to first unanswered
|
|
395
|
-
// Returns true if all complete and we should resolve, false if navigated to unanswered
|
|
396
|
-
const tryComplete = () => {
|
|
397
|
-
const unanswered = getUnansweredIndices();
|
|
484
|
+
if (this.state.currentQuestion > 0) {
|
|
485
|
+
this.state.currentQuestion--;
|
|
486
|
+
this.restoreFromAnswer();
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
tryComplete() {
|
|
490
|
+
const unanswered = this.questions.filter((q) => !(q.id in this.state.answers));
|
|
398
491
|
if (unanswered.length === 0) {
|
|
399
|
-
|
|
400
|
-
state.warningMessage = '';
|
|
492
|
+
this.state.warningMessage = '';
|
|
401
493
|
return true;
|
|
402
494
|
}
|
|
403
495
|
// Navigate to first unanswered question and show warning
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
state.
|
|
407
|
-
state.
|
|
408
|
-
restoreFromAnswer();
|
|
496
|
+
const firstUnansweredIndex = this.questions.findIndex((q) => !(q.id in this.state.answers));
|
|
497
|
+
this.state.warningMessage = `${String(unanswered.length)} question${unanswered.length > 1 ? 's' : ''} unanswered. Please answer all questions.`;
|
|
498
|
+
this.state.currentQuestion = firstUnansweredIndex;
|
|
499
|
+
this.state.isOnSubmitTab = false;
|
|
500
|
+
this.restoreFromAnswer();
|
|
409
501
|
return false;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
const q = questions[state.currentQuestion];
|
|
502
|
+
}
|
|
503
|
+
submitAnswer() {
|
|
504
|
+
const q = this.questions[this.state.currentQuestion];
|
|
414
505
|
const options = q.options ?? [];
|
|
415
506
|
const allowCustom = q.allowCustom !== false;
|
|
416
507
|
const isMultiSelect = q.multiSelect === true;
|
|
417
508
|
const customIndex = options.length;
|
|
418
509
|
if (isMultiSelect) {
|
|
419
|
-
// Multi-select: gather selected options
|
|
420
510
|
const selectedAnswers = [];
|
|
421
|
-
for (const idx of state.multiSelections) {
|
|
511
|
+
for (const idx of this.state.multiSelections) {
|
|
422
512
|
if (idx < options.length) {
|
|
423
513
|
selectedAnswers.push(options[idx]);
|
|
424
514
|
}
|
|
425
515
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
selectedAnswers.push(state.inputBuffer.trim());
|
|
516
|
+
if (this.state.multiSelections.has(customIndex) && this.state.inputBuffer.trim()) {
|
|
517
|
+
selectedAnswers.push(this.state.inputBuffer.trim());
|
|
429
518
|
}
|
|
430
519
|
if (selectedAnswers.length > 0) {
|
|
431
|
-
state.answers[q.id] = selectedAnswers;
|
|
520
|
+
this.state.answers[q.id] = selectedAnswers;
|
|
432
521
|
return true;
|
|
433
522
|
}
|
|
434
|
-
return false;
|
|
523
|
+
return false;
|
|
435
524
|
}
|
|
436
525
|
else {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
const custom = state.inputBuffer.trim();
|
|
526
|
+
if (this.state.isTypingCustom) {
|
|
527
|
+
const custom = this.state.inputBuffer.trim();
|
|
440
528
|
if (custom) {
|
|
441
|
-
state.answers[q.id] = custom;
|
|
529
|
+
this.state.answers[q.id] = custom;
|
|
442
530
|
return true;
|
|
443
531
|
}
|
|
444
|
-
return false;
|
|
532
|
+
return false;
|
|
445
533
|
}
|
|
446
|
-
else if (state.selectedIndex < options.length) {
|
|
447
|
-
state.answers[q.id] = options[state.selectedIndex];
|
|
534
|
+
else if (this.state.selectedIndex < options.length) {
|
|
535
|
+
this.state.answers[q.id] = options[this.state.selectedIndex];
|
|
448
536
|
return true;
|
|
449
537
|
}
|
|
450
|
-
else if (allowCustom && state.selectedIndex === customIndex) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
return false; // Don't advance yet
|
|
538
|
+
else if (allowCustom && this.state.selectedIndex === customIndex) {
|
|
539
|
+
this.state.isTypingCustom = true;
|
|
540
|
+
return false;
|
|
454
541
|
}
|
|
455
542
|
}
|
|
456
543
|
return false;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
process.stdin.removeListener('data', handleData);
|
|
469
|
-
// NOTE: Footer resume is handled by the caller (index.ts) in the finally block
|
|
470
|
-
};
|
|
471
|
-
const handleData = (data) => {
|
|
472
|
-
onData(data);
|
|
473
|
-
};
|
|
474
|
-
const onData = (data) => {
|
|
475
|
-
const isEscape = data.length === 1 && data[0] === 0x1b;
|
|
476
|
-
const isUpArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41;
|
|
477
|
-
const isDownArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42;
|
|
478
|
-
const isLeftArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x44;
|
|
479
|
-
const isRightArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x43;
|
|
480
|
-
const isCtrlC = data.length === 1 && data[0] === 0x03;
|
|
481
|
-
const isEnter = data.length === 1 && (data[0] === 0x0d || data[0] === 0x0a);
|
|
482
|
-
const isBackspace = data.length === 1 && (data[0] === 0x7f || data[0] === 0x08);
|
|
483
|
-
const isTab = data.length === 1 && data[0] === 0x09;
|
|
484
|
-
const isSpace = data.length === 1 && data[0] === 0x20;
|
|
485
|
-
// Helper to get skipped questions
|
|
486
|
-
const getSkipped = () => questions.filter((q) => !(q.id in state.answers)).map((q) => q.id);
|
|
487
|
-
// Ctrl+C always cancels
|
|
488
|
-
if (isCtrlC) {
|
|
489
|
-
cleanup();
|
|
490
|
-
state.cancelled = true;
|
|
491
|
-
resolve({
|
|
492
|
-
answers: state.answers,
|
|
493
|
-
skipped: getSkipped(),
|
|
494
|
-
});
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
// Submit tab takes priority over typing mode
|
|
498
|
-
// (This is a safeguard - nextQuestion() should already clear isTypingCustom)
|
|
499
|
-
if (state.isOnSubmitTab) {
|
|
500
|
-
// On Submit tab - handle special navigation
|
|
501
|
-
if (isEscape) {
|
|
502
|
-
// Cancel overlay
|
|
503
|
-
cleanup();
|
|
504
|
-
resolve({
|
|
505
|
-
answers: state.answers,
|
|
506
|
-
skipped: getSkipped(),
|
|
507
|
-
});
|
|
508
|
-
return;
|
|
509
|
-
}
|
|
510
|
-
else if (isLeftArrow || isTab) {
|
|
511
|
-
// Go back to last question
|
|
512
|
-
prevQuestion();
|
|
513
|
-
}
|
|
514
|
-
else if (isEnter) {
|
|
515
|
-
// Try to submit - check completeness
|
|
516
|
-
if (tryComplete()) {
|
|
517
|
-
cleanup();
|
|
518
|
-
resolve({
|
|
519
|
-
answers: state.answers,
|
|
520
|
-
skipped: getSkipped(),
|
|
521
|
-
});
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
// tryComplete sets warning and navigates to first unanswered
|
|
525
|
-
}
|
|
526
|
-
// Re-render and return early
|
|
527
|
-
lineCount = render(questions, state, context, maxLineCount, maxLineCount);
|
|
528
|
-
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
// If typing custom input
|
|
532
|
-
if (state.isTypingCustom) {
|
|
533
|
-
const currentQ = questions[state.currentQuestion];
|
|
534
|
-
const options = currentQ.options ?? [];
|
|
535
|
-
if (isEscape) {
|
|
536
|
-
// Cancel custom input
|
|
537
|
-
state.isTypingCustom = false;
|
|
538
|
-
state.inputBuffer = '';
|
|
539
|
-
}
|
|
540
|
-
else if (isUpArrow && options.length > 0) {
|
|
541
|
-
// Exit typing mode and navigate up (only if there are other options)
|
|
542
|
-
state.isTypingCustom = false;
|
|
543
|
-
state.inputBuffer = '';
|
|
544
|
-
state.selectedIndex = Math.max(0, state.selectedIndex - 1);
|
|
545
|
-
}
|
|
546
|
-
else if (isDownArrow) {
|
|
547
|
-
// Custom is last option, so down arrow does nothing
|
|
548
|
-
// But we handle it to be consistent
|
|
549
|
-
}
|
|
550
|
-
else if (isEnter) {
|
|
551
|
-
// Submit custom input
|
|
552
|
-
if (submitAnswer()) {
|
|
553
|
-
// Clear warning on successful submit
|
|
554
|
-
state.warningMessage = '';
|
|
555
|
-
// Move to next question (or Submit tab if on last question)
|
|
556
|
-
nextQuestion();
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
else if (isBackspace) {
|
|
560
|
-
state.inputBuffer = state.inputBuffer.slice(0, -1);
|
|
561
|
-
}
|
|
562
|
-
else if (data.length === 1 && data[0] >= 0x20 && data[0] < 0x7f) {
|
|
563
|
-
// Printable character
|
|
564
|
-
state.inputBuffer += String.fromCharCode(data[0]);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
else {
|
|
568
|
-
// Navigation mode - on a question (Submit tab is handled earlier)
|
|
569
|
-
const optionCount = getOptionCount();
|
|
570
|
-
const currentQ = questions[state.currentQuestion];
|
|
571
|
-
const isMultiSelect = currentQ.multiSelect === true;
|
|
572
|
-
const options = currentQ.options ?? [];
|
|
573
|
-
const allowCustom = currentQ.allowCustom !== false;
|
|
574
|
-
const customIndex = options.length;
|
|
575
|
-
if (isEscape) {
|
|
576
|
-
// Cancel overlay
|
|
577
|
-
cleanup();
|
|
578
|
-
resolve({
|
|
579
|
-
answers: state.answers,
|
|
580
|
-
skipped: getSkipped(),
|
|
581
|
-
});
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
else if (isUpArrow) {
|
|
585
|
-
state.selectedIndex = Math.max(0, state.selectedIndex - 1);
|
|
586
|
-
// Auto-enable typing when navigating to custom option (single-select only)
|
|
587
|
-
if (!isMultiSelect && allowCustom && state.selectedIndex === customIndex) {
|
|
588
|
-
state.isTypingCustom = true;
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
else if (isDownArrow) {
|
|
592
|
-
state.selectedIndex = Math.min(optionCount - 1, state.selectedIndex + 1);
|
|
593
|
-
// Auto-enable typing when navigating to custom option (single-select only)
|
|
594
|
-
if (!isMultiSelect && allowCustom && state.selectedIndex === customIndex) {
|
|
595
|
-
state.isTypingCustom = true;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
else if (isLeftArrow) {
|
|
599
|
-
prevQuestion();
|
|
600
|
-
}
|
|
601
|
-
else if (isRightArrow || isTab) {
|
|
602
|
-
// Tab or right arrow: move to next question (or Submit tab)
|
|
603
|
-
nextQuestion();
|
|
604
|
-
}
|
|
605
|
-
else if (isSpace && isMultiSelect) {
|
|
606
|
-
// Toggle multi-select
|
|
607
|
-
if (state.multiSelections.has(state.selectedIndex)) {
|
|
608
|
-
state.multiSelections.delete(state.selectedIndex);
|
|
609
|
-
}
|
|
610
|
-
else {
|
|
611
|
-
state.multiSelections.add(state.selectedIndex);
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
else if (isEnter) {
|
|
615
|
-
const submitted = submitAnswer();
|
|
616
|
-
if (submitted) {
|
|
617
|
-
// Clear warning on successful submit
|
|
618
|
-
state.warningMessage = '';
|
|
619
|
-
// Move to next question (or Submit tab)
|
|
620
|
-
nextQuestion();
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
else if (data.length === 1 && data[0] >= 0x31 && data[0] <= 0x39) {
|
|
624
|
-
// Number keys 1-9
|
|
625
|
-
const numIndex = data[0] - 0x31; // 0-indexed
|
|
626
|
-
if (numIndex < optionCount) {
|
|
627
|
-
state.selectedIndex = numIndex;
|
|
628
|
-
if (!isMultiSelect) {
|
|
629
|
-
// Auto-select for single select
|
|
630
|
-
const submitted = submitAnswer();
|
|
631
|
-
if (submitted) {
|
|
632
|
-
// Clear warning on successful submit
|
|
633
|
-
state.warningMessage = '';
|
|
634
|
-
// Move to next question (or Submit tab)
|
|
635
|
-
nextQuestion();
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
// Re-render - use maxLineCount for both clearing AND target height to prevent cursor drift
|
|
642
|
-
lineCount = render(questions, state, context, maxLineCount, maxLineCount);
|
|
643
|
-
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
644
|
-
};
|
|
645
|
-
process.stdin.on('data', handleData);
|
|
646
|
-
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
// =============================================================================
|
|
547
|
+
// Main Export
|
|
548
|
+
// =============================================================================
|
|
549
|
+
/**
|
|
550
|
+
* Show the ask user overlay
|
|
551
|
+
*/
|
|
552
|
+
export async function showAskUserOverlay(options) {
|
|
553
|
+
const overlay = new AskUserOverlayImpl(options);
|
|
554
|
+
return overlay.show();
|
|
647
555
|
}
|