mepcli 0.6.1 → 1.0.0-beta.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/LICENSE +21 -21
- package/README.md +512 -326
- package/dist/ansi.d.ts +8 -0
- package/dist/ansi.js +8 -0
- package/dist/base.d.ts +21 -0
- package/dist/base.js +57 -0
- package/dist/core.d.ts +48 -1
- package/dist/core.js +156 -0
- package/dist/data/licenses.d.ts +2 -0
- package/dist/data/licenses.js +109 -0
- package/dist/highlight.js +58 -26
- package/dist/index.d.ts +36 -0
- package/dist/index.js +36 -0
- package/dist/input.js +0 -3
- package/dist/prompts/box.d.ts +21 -0
- package/dist/prompts/box.js +192 -0
- package/dist/prompts/breadcrumb.d.ts +22 -0
- package/dist/prompts/breadcrumb.js +302 -0
- package/dist/prompts/byte.d.ts +13 -0
- package/dist/prompts/byte.js +159 -0
- package/dist/prompts/calculator.d.ts +16 -0
- package/dist/prompts/calculator.js +213 -0
- package/dist/prompts/calendar.js +0 -5
- package/dist/prompts/code.d.ts +2 -0
- package/dist/prompts/code.js +104 -70
- package/dist/prompts/connection-string.d.ts +18 -0
- package/dist/prompts/connection-string.js +97 -0
- package/dist/prompts/curl.d.ts +39 -0
- package/dist/prompts/curl.js +285 -0
- package/dist/prompts/data-inspector.d.ts +22 -0
- package/dist/prompts/data-inspector.js +256 -0
- package/dist/prompts/dependency.d.ts +16 -0
- package/dist/prompts/dependency.js +265 -0
- package/dist/prompts/dial.d.ts +10 -0
- package/dist/prompts/dial.js +110 -0
- package/dist/prompts/diff.d.ts +10 -0
- package/dist/prompts/diff.js +101 -0
- package/dist/prompts/draw.d.ts +20 -0
- package/dist/prompts/draw.js +188 -0
- package/dist/prompts/editor.js +0 -4
- package/dist/prompts/emoji.d.ts +18 -0
- package/dist/prompts/emoji.js +228 -0
- package/dist/prompts/exec.d.ts +13 -0
- package/dist/prompts/exec.js +83 -0
- package/dist/prompts/fuzzy.d.ts +12 -0
- package/dist/prompts/fuzzy.js +136 -0
- package/dist/prompts/gauge.d.ts +21 -0
- package/dist/prompts/gauge.js +130 -0
- package/dist/prompts/heatmap.d.ts +13 -0
- package/dist/prompts/heatmap.js +141 -0
- package/dist/prompts/ip.d.ts +11 -0
- package/dist/prompts/ip.js +118 -0
- package/dist/prompts/kanban.d.ts +17 -0
- package/dist/prompts/kanban.js +228 -0
- package/dist/prompts/keypress.js +0 -2
- package/dist/prompts/license.d.ts +9 -0
- package/dist/prompts/license.js +105 -0
- package/dist/prompts/map.d.ts +15 -0
- package/dist/prompts/map.js +199 -0
- package/dist/prompts/match.d.ts +19 -0
- package/dist/prompts/match.js +275 -0
- package/dist/prompts/miller.d.ts +15 -0
- package/dist/prompts/miller.js +221 -0
- package/dist/prompts/multi-column-select.d.ts +10 -0
- package/dist/prompts/multi-column-select.js +166 -0
- package/dist/prompts/number.js +0 -2
- package/dist/prompts/otp.d.ts +10 -0
- package/dist/prompts/otp.js +91 -0
- package/dist/prompts/pattern.d.ts +22 -0
- package/dist/prompts/pattern.js +249 -0
- package/dist/prompts/quiz-select.d.ts +10 -0
- package/dist/prompts/quiz-select.js +104 -0
- package/dist/prompts/quiz-text.d.ts +11 -0
- package/dist/prompts/quiz-text.js +82 -0
- package/dist/prompts/regex.d.ts +13 -0
- package/dist/prompts/regex.js +131 -0
- package/dist/prompts/region.d.ts +11 -0
- package/dist/prompts/region.js +164 -0
- package/dist/prompts/schedule.d.ts +18 -0
- package/dist/prompts/schedule.js +221 -0
- package/dist/prompts/scroll.d.ts +13 -0
- package/dist/prompts/scroll.js +152 -0
- package/dist/prompts/seat.d.ts +17 -0
- package/dist/prompts/seat.js +165 -0
- package/dist/prompts/select-range.d.ts +8 -0
- package/dist/prompts/select-range.js +136 -0
- package/dist/prompts/select.d.ts +9 -9
- package/dist/prompts/semver.d.ts +6 -0
- package/dist/prompts/semver.js +32 -0
- package/dist/prompts/shortcut.d.ts +9 -0
- package/dist/prompts/shortcut.js +135 -0
- package/dist/prompts/slot.d.ts +16 -0
- package/dist/prompts/slot.js +107 -0
- package/dist/prompts/snippet.js +0 -3
- package/dist/prompts/sort-grid.d.ts +16 -0
- package/dist/prompts/sort-grid.js +146 -0
- package/dist/prompts/sort.js +0 -1
- package/dist/prompts/spreadsheet.d.ts +21 -0
- package/dist/prompts/spreadsheet.js +239 -0
- package/dist/prompts/text.d.ts +9 -7
- package/dist/prompts/text.js +52 -0
- package/dist/prompts/time.d.ts +12 -0
- package/dist/prompts/time.js +202 -0
- package/dist/prompts/tree-select.d.ts +0 -1
- package/dist/prompts/tree-select.js +1 -5
- package/dist/symbols.d.ts +12 -0
- package/dist/symbols.js +14 -2
- package/dist/theme.js +10 -1
- package/dist/types.d.ts +264 -1
- package/dist/utils.d.ts +53 -0
- package/dist/utils.js +252 -0
- package/package.json +51 -47
- package/example.ts +0 -390
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DataInspectorPrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
8
|
+
const symbols_1 = require("../symbols");
|
|
9
|
+
class DataInspectorPrompt extends base_1.Prompt {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super(options);
|
|
12
|
+
this.cursor = 0;
|
|
13
|
+
this.flatList = [];
|
|
14
|
+
this.expandedPaths = new Set();
|
|
15
|
+
this.scrollTop = 0;
|
|
16
|
+
this.pageSize = 15;
|
|
17
|
+
// Edit Mode State
|
|
18
|
+
this.editMode = false;
|
|
19
|
+
this.editBuffer = '';
|
|
20
|
+
this.rootData = options.data; // We mutate this directly
|
|
21
|
+
this.expandedPaths.add('root'); // Always expand root if it's an object
|
|
22
|
+
this.recalculateFlatList();
|
|
23
|
+
}
|
|
24
|
+
getType(value) {
|
|
25
|
+
if (value === null)
|
|
26
|
+
return 'null';
|
|
27
|
+
if (value === undefined)
|
|
28
|
+
return 'undefined';
|
|
29
|
+
if (Array.isArray(value))
|
|
30
|
+
return 'array';
|
|
31
|
+
if (value instanceof Date)
|
|
32
|
+
return 'date';
|
|
33
|
+
return typeof value;
|
|
34
|
+
}
|
|
35
|
+
recalculateFlatList() {
|
|
36
|
+
this.flatList = [];
|
|
37
|
+
this.traverse(this.rootData, 'root', 0, null, 'root');
|
|
38
|
+
}
|
|
39
|
+
traverse(data, key, depth, parentRef, currentPath) {
|
|
40
|
+
const type = this.getType(data);
|
|
41
|
+
const isLeaf = !['object', 'array'].includes(type) || data === null;
|
|
42
|
+
const node = {
|
|
43
|
+
key: String(key),
|
|
44
|
+
value: data,
|
|
45
|
+
type,
|
|
46
|
+
depth,
|
|
47
|
+
path: currentPath,
|
|
48
|
+
parentRef,
|
|
49
|
+
refKey: key,
|
|
50
|
+
isLeaf
|
|
51
|
+
};
|
|
52
|
+
this.flatList.push(node);
|
|
53
|
+
if (!isLeaf && this.expandedPaths.has(currentPath)) {
|
|
54
|
+
const keys = Object.keys(data);
|
|
55
|
+
keys.forEach(k => {
|
|
56
|
+
this.traverse(data[k], k, depth + 1, data, `${currentPath}.${k}`);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
getValueColor(type) {
|
|
61
|
+
switch (type) {
|
|
62
|
+
case 'string': return ansi_1.ANSI.FG_GREEN;
|
|
63
|
+
case 'number': return ansi_1.ANSI.FG_YELLOW;
|
|
64
|
+
case 'boolean': return ansi_1.ANSI.FG_MAGENTA;
|
|
65
|
+
case 'null':
|
|
66
|
+
case 'undefined': return ansi_1.ANSI.FG_GRAY;
|
|
67
|
+
case 'date': return ansi_1.ANSI.FG_BLUE;
|
|
68
|
+
default: return ansi_1.ANSI.RESET;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
formatValue(value, type) {
|
|
72
|
+
if (type === 'string')
|
|
73
|
+
return `"${value}"`;
|
|
74
|
+
if (type === 'date')
|
|
75
|
+
return value.toISOString();
|
|
76
|
+
if (type === 'array')
|
|
77
|
+
return `Array(${value.length})`;
|
|
78
|
+
if (type === 'object')
|
|
79
|
+
return `Object{${Object.keys(value).length}}`;
|
|
80
|
+
return String(value);
|
|
81
|
+
}
|
|
82
|
+
render(_firstRender) {
|
|
83
|
+
let output = `${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
|
|
84
|
+
if (this.cursor < this.scrollTop) {
|
|
85
|
+
this.scrollTop = this.cursor;
|
|
86
|
+
}
|
|
87
|
+
else if (this.cursor >= this.scrollTop + this.pageSize) {
|
|
88
|
+
this.scrollTop = this.cursor - this.pageSize + 1;
|
|
89
|
+
}
|
|
90
|
+
const visible = this.flatList.slice(this.scrollTop, this.scrollTop + this.pageSize);
|
|
91
|
+
visible.forEach((node, index) => {
|
|
92
|
+
const actualIndex = this.scrollTop + index;
|
|
93
|
+
const isSelected = actualIndex === this.cursor;
|
|
94
|
+
// Indentation & Tree Lines
|
|
95
|
+
const indent = ' '.repeat(node.depth);
|
|
96
|
+
const prefix = isSelected ? `${theme_1.theme.main}${symbols_1.symbols.pointer} ` : ' ';
|
|
97
|
+
// Icon
|
|
98
|
+
let icon = '';
|
|
99
|
+
if (!node.isLeaf) {
|
|
100
|
+
icon = this.expandedPaths.has(node.path) ? '▾ ' : '▸ ';
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
icon = '• '; // Leaf
|
|
104
|
+
}
|
|
105
|
+
// Key
|
|
106
|
+
let keyStr = node.key;
|
|
107
|
+
if (node.path === 'root')
|
|
108
|
+
keyStr = 'ROOT';
|
|
109
|
+
// Value Representation
|
|
110
|
+
let valueStr = '';
|
|
111
|
+
if (isSelected && this.editMode) {
|
|
112
|
+
// Editing View
|
|
113
|
+
valueStr = `${ansi_1.ANSI.BG_BLUE}${ansi_1.ANSI.FG_WHITE} ${this.editBuffer}_ ${ansi_1.ANSI.RESET}`;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// Normal View
|
|
117
|
+
const color = this.getValueColor(node.type);
|
|
118
|
+
const formatted = this.formatValue(node.value, node.type);
|
|
119
|
+
valueStr = `${color}${formatted}${ansi_1.ANSI.RESET}`;
|
|
120
|
+
}
|
|
121
|
+
// Type Label (Right aligned or just dimmed next to key)
|
|
122
|
+
const typeLabel = `${ansi_1.ANSI.FG_GRAY}(${node.type})${ansi_1.ANSI.RESET}`;
|
|
123
|
+
let line = `${indent}${icon}${ansi_1.ANSI.BOLD}${keyStr}${ansi_1.ANSI.RESET}: ${valueStr} ${typeLabel}`;
|
|
124
|
+
if (isSelected && !this.editMode) {
|
|
125
|
+
line = `${theme_1.theme.main}${(0, utils_1.stripAnsi)(line)}${ansi_1.ANSI.RESET}`; // Highlight whole line
|
|
126
|
+
}
|
|
127
|
+
else if (isSelected && this.editMode) {
|
|
128
|
+
// In edit mode, we don't highlight the whole line, just the input box
|
|
129
|
+
line = `${indent}${icon}${ansi_1.ANSI.BOLD}${keyStr}${ansi_1.ANSI.RESET}: ${valueStr} ${typeLabel}`;
|
|
130
|
+
}
|
|
131
|
+
output += `${prefix}${line}\n`;
|
|
132
|
+
});
|
|
133
|
+
// Footer
|
|
134
|
+
if (this.editMode) {
|
|
135
|
+
output += `\n${theme_1.theme.main}EDIT MODE${ansi_1.ANSI.RESET} Enter: Save, Esc: Cancel`;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
output += `\n${theme_1.theme.muted}(Arrows: Nav, Space: Toggle, Enter: Edit/Submit)${ansi_1.ANSI.RESET}`;
|
|
139
|
+
}
|
|
140
|
+
this.renderFrame(output);
|
|
141
|
+
}
|
|
142
|
+
handleInput(char, key) {
|
|
143
|
+
if (this.editMode) {
|
|
144
|
+
this.handleEditInput(char, key);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const node = this.flatList[this.cursor];
|
|
148
|
+
if (this.isUp(char)) {
|
|
149
|
+
this.cursor = (this.cursor - 1 + this.flatList.length) % this.flatList.length;
|
|
150
|
+
this.render(false);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (this.isDown(char)) {
|
|
154
|
+
this.cursor = (this.cursor + 1) % this.flatList.length;
|
|
155
|
+
this.render(false);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Expand/Collapse
|
|
159
|
+
if (char === ' ' || this.isRight(char) || this.isLeft(char)) {
|
|
160
|
+
if (!node.isLeaf) {
|
|
161
|
+
const isExpanded = this.expandedPaths.has(node.path);
|
|
162
|
+
if (this.isRight(char) && !isExpanded) {
|
|
163
|
+
this.expandedPaths.add(node.path);
|
|
164
|
+
}
|
|
165
|
+
else if (this.isLeft(char) && isExpanded) {
|
|
166
|
+
this.expandedPaths.delete(node.path);
|
|
167
|
+
}
|
|
168
|
+
else if (char === ' ') {
|
|
169
|
+
if (isExpanded)
|
|
170
|
+
this.expandedPaths.delete(node.path);
|
|
171
|
+
else
|
|
172
|
+
this.expandedPaths.add(node.path);
|
|
173
|
+
}
|
|
174
|
+
else if (this.isLeft(char) && !isExpanded && node.parentRef) {
|
|
175
|
+
// Jump to parent
|
|
176
|
+
// This requires finding parent index, but simplification: just do nothing or standard logic
|
|
177
|
+
}
|
|
178
|
+
this.recalculateFlatList();
|
|
179
|
+
this.render(false);
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Enter: Edit or Submit
|
|
184
|
+
if (char === '\r' || char === '\n') {
|
|
185
|
+
if (node.path === 'root') {
|
|
186
|
+
this.submit(this.rootData);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// Toggle Boolean immediately
|
|
190
|
+
if (node.type === 'boolean') {
|
|
191
|
+
const newVal = !node.value;
|
|
192
|
+
node.parentRef[node.refKey] = newVal;
|
|
193
|
+
this.recalculateFlatList(); // Value changed
|
|
194
|
+
this.render(false);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
// Enter Edit Mode for String/Number
|
|
198
|
+
if (['string', 'number'].includes(node.type)) {
|
|
199
|
+
this.editMode = true;
|
|
200
|
+
this.editBuffer = String(node.value);
|
|
201
|
+
this.render(false);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
this.submit(this.rootData);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
handleEditInput(char, key) {
|
|
208
|
+
const node = this.flatList[this.cursor];
|
|
209
|
+
// Enter: Save
|
|
210
|
+
if (char === '\r' || char === '\n') {
|
|
211
|
+
let newValue = this.editBuffer;
|
|
212
|
+
if (node.type === 'number') {
|
|
213
|
+
newValue = Number(this.editBuffer);
|
|
214
|
+
if (isNaN(newValue))
|
|
215
|
+
newValue = 0; // Fallback
|
|
216
|
+
}
|
|
217
|
+
// Update Data
|
|
218
|
+
node.parentRef[node.refKey] = newValue;
|
|
219
|
+
this.editMode = false;
|
|
220
|
+
this.recalculateFlatList();
|
|
221
|
+
this.render(false);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// Esc: Cancel
|
|
225
|
+
if (key[0] === 27 && key.length === 1) { // Standard ESC
|
|
226
|
+
this.editMode = false;
|
|
227
|
+
this.render(false);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
// Backspace
|
|
231
|
+
if (key.toString() === '\x7f' || char === '\b') {
|
|
232
|
+
this.editBuffer = this.editBuffer.slice(0, -1);
|
|
233
|
+
this.render(false);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// Typing
|
|
237
|
+
if (char && char.length === 1 && char.charCodeAt(0) >= 32) {
|
|
238
|
+
this.editBuffer += char;
|
|
239
|
+
this.render(false);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
handleMouse(event) {
|
|
243
|
+
if (this.editMode)
|
|
244
|
+
return; // Disable scroll in edit mode for now
|
|
245
|
+
if (event.action === 'scroll') {
|
|
246
|
+
if (event.scroll === 'up') {
|
|
247
|
+
this.cursor = (this.cursor - 1 + this.flatList.length) % this.flatList.length;
|
|
248
|
+
}
|
|
249
|
+
else if (event.scroll === 'down') {
|
|
250
|
+
this.cursor = (this.cursor + 1) % this.flatList.length;
|
|
251
|
+
}
|
|
252
|
+
this.render(false);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
exports.DataInspectorPrompt = DataInspectorPrompt;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { DependencyOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class DependencyPrompt<V> extends Prompt<V[], DependencyOptions<V>> {
|
|
4
|
+
private selectedIndex;
|
|
5
|
+
private checkedState;
|
|
6
|
+
private errorMsg;
|
|
7
|
+
private warningMsg;
|
|
8
|
+
private scrollTop;
|
|
9
|
+
private readonly pageSize;
|
|
10
|
+
constructor(options: DependencyOptions<V>);
|
|
11
|
+
private resolveDependencies;
|
|
12
|
+
protected render(_firstRender: boolean): void;
|
|
13
|
+
protected handleMouse(event: MouseEvent): void;
|
|
14
|
+
protected handleInput(char: string): void;
|
|
15
|
+
private validateDependencies;
|
|
16
|
+
}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DependencyPrompt = void 0;
|
|
4
|
+
const ansi_1 = require("../ansi");
|
|
5
|
+
const base_1 = require("../base");
|
|
6
|
+
const theme_1 = require("../theme");
|
|
7
|
+
const symbols_1 = require("../symbols");
|
|
8
|
+
class DependencyPrompt extends base_1.Prompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.selectedIndex = 0;
|
|
12
|
+
this.errorMsg = '';
|
|
13
|
+
this.warningMsg = '';
|
|
14
|
+
// Pagination state
|
|
15
|
+
this.scrollTop = 0;
|
|
16
|
+
this.pageSize = 10;
|
|
17
|
+
// Initialize checked state from options (default selected)
|
|
18
|
+
// We also need to run initial validation/resolution
|
|
19
|
+
this.checkedState = options.choices.map(c => !!c.selected);
|
|
20
|
+
if (options.autoResolve !== false) {
|
|
21
|
+
// Run resolution for all initially selected items
|
|
22
|
+
this.checkedState.forEach((isChecked, i) => {
|
|
23
|
+
if (isChecked) {
|
|
24
|
+
this.resolveDependencies(i, true);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
resolveDependencies(index, value) {
|
|
30
|
+
// If autoResolve is false, we don't do anything automatically,
|
|
31
|
+
// validation will handle it on submit.
|
|
32
|
+
if (this.options.autoResolve === false)
|
|
33
|
+
return;
|
|
34
|
+
const choices = this.options.choices;
|
|
35
|
+
const visited = new Set();
|
|
36
|
+
const queue = [];
|
|
37
|
+
queue.push({ idx: index, val: value });
|
|
38
|
+
// Process queue
|
|
39
|
+
let loops = 0;
|
|
40
|
+
while (queue.length > 0 && loops < 1000) { // Safety break
|
|
41
|
+
loops++;
|
|
42
|
+
const current = queue.shift();
|
|
43
|
+
if (visited.has(current.idx))
|
|
44
|
+
continue;
|
|
45
|
+
// Apply state
|
|
46
|
+
// Only if it changes state
|
|
47
|
+
if (this.checkedState[current.idx] !== current.val) {
|
|
48
|
+
this.checkedState[current.idx] = current.val;
|
|
49
|
+
if (current.reason) {
|
|
50
|
+
this.warningMsg = current.reason;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
visited.add(current.idx);
|
|
54
|
+
const currentItem = choices[current.idx];
|
|
55
|
+
if (current.val) {
|
|
56
|
+
// Turning ON
|
|
57
|
+
// 1. Check Conflicts (Disable them)
|
|
58
|
+
if (currentItem.conflictsWith) {
|
|
59
|
+
currentItem.conflictsWith.forEach(conflictVal => {
|
|
60
|
+
const conflictIdx = choices.findIndex(c => c.value === conflictVal);
|
|
61
|
+
if (conflictIdx !== -1 && this.checkedState[conflictIdx]) {
|
|
62
|
+
queue.push({
|
|
63
|
+
idx: conflictIdx,
|
|
64
|
+
val: false,
|
|
65
|
+
reason: `Disabled ${choices[conflictIdx].title} due to conflict with ${currentItem.title}`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
// 2. Check Dependencies (Enable them)
|
|
71
|
+
if (currentItem.dependsOn) {
|
|
72
|
+
currentItem.dependsOn.forEach(depVal => {
|
|
73
|
+
const depIdx = choices.findIndex(c => c.value === depVal);
|
|
74
|
+
if (depIdx !== -1 && !this.checkedState[depIdx]) {
|
|
75
|
+
queue.push({
|
|
76
|
+
idx: depIdx,
|
|
77
|
+
val: true,
|
|
78
|
+
reason: `Enabled ${choices[depIdx].title} because ${currentItem.title} requires it`
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
// 3. Check Triggers (Enable them)
|
|
84
|
+
if (currentItem.triggers) {
|
|
85
|
+
currentItem.triggers.forEach(trigVal => {
|
|
86
|
+
const trigIdx = choices.findIndex(c => c.value === trigVal);
|
|
87
|
+
if (trigIdx !== -1 && !this.checkedState[trigIdx]) {
|
|
88
|
+
queue.push({
|
|
89
|
+
idx: trigIdx,
|
|
90
|
+
val: true,
|
|
91
|
+
reason: `Triggered ${choices[trigIdx].title} from ${currentItem.title}`
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// Turning OFF
|
|
99
|
+
// Check if other ON items depend on this one. If so, disable them.
|
|
100
|
+
choices.forEach((other, otherIdx) => {
|
|
101
|
+
if (this.checkedState[otherIdx] && other.dependsOn && other.dependsOn.includes(currentItem.value)) {
|
|
102
|
+
queue.push({
|
|
103
|
+
idx: otherIdx,
|
|
104
|
+
val: false,
|
|
105
|
+
reason: `Disabled ${other.title} because it depends on ${currentItem.title}`
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
render(_firstRender) {
|
|
113
|
+
// Adjust Scroll Top
|
|
114
|
+
if (this.selectedIndex < this.scrollTop) {
|
|
115
|
+
this.scrollTop = this.selectedIndex;
|
|
116
|
+
}
|
|
117
|
+
else if (this.selectedIndex >= this.scrollTop + this.pageSize) {
|
|
118
|
+
this.scrollTop = this.selectedIndex - this.pageSize + 1;
|
|
119
|
+
}
|
|
120
|
+
if (this.options.choices.length <= this.pageSize) {
|
|
121
|
+
this.scrollTop = 0;
|
|
122
|
+
}
|
|
123
|
+
let output = '';
|
|
124
|
+
// Header
|
|
125
|
+
const icon = this.errorMsg ? `${theme_1.theme.error}${symbols_1.symbols.cross}` : `${theme_1.theme.success}?`;
|
|
126
|
+
output += `${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${theme_1.theme.muted}(Space: toggle, Enter: submit)${ansi_1.ANSI.RESET}`;
|
|
127
|
+
// List
|
|
128
|
+
const choices = this.options.choices;
|
|
129
|
+
const visibleChoices = choices.slice(this.scrollTop, this.scrollTop + this.pageSize);
|
|
130
|
+
visibleChoices.forEach((choice, index) => {
|
|
131
|
+
const actualIndex = this.scrollTop + index;
|
|
132
|
+
output += '\n'; // New line for each item
|
|
133
|
+
const cursor = actualIndex === this.selectedIndex ? `${theme_1.theme.main}${symbols_1.symbols.pointer}${ansi_1.ANSI.RESET}` : ' ';
|
|
134
|
+
const isChecked = this.checkedState[actualIndex];
|
|
135
|
+
const checkbox = isChecked
|
|
136
|
+
? `${theme_1.theme.success}${symbols_1.symbols.checked}${ansi_1.ANSI.RESET}`
|
|
137
|
+
: `${theme_1.theme.muted}${symbols_1.symbols.unchecked}${ansi_1.ANSI.RESET}`;
|
|
138
|
+
let title = actualIndex === this.selectedIndex
|
|
139
|
+
? `${theme_1.theme.main}${choice.title}${ansi_1.ANSI.RESET}`
|
|
140
|
+
: choice.title;
|
|
141
|
+
// Add tags for relationships
|
|
142
|
+
if (choice.dependsOn && choice.dependsOn.length > 0) {
|
|
143
|
+
title += ` ${theme_1.theme.muted}[Req: ${choice.dependsOn.length}]${ansi_1.ANSI.RESET}`;
|
|
144
|
+
}
|
|
145
|
+
if (choice.conflictsWith && choice.conflictsWith.length > 0) {
|
|
146
|
+
title += ` ${theme_1.theme.error}[Con: ${choice.conflictsWith.length}]${ansi_1.ANSI.RESET}`;
|
|
147
|
+
}
|
|
148
|
+
output += `${cursor} ${checkbox} ${title}`;
|
|
149
|
+
});
|
|
150
|
+
if (this.errorMsg) {
|
|
151
|
+
output += `\n${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`;
|
|
152
|
+
}
|
|
153
|
+
else if (this.warningMsg) {
|
|
154
|
+
output += `\n${theme_1.theme.main}>> ${this.warningMsg}${ansi_1.ANSI.RESET}`;
|
|
155
|
+
}
|
|
156
|
+
this.renderFrame(output);
|
|
157
|
+
}
|
|
158
|
+
handleMouse(event) {
|
|
159
|
+
if (event.action === 'scroll') {
|
|
160
|
+
if (event.scroll === 'up') {
|
|
161
|
+
this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.options.choices.length - 1;
|
|
162
|
+
this.render(false);
|
|
163
|
+
}
|
|
164
|
+
else if (event.scroll === 'down') {
|
|
165
|
+
this.selectedIndex = this.selectedIndex < this.options.choices.length - 1 ? this.selectedIndex + 1 : 0;
|
|
166
|
+
this.render(false);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
handleInput(char) {
|
|
171
|
+
if (char === '\r' || char === '\n') {
|
|
172
|
+
// Final Validation
|
|
173
|
+
const selectedCount = this.checkedState.filter(Boolean).length;
|
|
174
|
+
const { min = 0, max } = this.options;
|
|
175
|
+
if (selectedCount < min) {
|
|
176
|
+
this.errorMsg = `You must select at least ${min} options.`;
|
|
177
|
+
this.render(false);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (max && selectedCount > max) {
|
|
181
|
+
this.errorMsg = `You can only select up to ${max} options.`;
|
|
182
|
+
this.render(false);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
// Dependency Logic Check (if autoResolve was off, or double check)
|
|
186
|
+
// Even if autoResolve is on, we check for cycles or invalid states that might have slipped?
|
|
187
|
+
// Or just check if manual toggle left things broken (if autoResolve is OFF).
|
|
188
|
+
if (this.options.autoResolve === false) {
|
|
189
|
+
const invalid = this.validateDependencies();
|
|
190
|
+
if (invalid) {
|
|
191
|
+
this.errorMsg = invalid;
|
|
192
|
+
this.render(false);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
this.cleanup();
|
|
197
|
+
const results = this.options.choices
|
|
198
|
+
.filter((_, i) => this.checkedState[i])
|
|
199
|
+
.map(c => c.value);
|
|
200
|
+
this.submit(results);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
// Space Toggle
|
|
204
|
+
if (char === ' ') {
|
|
205
|
+
const currentChecked = this.checkedState[this.selectedIndex];
|
|
206
|
+
// Toggle
|
|
207
|
+
const newState = !currentChecked;
|
|
208
|
+
// Check Max limit before enabling
|
|
209
|
+
if (newState) {
|
|
210
|
+
const selectedCount = this.checkedState.filter(Boolean).length;
|
|
211
|
+
const { max } = this.options;
|
|
212
|
+
if (max && selectedCount >= max) {
|
|
213
|
+
this.errorMsg = `Max ${max} selections allowed.`;
|
|
214
|
+
this.render(false);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
this.errorMsg = '';
|
|
219
|
+
this.warningMsg = '';
|
|
220
|
+
if (this.options.autoResolve !== false) {
|
|
221
|
+
this.resolveDependencies(this.selectedIndex, newState);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
this.checkedState[this.selectedIndex] = newState;
|
|
225
|
+
}
|
|
226
|
+
this.render(false);
|
|
227
|
+
}
|
|
228
|
+
if (this.isUp(char)) { // Up
|
|
229
|
+
this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.options.choices.length - 1;
|
|
230
|
+
this.render(false);
|
|
231
|
+
}
|
|
232
|
+
if (this.isDown(char)) { // Down
|
|
233
|
+
this.selectedIndex = this.selectedIndex < this.options.choices.length - 1 ? this.selectedIndex + 1 : 0;
|
|
234
|
+
this.render(false);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
validateDependencies() {
|
|
238
|
+
const choices = this.options.choices;
|
|
239
|
+
for (let i = 0; i < choices.length; i++) {
|
|
240
|
+
if (!this.checkedState[i])
|
|
241
|
+
continue;
|
|
242
|
+
const item = choices[i];
|
|
243
|
+
// Check dependencies
|
|
244
|
+
if (item.dependsOn) {
|
|
245
|
+
for (const depVal of item.dependsOn) {
|
|
246
|
+
const depIdx = choices.findIndex(c => c.value === depVal);
|
|
247
|
+
if (depIdx === -1 || !this.checkedState[depIdx]) {
|
|
248
|
+
return `${item.title} requires ${depVal}`; // Should look up title for depVal ideally
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Check conflicts
|
|
253
|
+
if (item.conflictsWith) {
|
|
254
|
+
for (const conVal of item.conflictsWith) {
|
|
255
|
+
const conIdx = choices.findIndex(c => c.value === conVal);
|
|
256
|
+
if (conIdx !== -1 && this.checkedState[conIdx]) {
|
|
257
|
+
return `${item.title} conflicts with ${choices[conIdx].title}`;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
exports.DependencyPrompt = DependencyPrompt;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { DialOptions, MouseEvent } from '../types';
|
|
3
|
+
export declare class DialPrompt extends Prompt<number, DialOptions> {
|
|
4
|
+
private currentValue;
|
|
5
|
+
constructor(options: DialOptions);
|
|
6
|
+
protected render(_firstRender: boolean): void;
|
|
7
|
+
protected handleInput(char: string, _key: Buffer): void;
|
|
8
|
+
protected handleMouse(event: MouseEvent): void;
|
|
9
|
+
private updateValue;
|
|
10
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DialPrompt = void 0;
|
|
4
|
+
const base_1 = require("../base");
|
|
5
|
+
const theme_1 = require("../theme");
|
|
6
|
+
const ansi_1 = require("../ansi");
|
|
7
|
+
class DialPrompt extends base_1.Prompt {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super(options);
|
|
10
|
+
this.currentValue = options.initial !== undefined ? options.initial : options.min;
|
|
11
|
+
// Clamp initial
|
|
12
|
+
if (this.currentValue < this.options.min)
|
|
13
|
+
this.currentValue = this.options.min;
|
|
14
|
+
if (this.currentValue > this.options.max)
|
|
15
|
+
this.currentValue = this.options.max;
|
|
16
|
+
}
|
|
17
|
+
render(_firstRender) {
|
|
18
|
+
// Round value for display if necessary
|
|
19
|
+
const displayValue = Math.round(this.currentValue * 100) / 100;
|
|
20
|
+
let output = `${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${theme_1.theme.main}${displayValue}${ansi_1.ANSI.RESET}\n`;
|
|
21
|
+
const radius = this.options.radius || 5;
|
|
22
|
+
// Adjust aspect ratio: terminal chars are ~2x taller than wide.
|
|
23
|
+
// So we multiply X by 2.
|
|
24
|
+
const centerX = radius * 2;
|
|
25
|
+
const centerY = radius;
|
|
26
|
+
const width = centerX * 2 + 1;
|
|
27
|
+
const height = centerY * 2 + 1;
|
|
28
|
+
// Initialize grid
|
|
29
|
+
const grid = [];
|
|
30
|
+
for (let y = 0; y < height; y++) {
|
|
31
|
+
const row = [];
|
|
32
|
+
for (let x = 0; x < width; x++) {
|
|
33
|
+
row.push(' ');
|
|
34
|
+
}
|
|
35
|
+
grid.push(row);
|
|
36
|
+
}
|
|
37
|
+
// Draw track (static circle arc)
|
|
38
|
+
// Knob usually goes from Bottom-Left (135 deg) to Bottom-Right (405 deg)
|
|
39
|
+
// 0 deg is Right. 90 deg is Down.
|
|
40
|
+
for (let a = 135; a <= 405; a += 10) {
|
|
41
|
+
const rad = a * Math.PI / 180;
|
|
42
|
+
const rX = Math.round(centerX + radius * Math.cos(rad) * 2);
|
|
43
|
+
const rY = Math.round(centerY + radius * Math.sin(rad));
|
|
44
|
+
if (rY >= 0 && rY < height && rX >= 0 && rX < width) {
|
|
45
|
+
grid[rY][rX] = `${ansi_1.ANSI.FG_GRAY}·${ansi_1.ANSI.RESET}`;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Calculate Pointer Position
|
|
49
|
+
const totalRange = this.options.max - this.options.min;
|
|
50
|
+
// Avoid division by zero
|
|
51
|
+
const percent = totalRange === 0 ? 0 : (this.currentValue - this.options.min) / totalRange;
|
|
52
|
+
const angleDeg = 135 + (percent * 270);
|
|
53
|
+
const rad = angleDeg * Math.PI / 180;
|
|
54
|
+
const ptrX = Math.round(centerX + radius * Math.cos(rad) * 2);
|
|
55
|
+
const ptrY = Math.round(centerY + radius * Math.sin(rad));
|
|
56
|
+
if (ptrY >= 0 && ptrY < height && ptrX >= 0 && ptrX < width) {
|
|
57
|
+
grid[ptrY][ptrX] = `${theme_1.theme.main}${this.options.pointerSymbol || '●'}${ansi_1.ANSI.RESET}`;
|
|
58
|
+
}
|
|
59
|
+
// Draw Center Value (Optional - roughly centered)
|
|
60
|
+
// const valStr = displayValue.toString();
|
|
61
|
+
// const valX = centerX - Math.floor(valStr.length / 2);
|
|
62
|
+
// const valY = centerY;
|
|
63
|
+
// if (valY >= 0 && valY < height && valX >= 0 && valX + valStr.length <= width) {
|
|
64
|
+
// for (let i = 0; i < valStr.length; i++) {
|
|
65
|
+
// // grid[valY][valX + i] = valStr[i];
|
|
66
|
+
// }
|
|
67
|
+
// }
|
|
68
|
+
// Construct string
|
|
69
|
+
for (let y = 0; y < height; y++) {
|
|
70
|
+
output += ' ' + grid[y].join('') + '\n';
|
|
71
|
+
}
|
|
72
|
+
// Instructions
|
|
73
|
+
output += `\n${ansi_1.ANSI.FG_GRAY}(Arrows/Scroll to adjust, Enter to submit)${ansi_1.ANSI.RESET}`;
|
|
74
|
+
this.renderFrame(output);
|
|
75
|
+
}
|
|
76
|
+
handleInput(char, _key) {
|
|
77
|
+
const step = this.options.step || 1;
|
|
78
|
+
if (this.isLeft(char) || this.isDown(char)) {
|
|
79
|
+
this.updateValue(this.currentValue - step);
|
|
80
|
+
}
|
|
81
|
+
else if (this.isRight(char) || this.isUp(char)) {
|
|
82
|
+
this.updateValue(this.currentValue + step);
|
|
83
|
+
}
|
|
84
|
+
else if (char === '\r' || char === '\n') {
|
|
85
|
+
this.submit(this.currentValue);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
handleMouse(event) {
|
|
89
|
+
const step = this.options.step || 1;
|
|
90
|
+
if (event.action === 'scroll') {
|
|
91
|
+
if (event.scroll === 'up') {
|
|
92
|
+
this.updateValue(this.currentValue + step);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.updateValue(this.currentValue - step);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
updateValue(val) {
|
|
100
|
+
if (val < this.options.min)
|
|
101
|
+
val = this.options.min;
|
|
102
|
+
if (val > this.options.max)
|
|
103
|
+
val = this.options.max;
|
|
104
|
+
if (this.currentValue !== val) {
|
|
105
|
+
this.currentValue = val;
|
|
106
|
+
this.render(false);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.DialPrompt = DialPrompt;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { DiffOptions } from '../types';
|
|
3
|
+
export declare class DiffPrompt extends Prompt<string, DiffOptions> {
|
|
4
|
+
private activeAction;
|
|
5
|
+
private actions;
|
|
6
|
+
constructor(options: DiffOptions);
|
|
7
|
+
protected render(_firstRender: boolean): void;
|
|
8
|
+
protected handleInput(char: string, _key: Buffer): void;
|
|
9
|
+
private handleSubmit;
|
|
10
|
+
}
|