mepcli 0.5.5 → 0.6.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 +173 -6
- package/dist/ansi.d.ts +1 -0
- package/dist/ansi.js +1 -0
- package/dist/base.d.ts +1 -1
- package/dist/base.js +1 -10
- package/dist/core.d.ts +23 -1
- package/dist/core.js +60 -0
- package/dist/highlight.d.ts +1 -0
- package/dist/highlight.js +40 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/input.js +26 -14
- package/dist/prompts/autocomplete.d.ts +1 -1
- package/dist/prompts/autocomplete.js +2 -7
- package/dist/prompts/calendar.d.ts +20 -0
- package/dist/prompts/calendar.js +329 -0
- package/dist/prompts/checkbox.d.ts +1 -1
- package/dist/prompts/checkbox.js +38 -8
- package/dist/prompts/code.d.ts +17 -0
- package/dist/prompts/code.js +210 -0
- package/dist/prompts/color.d.ts +14 -0
- package/dist/prompts/color.js +147 -0
- package/dist/prompts/confirm.d.ts +1 -1
- package/dist/prompts/confirm.js +1 -1
- package/dist/prompts/cron.d.ts +13 -0
- package/dist/prompts/cron.js +176 -0
- package/dist/prompts/date.d.ts +1 -1
- package/dist/prompts/date.js +15 -5
- package/dist/prompts/editor.js +2 -2
- package/dist/prompts/file.d.ts +7 -0
- package/dist/prompts/file.js +56 -60
- package/dist/prompts/form.d.ts +17 -0
- package/dist/prompts/form.js +225 -0
- package/dist/prompts/grid.d.ts +14 -0
- package/dist/prompts/grid.js +178 -0
- package/dist/prompts/keypress.d.ts +2 -2
- package/dist/prompts/keypress.js +2 -2
- package/dist/prompts/list.d.ts +1 -1
- package/dist/prompts/list.js +42 -22
- package/dist/prompts/multi-select.d.ts +1 -1
- package/dist/prompts/multi-select.js +39 -4
- package/dist/prompts/number.d.ts +1 -1
- package/dist/prompts/number.js +2 -2
- package/dist/prompts/range.d.ts +9 -0
- package/dist/prompts/range.js +140 -0
- package/dist/prompts/rating.d.ts +1 -1
- package/dist/prompts/rating.js +1 -1
- package/dist/prompts/select.d.ts +1 -1
- package/dist/prompts/select.js +1 -1
- package/dist/prompts/slider.d.ts +1 -1
- package/dist/prompts/slider.js +1 -1
- package/dist/prompts/snippet.d.ts +18 -0
- package/dist/prompts/snippet.js +203 -0
- package/dist/prompts/sort.d.ts +1 -1
- package/dist/prompts/sort.js +1 -4
- package/dist/prompts/spam.d.ts +17 -0
- package/dist/prompts/spam.js +62 -0
- package/dist/prompts/table.d.ts +1 -1
- package/dist/prompts/table.js +1 -1
- package/dist/prompts/text.d.ts +1 -0
- package/dist/prompts/text.js +13 -31
- package/dist/prompts/toggle.d.ts +1 -1
- package/dist/prompts/toggle.js +1 -1
- package/dist/prompts/transfer.d.ts +18 -0
- package/dist/prompts/transfer.js +203 -0
- package/dist/prompts/tree-select.d.ts +32 -0
- package/dist/prompts/tree-select.js +277 -0
- package/dist/prompts/tree.d.ts +3 -3
- package/dist/prompts/tree.js +27 -19
- package/dist/prompts/wait.d.ts +18 -0
- package/dist/prompts/wait.js +62 -0
- package/dist/types.d.ts +84 -0
- package/dist/utils.js +1 -1
- package/example.ts +150 -15
- package/package.json +2 -2
package/dist/prompts/tree.js
CHANGED
|
@@ -16,9 +16,7 @@ class TreePrompt extends base_1.Prompt {
|
|
|
16
16
|
// Icons
|
|
17
17
|
this.ICON_CLOSED = symbols_1.symbols.pointer === '>' ? '+' : '▸';
|
|
18
18
|
this.ICON_OPEN = symbols_1.symbols.pointer === '>' ? '-' : '▾';
|
|
19
|
-
this.ICON_LEAF = symbols_1.symbols.pointer === '>' ? ' ' : ' '; // No specific icon for leaf, just indentation
|
|
20
19
|
this.initializeExpanded(this.options.data);
|
|
21
|
-
// Handle initial value
|
|
22
20
|
if (this.options.initial !== undefined) {
|
|
23
21
|
this.expandPathTo(this.options.initial);
|
|
24
22
|
}
|
|
@@ -59,7 +57,6 @@ class TreePrompt extends base_1.Prompt {
|
|
|
59
57
|
recalculateFlatList() {
|
|
60
58
|
this.flatList = [];
|
|
61
59
|
this.traverse(this.options.data, 0, null);
|
|
62
|
-
// Adjust cursor if it went out of bounds (e.g. collapsing a folder above cursor)
|
|
63
60
|
if (this.cursor >= this.flatList.length) {
|
|
64
61
|
this.cursor = Math.max(0, this.flatList.length - 1);
|
|
65
62
|
}
|
|
@@ -76,14 +73,22 @@ class TreePrompt extends base_1.Prompt {
|
|
|
76
73
|
}
|
|
77
74
|
}
|
|
78
75
|
}
|
|
79
|
-
|
|
76
|
+
toggleRecursive(node, expand) {
|
|
77
|
+
if (expand)
|
|
78
|
+
this.expandedNodes.add(node);
|
|
79
|
+
else
|
|
80
|
+
this.expandedNodes.delete(node);
|
|
81
|
+
if (node.children) {
|
|
82
|
+
node.children.forEach(child => this.toggleRecursive(child, expand));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
render(_firstRender) {
|
|
80
86
|
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`;
|
|
81
87
|
if (this.flatList.length === 0) {
|
|
82
88
|
output += ` ${theme_1.theme.muted}No data${ansi_1.ANSI.RESET}`;
|
|
83
89
|
this.renderFrame(output);
|
|
84
90
|
return;
|
|
85
91
|
}
|
|
86
|
-
// Adjust Scroll
|
|
87
92
|
if (this.cursor < this.scrollTop) {
|
|
88
93
|
this.scrollTop = this.cursor;
|
|
89
94
|
}
|
|
@@ -94,10 +99,8 @@ class TreePrompt extends base_1.Prompt {
|
|
|
94
99
|
visible.forEach((item, index) => {
|
|
95
100
|
const actualIndex = this.scrollTop + index;
|
|
96
101
|
const isSelected = actualIndex === this.cursor;
|
|
97
|
-
// Indentation
|
|
98
102
|
const indentSize = this.options.indent || 2;
|
|
99
103
|
const indentation = ' '.repeat(item.depth * indentSize);
|
|
100
|
-
// Pointer
|
|
101
104
|
let linePrefix = '';
|
|
102
105
|
if (isSelected) {
|
|
103
106
|
linePrefix = `${theme_1.theme.main}${symbols_1.symbols.pointer} `;
|
|
@@ -105,8 +108,7 @@ class TreePrompt extends base_1.Prompt {
|
|
|
105
108
|
else {
|
|
106
109
|
linePrefix = ' ';
|
|
107
110
|
}
|
|
108
|
-
|
|
109
|
-
let icon = ' '; // Default 2 spaces for alignment
|
|
111
|
+
let icon = ' ';
|
|
110
112
|
const hasChildren = item.node.children && item.node.children.length > 0;
|
|
111
113
|
if (hasChildren) {
|
|
112
114
|
if (this.expandedNodes.has(item.node)) {
|
|
@@ -116,12 +118,10 @@ class TreePrompt extends base_1.Prompt {
|
|
|
116
118
|
icon = `${this.ICON_CLOSED} `;
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
|
-
// Title
|
|
120
121
|
let title = item.node.title;
|
|
121
122
|
if (item.node.disabled) {
|
|
122
123
|
title = `${theme_1.theme.muted}${title} (disabled)${ansi_1.ANSI.RESET}`;
|
|
123
124
|
}
|
|
124
|
-
// Compose line
|
|
125
125
|
let line = `${indentation}${icon}${title}`;
|
|
126
126
|
if (isSelected) {
|
|
127
127
|
line = `${theme_1.theme.main}${line}${ansi_1.ANSI.RESET}`;
|
|
@@ -130,12 +130,12 @@ class TreePrompt extends base_1.Prompt {
|
|
|
130
130
|
if (index < visible.length - 1)
|
|
131
131
|
output += '\n';
|
|
132
132
|
});
|
|
133
|
+
output += `\n${theme_1.theme.muted}(Arrows: Nav, e: Expand All, c: Collapse All)${ansi_1.ANSI.RESET}`;
|
|
133
134
|
this.renderFrame(output);
|
|
134
135
|
}
|
|
135
|
-
handleInput(char,
|
|
136
|
+
handleInput(char, _key) {
|
|
136
137
|
if (this.flatList.length === 0)
|
|
137
138
|
return;
|
|
138
|
-
// Navigation
|
|
139
139
|
if (this.isUp(char)) {
|
|
140
140
|
this.cursor = (this.cursor - 1 + this.flatList.length) % this.flatList.length;
|
|
141
141
|
this.render(false);
|
|
@@ -149,7 +149,20 @@ class TreePrompt extends base_1.Prompt {
|
|
|
149
149
|
const currentItem = this.flatList[this.cursor];
|
|
150
150
|
const node = currentItem.node;
|
|
151
151
|
const hasChildren = node.children && node.children.length > 0;
|
|
152
|
-
//
|
|
152
|
+
// Recursive Expand (e)
|
|
153
|
+
if (char === 'e' && hasChildren) {
|
|
154
|
+
this.toggleRecursive(node, true);
|
|
155
|
+
this.recalculateFlatList();
|
|
156
|
+
this.render(false);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
// Recursive Collapse (c)
|
|
160
|
+
if (char === 'c' && hasChildren) {
|
|
161
|
+
this.toggleRecursive(node, false);
|
|
162
|
+
this.recalculateFlatList();
|
|
163
|
+
this.render(false);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
153
166
|
if (this.isRight(char)) {
|
|
154
167
|
if (hasChildren) {
|
|
155
168
|
if (!this.expandedNodes.has(node)) {
|
|
@@ -157,7 +170,6 @@ class TreePrompt extends base_1.Prompt {
|
|
|
157
170
|
this.recalculateFlatList();
|
|
158
171
|
}
|
|
159
172
|
else {
|
|
160
|
-
// Go to first child (next item in flat list)
|
|
161
173
|
if (this.cursor + 1 < this.flatList.length) {
|
|
162
174
|
this.cursor++;
|
|
163
175
|
}
|
|
@@ -166,7 +178,6 @@ class TreePrompt extends base_1.Prompt {
|
|
|
166
178
|
return;
|
|
167
179
|
}
|
|
168
180
|
}
|
|
169
|
-
// Left: Collapse or Go Up (Parent)
|
|
170
181
|
if (this.isLeft(char)) {
|
|
171
182
|
if (hasChildren && this.expandedNodes.has(node)) {
|
|
172
183
|
this.expandedNodes.delete(node);
|
|
@@ -175,7 +186,6 @@ class TreePrompt extends base_1.Prompt {
|
|
|
175
186
|
return;
|
|
176
187
|
}
|
|
177
188
|
else {
|
|
178
|
-
// Go to parent
|
|
179
189
|
if (currentItem.parent) {
|
|
180
190
|
const parentIndex = this.flatList.findIndex(x => x.node === currentItem.parent);
|
|
181
191
|
if (parentIndex !== -1) {
|
|
@@ -186,7 +196,6 @@ class TreePrompt extends base_1.Prompt {
|
|
|
186
196
|
}
|
|
187
197
|
}
|
|
188
198
|
}
|
|
189
|
-
// Toggle (Space)
|
|
190
199
|
if (char === ' ') {
|
|
191
200
|
if (hasChildren) {
|
|
192
201
|
if (this.expandedNodes.has(node)) {
|
|
@@ -200,7 +209,6 @@ class TreePrompt extends base_1.Prompt {
|
|
|
200
209
|
}
|
|
201
210
|
return;
|
|
202
211
|
}
|
|
203
|
-
// Submit (Enter)
|
|
204
212
|
if (char === '\r' || char === '\n') {
|
|
205
213
|
if (!node.disabled) {
|
|
206
214
|
this.submit(node.value);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Prompt } from '../base';
|
|
2
|
+
import { BaseOptions } from '../types';
|
|
3
|
+
interface WaitOptions extends BaseOptions {
|
|
4
|
+
seconds: number;
|
|
5
|
+
autoSubmit?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare class WaitPrompt extends Prompt<void, WaitOptions> {
|
|
8
|
+
private remaining;
|
|
9
|
+
private timer?;
|
|
10
|
+
private isDone;
|
|
11
|
+
constructor(options: WaitOptions);
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
private stopTimer;
|
|
14
|
+
protected cleanup(): void;
|
|
15
|
+
protected render(_firstRender: boolean): void;
|
|
16
|
+
protected handleInput(char: string): void;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WaitPrompt = void 0;
|
|
4
|
+
// src/prompts/wait.ts
|
|
5
|
+
const ansi_1 = require("../ansi");
|
|
6
|
+
const base_1 = require("../base");
|
|
7
|
+
const theme_1 = require("../theme");
|
|
8
|
+
class WaitPrompt extends base_1.Prompt {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.isDone = false;
|
|
12
|
+
this.remaining = options.seconds;
|
|
13
|
+
}
|
|
14
|
+
run() {
|
|
15
|
+
// Start the countdown immediately upon running
|
|
16
|
+
this.timer = setInterval(() => {
|
|
17
|
+
this.remaining--;
|
|
18
|
+
if (this.remaining <= 0) {
|
|
19
|
+
this.isDone = true;
|
|
20
|
+
this.stopTimer();
|
|
21
|
+
if (this.options.autoSubmit) {
|
|
22
|
+
this.submit();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.render(false);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
this.render(false);
|
|
30
|
+
}
|
|
31
|
+
}, 1000);
|
|
32
|
+
return super.run();
|
|
33
|
+
}
|
|
34
|
+
stopTimer() {
|
|
35
|
+
if (this.timer) {
|
|
36
|
+
clearInterval(this.timer);
|
|
37
|
+
this.timer = undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
cleanup() {
|
|
41
|
+
this.stopTimer();
|
|
42
|
+
super.cleanup();
|
|
43
|
+
}
|
|
44
|
+
render(_firstRender) {
|
|
45
|
+
let output = `${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} `;
|
|
46
|
+
if (this.isDone) {
|
|
47
|
+
output += `${theme_1.theme.success}Done! Press Enter to continue.${ansi_1.ANSI.RESET}`;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Fun countdown visualization
|
|
51
|
+
output += `${theme_1.theme.muted}Please wait... ${this.remaining}s${ansi_1.ANSI.RESET}`;
|
|
52
|
+
}
|
|
53
|
+
this.renderFrame(output);
|
|
54
|
+
}
|
|
55
|
+
handleInput(char) {
|
|
56
|
+
if (this.isDone && (char === '\r' || char === '\n')) {
|
|
57
|
+
this.submit();
|
|
58
|
+
}
|
|
59
|
+
// Else: Ignore all input while waiting
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.WaitPrompt = WaitPrompt;
|
package/dist/types.d.ts
CHANGED
|
@@ -19,6 +19,9 @@ export interface MouseEvent {
|
|
|
19
19
|
button: number;
|
|
20
20
|
action: 'press' | 'release' | 'move' | 'scroll';
|
|
21
21
|
scroll?: 'up' | 'down';
|
|
22
|
+
shift?: boolean;
|
|
23
|
+
ctrl?: boolean;
|
|
24
|
+
meta?: boolean;
|
|
22
25
|
}
|
|
23
26
|
export interface TextOptions extends BaseOptions {
|
|
24
27
|
placeholder?: string;
|
|
@@ -26,6 +29,7 @@ export interface TextOptions extends BaseOptions {
|
|
|
26
29
|
validate?: (value: string) => string | boolean | Promise<string | boolean>;
|
|
27
30
|
isPassword?: boolean;
|
|
28
31
|
multiline?: boolean;
|
|
32
|
+
mask?: string;
|
|
29
33
|
}
|
|
30
34
|
export interface Separator {
|
|
31
35
|
separator: true;
|
|
@@ -39,6 +43,14 @@ export interface SelectChoice<V> {
|
|
|
39
43
|
export interface SelectOptions<V> extends BaseOptions {
|
|
40
44
|
choices: (SelectChoice<V> | Separator)[];
|
|
41
45
|
}
|
|
46
|
+
export interface TransferOptions<V> extends BaseOptions {
|
|
47
|
+
source: (string | SelectChoice<V>)[];
|
|
48
|
+
target?: (string | SelectChoice<V>)[];
|
|
49
|
+
}
|
|
50
|
+
export interface CronOptions extends BaseOptions {
|
|
51
|
+
initial?: string;
|
|
52
|
+
placeholder?: string;
|
|
53
|
+
}
|
|
42
54
|
export interface CheckboxChoice<V> extends SelectChoice<V> {
|
|
43
55
|
selected?: boolean;
|
|
44
56
|
}
|
|
@@ -74,6 +86,13 @@ export interface SliderOptions extends BaseOptions {
|
|
|
74
86
|
step?: number;
|
|
75
87
|
unit?: string;
|
|
76
88
|
}
|
|
89
|
+
export interface RangeOptions extends BaseOptions {
|
|
90
|
+
min: number;
|
|
91
|
+
max: number;
|
|
92
|
+
initial?: [number, number];
|
|
93
|
+
step?: number;
|
|
94
|
+
unit?: string;
|
|
95
|
+
}
|
|
77
96
|
export interface RatingOptions extends BaseOptions {
|
|
78
97
|
min?: number;
|
|
79
98
|
max?: number;
|
|
@@ -120,6 +139,7 @@ export interface TreeNode<V> {
|
|
|
120
139
|
children?: TreeNode<V>[];
|
|
121
140
|
expanded?: boolean;
|
|
122
141
|
disabled?: boolean;
|
|
142
|
+
selected?: boolean | 'indeterminate';
|
|
123
143
|
}
|
|
124
144
|
export interface TreeOptions<V> extends BaseOptions {
|
|
125
145
|
data: TreeNode<V>[];
|
|
@@ -130,3 +150,67 @@ export interface KeypressOptions extends BaseOptions {
|
|
|
130
150
|
keys?: string[];
|
|
131
151
|
showInvisible?: boolean;
|
|
132
152
|
}
|
|
153
|
+
export interface FormField {
|
|
154
|
+
name: string;
|
|
155
|
+
message: string;
|
|
156
|
+
initial?: string;
|
|
157
|
+
validate?: (value: string) => string | boolean | Promise<string | boolean>;
|
|
158
|
+
}
|
|
159
|
+
export interface FormOptions extends BaseOptions {
|
|
160
|
+
fields: FormField[];
|
|
161
|
+
}
|
|
162
|
+
export interface SnippetOptions extends BaseOptions {
|
|
163
|
+
template: string;
|
|
164
|
+
values?: Record<string, string>;
|
|
165
|
+
fields?: Record<string, {
|
|
166
|
+
message?: string;
|
|
167
|
+
validate?: (value: string) => string | boolean;
|
|
168
|
+
}>;
|
|
169
|
+
}
|
|
170
|
+
export interface SpamOptions extends BaseOptions {
|
|
171
|
+
threshold: number;
|
|
172
|
+
spamKey?: string;
|
|
173
|
+
decay?: boolean;
|
|
174
|
+
}
|
|
175
|
+
export interface WaitOptions extends BaseOptions {
|
|
176
|
+
seconds: number;
|
|
177
|
+
autoSubmit?: boolean;
|
|
178
|
+
}
|
|
179
|
+
export interface CodeOptions extends BaseOptions {
|
|
180
|
+
template: string;
|
|
181
|
+
language?: 'json' | 'yaml';
|
|
182
|
+
/**
|
|
183
|
+
* Enable syntax highlighting (Experimental).
|
|
184
|
+
* @default true
|
|
185
|
+
*/
|
|
186
|
+
highlight?: boolean;
|
|
187
|
+
}
|
|
188
|
+
export interface TreeSelectNode<V> {
|
|
189
|
+
title: string;
|
|
190
|
+
value: V;
|
|
191
|
+
children?: TreeSelectNode<V>[];
|
|
192
|
+
expanded?: boolean;
|
|
193
|
+
disabled?: boolean;
|
|
194
|
+
selected?: boolean | 'indeterminate';
|
|
195
|
+
}
|
|
196
|
+
export interface TreeSelectOptions<V> extends BaseOptions {
|
|
197
|
+
data: TreeSelectNode<V>[];
|
|
198
|
+
initial?: V[];
|
|
199
|
+
indent?: number;
|
|
200
|
+
}
|
|
201
|
+
export interface ColorOptions extends BaseOptions {
|
|
202
|
+
initial?: string;
|
|
203
|
+
format?: 'hex' | 'rgb' | 'hsl';
|
|
204
|
+
}
|
|
205
|
+
export interface GridOptions extends BaseOptions {
|
|
206
|
+
rows: string[];
|
|
207
|
+
columns: string[];
|
|
208
|
+
initial?: boolean[][];
|
|
209
|
+
}
|
|
210
|
+
export interface CalendarOptions extends BaseOptions {
|
|
211
|
+
mode?: 'single' | 'range';
|
|
212
|
+
initial?: Date | [Date, Date];
|
|
213
|
+
min?: Date;
|
|
214
|
+
max?: Date;
|
|
215
|
+
weekStart?: 0 | 1;
|
|
216
|
+
}
|
package/dist/utils.js
CHANGED
|
@@ -13,7 +13,7 @@ function detectCapabilities() {
|
|
|
13
13
|
// Check for CI
|
|
14
14
|
const isCI = !!env.CI;
|
|
15
15
|
// Check for True Color support
|
|
16
|
-
const hasTrueColor = env.COLORTERM === 'truecolor';
|
|
16
|
+
const hasTrueColor = env.COLORTERM === 'truecolor' || !!env.WT_SESSION;
|
|
17
17
|
// Check if it is a TTY
|
|
18
18
|
const isTTY = process.stdout.isTTY;
|
|
19
19
|
const isWindows = process.platform === 'win32';
|
package/example.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { MepCLI } from './src'; // Or 'mepcli' if installed via NPM
|
|
|
8
8
|
*/
|
|
9
9
|
async function runComprehensiveDemo() {
|
|
10
10
|
console.clear();
|
|
11
|
-
console.log("--- MepCLI Comprehensive Demo (All
|
|
11
|
+
console.log("--- MepCLI Comprehensive Demo (All Prompts + Spin Utility) ---\n");
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
14
|
// --- 1. Text Prompt (Input with Validation and initial value) ---
|
|
@@ -30,6 +30,13 @@ async function runComprehensiveDemo() {
|
|
|
30
30
|
});
|
|
31
31
|
console.log(`\n Password Result: API key entered (length: ${apiKey.length})`);
|
|
32
32
|
|
|
33
|
+
// --- 2.5. Secret Prompt (Completely hidden input) ---
|
|
34
|
+
const secretToken = await MepCLI.secret({
|
|
35
|
+
message: "Enter secret token (no feedback):",
|
|
36
|
+
validate: (v) => v.length > 0 || "Token required"
|
|
37
|
+
});
|
|
38
|
+
console.log(`\n Secret Result: Token entered (length: ${secretToken.length})`);
|
|
39
|
+
|
|
33
40
|
// --- 3. Select Prompt (Single choice, supports filtering/searching by typing) ---
|
|
34
41
|
const theme = await MepCLI.select({
|
|
35
42
|
message: "Choose your preferred editor color theme:",
|
|
@@ -77,7 +84,7 @@ async function runComprehensiveDemo() {
|
|
|
77
84
|
});
|
|
78
85
|
console.log(`\n Toggle Result: HTTPS enabled: ${isSecure}`);
|
|
79
86
|
|
|
80
|
-
// --- 7. List / Tags Input
|
|
87
|
+
// --- 7. List / Tags Input ---
|
|
81
88
|
const keywords = await MepCLI.list({
|
|
82
89
|
message: "Enter keywords for package.json (Enter to add, Backspace to remove):",
|
|
83
90
|
initial: ["cli", "mep"],
|
|
@@ -85,7 +92,7 @@ async function runComprehensiveDemo() {
|
|
|
85
92
|
});
|
|
86
93
|
console.log(`\n List Result: Keywords: [${keywords.join(', ')}]`);
|
|
87
94
|
|
|
88
|
-
// --- 8. Slider / Scale
|
|
95
|
+
// --- 8. Slider / Scale ---
|
|
89
96
|
const brightness = await MepCLI.slider({
|
|
90
97
|
message: "Set initial brightness:",
|
|
91
98
|
min: 0,
|
|
@@ -96,7 +103,18 @@ async function runComprehensiveDemo() {
|
|
|
96
103
|
});
|
|
97
104
|
console.log(`\n Slider Result: Brightness: ${brightness}%`);
|
|
98
105
|
|
|
99
|
-
// ---
|
|
106
|
+
// --- 8.1. Range Prompt (Dual Slider) ---
|
|
107
|
+
const priceRange = await MepCLI.range({
|
|
108
|
+
message: "Filter by price range:",
|
|
109
|
+
min: 0,
|
|
110
|
+
max: 1000,
|
|
111
|
+
initial: [200, 800],
|
|
112
|
+
step: 50,
|
|
113
|
+
unit: "$"
|
|
114
|
+
});
|
|
115
|
+
console.log(`\n Range Result: $${priceRange[0]} - $${priceRange[1]}`);
|
|
116
|
+
|
|
117
|
+
// --- 9. Rating Prompt ---
|
|
100
118
|
const userRating = await MepCLI.rating({
|
|
101
119
|
message: "How would you rate this CLI tool?",
|
|
102
120
|
min: 1,
|
|
@@ -105,7 +123,7 @@ async function runComprehensiveDemo() {
|
|
|
105
123
|
});
|
|
106
124
|
console.log(`\n Rating Result: You rated it: ${userRating}/5`);
|
|
107
125
|
|
|
108
|
-
// --- 10. Date / Time Picker
|
|
126
|
+
// --- 10. Date / Time Picker ---
|
|
109
127
|
// We capture 'now' once to ensure initial >= min
|
|
110
128
|
const now = new Date();
|
|
111
129
|
const releaseDate = await MepCLI.date({
|
|
@@ -115,14 +133,14 @@ async function runComprehensiveDemo() {
|
|
|
115
133
|
});
|
|
116
134
|
console.log(`\n Date Result: Release set for: ${releaseDate.toLocaleString()}`);
|
|
117
135
|
|
|
118
|
-
// --- 11. File Path Selector
|
|
136
|
+
// --- 11. File Path Selector ---
|
|
119
137
|
const configPath = await MepCLI.file({
|
|
120
138
|
message: "Select configuration file (Tab to autocomplete):",
|
|
121
139
|
basePath: process.cwd()
|
|
122
140
|
});
|
|
123
141
|
console.log(`\n File Result: Path: ${configPath}`);
|
|
124
142
|
|
|
125
|
-
// --- 12. Multi-Select Autocomplete
|
|
143
|
+
// --- 12. Multi-Select Autocomplete ---
|
|
126
144
|
const linters = await MepCLI.multiSelect({
|
|
127
145
|
message: "Select linters to install (Type to search, Space to select):",
|
|
128
146
|
choices: [
|
|
@@ -137,7 +155,7 @@ async function runComprehensiveDemo() {
|
|
|
137
155
|
});
|
|
138
156
|
console.log(`\n MultiSelect Result: Linters: [${linters.join(', ')}]`);
|
|
139
157
|
|
|
140
|
-
// --- 13. Autocomplete Prompt
|
|
158
|
+
// --- 13. Autocomplete Prompt ---
|
|
141
159
|
const city = await MepCLI.autocomplete({
|
|
142
160
|
message: "Search for a city (simulated async):",
|
|
143
161
|
suggest: async (query) => {
|
|
@@ -157,14 +175,22 @@ async function runComprehensiveDemo() {
|
|
|
157
175
|
});
|
|
158
176
|
console.log(`\n Autocomplete Result: City code: ${city}`);
|
|
159
177
|
|
|
160
|
-
// --- 14. Sort Prompt
|
|
178
|
+
// --- 14. Sort Prompt ---
|
|
161
179
|
const priorities = await MepCLI.sort({
|
|
162
180
|
message: "Rank your top priorities (Space to grab/drop, Arrows to move):",
|
|
163
181
|
items: ["Performance", "Security", "Features", "Usability", "Cost"]
|
|
164
182
|
});
|
|
165
183
|
console.log(`\n Sort Result: Priorities: [${priorities.join(', ')}]`);
|
|
166
184
|
|
|
167
|
-
// ---
|
|
185
|
+
// --- 14.1 Transfer Prompt (PickList) ---
|
|
186
|
+
const teamA = await MepCLI.transfer({
|
|
187
|
+
message: "Assign members to Team A (Space to move):",
|
|
188
|
+
source: ["Alice", "Bob", "Charlie", "David", "Eve"],
|
|
189
|
+
target: ["Frank"] // Pre-assigned
|
|
190
|
+
});
|
|
191
|
+
console.log(`\n Transfer Result: Team A: [${teamA[1].join(', ')}] (Remaining: [${teamA[0].join(', ')}])`);
|
|
192
|
+
|
|
193
|
+
// --- 15. Table Prompt ---
|
|
168
194
|
const userId = await MepCLI.table({
|
|
169
195
|
message: "Select a user from the database:",
|
|
170
196
|
columns: ["ID", "Name", "Role", "Status"],
|
|
@@ -184,7 +210,7 @@ async function runComprehensiveDemo() {
|
|
|
184
210
|
});
|
|
185
211
|
console.log(`\n Confirm Result: Deployment decision: ${proceed ? 'Proceed' : 'Cancel'}`);
|
|
186
212
|
|
|
187
|
-
// --- 17. Editor Prompt
|
|
213
|
+
// --- 17. Editor Prompt ---
|
|
188
214
|
const bio = await MepCLI.editor({
|
|
189
215
|
message: "Write your biography (opens default editor):",
|
|
190
216
|
initial: "Hi, I am a developer...",
|
|
@@ -193,7 +219,7 @@ async function runComprehensiveDemo() {
|
|
|
193
219
|
});
|
|
194
220
|
console.log(`\n Editor Result: Biography length: ${bio.length} chars`);
|
|
195
221
|
|
|
196
|
-
// --- 18. Keypress Prompt
|
|
222
|
+
// --- 18. Keypress Prompt ---
|
|
197
223
|
console.log("\n--- Press any key to continue to the Tree Prompt Demo... ---");
|
|
198
224
|
const key = await MepCLI.keypress({
|
|
199
225
|
message: "Press any key to proceed (or 'q' to quit):",
|
|
@@ -202,7 +228,7 @@ async function runComprehensiveDemo() {
|
|
|
202
228
|
console.log(`\n Keypress Result: You pressed '${key}'`);
|
|
203
229
|
if (key === 'q') return;
|
|
204
230
|
|
|
205
|
-
// --- 19. Tree Prompt
|
|
231
|
+
// --- 19. Tree Prompt ---
|
|
206
232
|
const selectedFile = await MepCLI.tree({
|
|
207
233
|
message: "Select a file from the project structure (Space to toggle, Enter to select):",
|
|
208
234
|
data: [
|
|
@@ -235,12 +261,121 @@ async function runComprehensiveDemo() {
|
|
|
235
261
|
});
|
|
236
262
|
console.log(`\n Tree Result: Selected path: ${selectedFile}`);
|
|
237
263
|
|
|
238
|
-
// --- 20.
|
|
264
|
+
// --- 20. Form Prompt ---
|
|
265
|
+
const userDetails = await MepCLI.form({
|
|
266
|
+
message: "Enter User Details (Up/Down/Tab to navigate):",
|
|
267
|
+
fields: [
|
|
268
|
+
{ name: "firstname", message: "First Name", initial: "John" },
|
|
269
|
+
{ name: "lastname", message: "Last Name", validate: (v) => v.length > 0 ? true : "Required" },
|
|
270
|
+
{ name: "email", message: "Email", validate: (v) => v.includes("@") || "Invalid email" },
|
|
271
|
+
{ name: "role", message: "Job Role", initial: "Developer" }
|
|
272
|
+
]
|
|
273
|
+
});
|
|
274
|
+
console.log(`\n Form Result: User: ${JSON.stringify(userDetails)}`);
|
|
275
|
+
|
|
276
|
+
// --- 21. Snippet Prompt ---
|
|
277
|
+
const commitMsg = await MepCLI.snippet({
|
|
278
|
+
message: "Compose Commit Message (Tab/Shift+Tab to navigate variables):",
|
|
279
|
+
template: "feat(${scope}): ${message} (Refs: #${issue})",
|
|
280
|
+
values: {
|
|
281
|
+
scope: "cli",
|
|
282
|
+
issue: "123"
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
console.log(`\n Snippet Result: "${commitMsg}"`);
|
|
286
|
+
|
|
287
|
+
// --- 22. Spam Prompt ---
|
|
288
|
+
const spamConfirmed = await MepCLI.spam({
|
|
289
|
+
message: "Hold on! Confirm deployment by mashing the Space key!",
|
|
290
|
+
threshold: 10,
|
|
291
|
+
decay: false, // We're not devil
|
|
292
|
+
spamKey: ' ' // Space key
|
|
293
|
+
});
|
|
294
|
+
console.log(`\n Spam Result: Deployment confirmed: ${spamConfirmed}`);
|
|
295
|
+
|
|
296
|
+
// --- 23. Wait Prompt ---
|
|
297
|
+
await MepCLI.wait({
|
|
298
|
+
message: "Please wait while we finalize the setup...",
|
|
299
|
+
seconds: 3, // Just 3 seconds for demo
|
|
300
|
+
autoSubmit: true // Automatically proceeds after time is up
|
|
301
|
+
});
|
|
302
|
+
console.log("\n Wait Result: Wait complete.");
|
|
303
|
+
|
|
304
|
+
// --- 24. Code Prompt ---
|
|
305
|
+
const config = await MepCLI.code({
|
|
306
|
+
message: "Configure Server (JSON) - Tab to nav:",
|
|
307
|
+
language: "json",
|
|
308
|
+
highlight: true, // Experimental syntax highlighting
|
|
309
|
+
template: `
|
|
310
|
+
{
|
|
311
|
+
"host": "\${host}",
|
|
312
|
+
"port": \${port},
|
|
313
|
+
"debug": \${debug}
|
|
314
|
+
}
|
|
315
|
+
`
|
|
316
|
+
});
|
|
317
|
+
console.log(`\n Code Result: Config: ${config.replace(/\n/g, ' ')}`);
|
|
318
|
+
|
|
319
|
+
// --- 25. Tree Select Prompt ---
|
|
320
|
+
const selectedTreeItems = await MepCLI.treeSelect({
|
|
321
|
+
message: "Select files to backup (Multi-select Tree):",
|
|
322
|
+
data: [
|
|
323
|
+
{
|
|
324
|
+
title: "src",
|
|
325
|
+
value: "src",
|
|
326
|
+
children: [
|
|
327
|
+
{ title: "index.ts", value: "src/index.ts" },
|
|
328
|
+
{ title: "utils.ts", value: "src/utils.ts" }
|
|
329
|
+
]
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
title: "tests",
|
|
333
|
+
value: "tests",
|
|
334
|
+
expanded: true,
|
|
335
|
+
children: [
|
|
336
|
+
{ title: "e2e", value: "tests/e2e", selected: true },
|
|
337
|
+
{ title: "unit", value: "tests/unit" }
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
]
|
|
341
|
+
});
|
|
342
|
+
console.log(`\n TreeSelect Result: Selected: [${selectedTreeItems.join(', ')}]`);
|
|
343
|
+
|
|
344
|
+
// --- 26. Cron Prompt ---
|
|
345
|
+
const schedule = await MepCLI.cron({
|
|
346
|
+
message: "Set backup schedule (Cron):",
|
|
347
|
+
initial: "0 4 * * *" // Daily at 4:00 AM
|
|
348
|
+
});
|
|
349
|
+
console.log(`\n Cron Result: "${schedule}"`);
|
|
350
|
+
|
|
351
|
+
// --- 27. Color Prompt ---
|
|
352
|
+
const themeColor = await MepCLI.color({
|
|
353
|
+
message: "Pick your brand color (RGB):",
|
|
354
|
+
initial: "#6366f1"
|
|
355
|
+
});
|
|
356
|
+
console.log(`\n Color Result: "${themeColor}"`);
|
|
357
|
+
|
|
358
|
+
// --- 28. Grid Prompt ---
|
|
359
|
+
const permissions = await MepCLI.grid({
|
|
360
|
+
message: "Configure Access Permissions:",
|
|
361
|
+
rows: ["Admin", "User", "Guest"],
|
|
362
|
+
columns: ["Read", "Write", "Execute"]
|
|
363
|
+
});
|
|
364
|
+
console.log(`\n Grid Result: (Boolean Matrix)`, permissions);
|
|
365
|
+
|
|
366
|
+
// --- 29. Calendar Prompt ---
|
|
367
|
+
const bookingRange = await MepCLI.calendar({
|
|
368
|
+
message: "Select booking period:",
|
|
369
|
+
mode: "range"
|
|
370
|
+
});
|
|
371
|
+
console.log(`\n Calendar Result:`, bookingRange);
|
|
372
|
+
|
|
373
|
+
// --- 30. Spin Utility (Loading/Async Task Indicator) ---
|
|
239
374
|
const s = MepCLI.spinner("Finalizing configuration and deploying...").start();
|
|
240
375
|
await new Promise(resolve => setTimeout(resolve, 1500)); // Simulates a 1.5 second async task
|
|
241
376
|
s.success();
|
|
242
377
|
|
|
243
|
-
console.log("\n--- Deployment successful! All MepCLI features
|
|
378
|
+
console.log("\n--- Deployment successful! All MepCLI features demonstrated! ---");
|
|
244
379
|
|
|
245
380
|
} catch (e) {
|
|
246
381
|
// Global handler for Ctrl+C closure
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mepcli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Zero-dependency,
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Zero-dependency, interactive CLI prompt for Node.js",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/CodeTease/mep.git"
|