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.
Files changed (75) hide show
  1. package/README.md +173 -6
  2. package/dist/ansi.d.ts +1 -0
  3. package/dist/ansi.js +1 -0
  4. package/dist/base.d.ts +1 -1
  5. package/dist/base.js +1 -10
  6. package/dist/core.d.ts +23 -1
  7. package/dist/core.js +60 -0
  8. package/dist/highlight.d.ts +1 -0
  9. package/dist/highlight.js +40 -0
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/input.js +26 -14
  13. package/dist/prompts/autocomplete.d.ts +1 -1
  14. package/dist/prompts/autocomplete.js +2 -7
  15. package/dist/prompts/calendar.d.ts +20 -0
  16. package/dist/prompts/calendar.js +329 -0
  17. package/dist/prompts/checkbox.d.ts +1 -1
  18. package/dist/prompts/checkbox.js +38 -8
  19. package/dist/prompts/code.d.ts +17 -0
  20. package/dist/prompts/code.js +210 -0
  21. package/dist/prompts/color.d.ts +14 -0
  22. package/dist/prompts/color.js +147 -0
  23. package/dist/prompts/confirm.d.ts +1 -1
  24. package/dist/prompts/confirm.js +1 -1
  25. package/dist/prompts/cron.d.ts +13 -0
  26. package/dist/prompts/cron.js +176 -0
  27. package/dist/prompts/date.d.ts +1 -1
  28. package/dist/prompts/date.js +15 -5
  29. package/dist/prompts/editor.js +2 -2
  30. package/dist/prompts/file.d.ts +7 -0
  31. package/dist/prompts/file.js +56 -60
  32. package/dist/prompts/form.d.ts +17 -0
  33. package/dist/prompts/form.js +225 -0
  34. package/dist/prompts/grid.d.ts +14 -0
  35. package/dist/prompts/grid.js +178 -0
  36. package/dist/prompts/keypress.d.ts +2 -2
  37. package/dist/prompts/keypress.js +2 -2
  38. package/dist/prompts/list.d.ts +1 -1
  39. package/dist/prompts/list.js +42 -22
  40. package/dist/prompts/multi-select.d.ts +1 -1
  41. package/dist/prompts/multi-select.js +39 -4
  42. package/dist/prompts/number.d.ts +1 -1
  43. package/dist/prompts/number.js +2 -2
  44. package/dist/prompts/range.d.ts +9 -0
  45. package/dist/prompts/range.js +140 -0
  46. package/dist/prompts/rating.d.ts +1 -1
  47. package/dist/prompts/rating.js +1 -1
  48. package/dist/prompts/select.d.ts +1 -1
  49. package/dist/prompts/select.js +1 -1
  50. package/dist/prompts/slider.d.ts +1 -1
  51. package/dist/prompts/slider.js +1 -1
  52. package/dist/prompts/snippet.d.ts +18 -0
  53. package/dist/prompts/snippet.js +203 -0
  54. package/dist/prompts/sort.d.ts +1 -1
  55. package/dist/prompts/sort.js +1 -4
  56. package/dist/prompts/spam.d.ts +17 -0
  57. package/dist/prompts/spam.js +62 -0
  58. package/dist/prompts/table.d.ts +1 -1
  59. package/dist/prompts/table.js +1 -1
  60. package/dist/prompts/text.d.ts +1 -0
  61. package/dist/prompts/text.js +13 -31
  62. package/dist/prompts/toggle.d.ts +1 -1
  63. package/dist/prompts/toggle.js +1 -1
  64. package/dist/prompts/transfer.d.ts +18 -0
  65. package/dist/prompts/transfer.js +203 -0
  66. package/dist/prompts/tree-select.d.ts +32 -0
  67. package/dist/prompts/tree-select.js +277 -0
  68. package/dist/prompts/tree.d.ts +3 -3
  69. package/dist/prompts/tree.js +27 -19
  70. package/dist/prompts/wait.d.ts +18 -0
  71. package/dist/prompts/wait.js +62 -0
  72. package/dist/types.d.ts +84 -0
  73. package/dist/utils.js +1 -1
  74. package/example.ts +150 -15
  75. package/package.json +2 -2
@@ -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
- render(firstRender) {
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
- // Folder Icon
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, key) {
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
- // Right: Expand or Go Down
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 15 Prompts + Spin Utility) ---\n");
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 (New) ---
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 (New) ---
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
- // --- 9. Rating Prompt (New) ---
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 (New) ---
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 (New) ---
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 (New) ---
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 (New) ---
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 (New) ---
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
- // --- 15. Table Prompt (New) ---
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 (New) ---
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 (New) ---
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 (New) ---
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. Spin Utility (Loading/Async Task Indicator) ---
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 (including Editor) demonstrated! ---");
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.5.5",
4
- "description": "Zero-dependency, minimalist interactive CLI prompt for Node.js",
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"