@nbtca/prompt 1.0.8 → 1.0.13
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 +16 -289
- package/dist/config/data.d.ts +1 -1
- package/dist/config/data.js +1 -1
- package/dist/config/data.js.map +1 -1
- package/dist/core/logo.d.ts.map +1 -1
- package/dist/core/logo.js +13 -2
- package/dist/core/logo.js.map +1 -1
- package/dist/core/menu.d.ts +5 -0
- package/dist/core/menu.d.ts.map +1 -1
- package/dist/core/menu.js +12 -5
- package/dist/core/menu.js.map +1 -1
- package/dist/core/ui.d.ts.map +1 -1
- package/dist/core/ui.js +5 -3
- package/dist/core/ui.js.map +1 -1
- package/dist/features/calendar.d.ts +13 -14
- package/dist/features/calendar.d.ts.map +1 -1
- package/dist/features/calendar.js +57 -59
- package/dist/features/calendar.js.map +1 -1
- package/dist/features/docs.d.ts.map +1 -1
- package/dist/features/docs.js +50 -47
- package/dist/features/docs.js.map +1 -1
- package/dist/features/repair.d.ts +4 -0
- package/dist/features/repair.d.ts.map +1 -1
- package/dist/features/repair.js +1 -1
- package/dist/features/repair.js.map +1 -1
- package/dist/features/website.d.ts +10 -0
- package/dist/features/website.d.ts.map +1 -1
- package/dist/features/website.js +14 -2
- package/dist/features/website.js.map +1 -1
- package/dist/i18n/index.d.ts +9 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js.map +1 -1
- package/dist/i18n/locales/en.json +10 -1
- package/dist/i18n/locales/zh.json +10 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +133 -4
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +4 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -3
- package/dist/main.js.map +1 -1
- package/package.json +8 -2
- package/.github/workflows/ci.yml +0 -40
- package/.github/workflows/publish.yml +0 -59
- package/CHANGELOG.md +0 -125
- package/DEVELOPMENT.md +0 -258
- package/TERMINAL_UX.md +0 -184
- package/assets/Prompt_demo.gif +0 -0
- package/src/config/data.js +0 -484
- package/src/config/data.ts +0 -28
- package/src/config/theme.js +0 -138
- package/src/config/theme.ts +0 -26
- package/src/core/logo.ts +0 -189
- package/src/core/menu.ts +0 -213
- package/src/core/ui.ts +0 -89
- package/src/core/vim-keys.ts +0 -70
- package/src/features/calendar.ts +0 -161
- package/src/features/docs.ts +0 -588
- package/src/features/repair.ts +0 -36
- package/src/features/website.ts +0 -45
- package/src/i18n/index.ts +0 -236
- package/src/i18n/locales/en.json +0 -107
- package/src/i18n/locales/zh.json +0 -107
- package/src/index.ts +0 -9
- package/src/logo/ascii-logo.txt +0 -6
- package/src/logo/logo.txt +0 -2
- package/src/logo/printLogo.js +0 -26
- package/src/main.ts +0 -45
- package/src/types.ts +0 -51
- package/tsconfig.json +0 -53
package/src/core/logo.ts
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Smart logo display module
|
|
3
|
-
* Attempts to display iTerm2 image format logo, falls back to ASCII art
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { readFileSync } from 'fs';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { dirname, join } from 'path';
|
|
9
|
-
import gradient from 'gradient-string';
|
|
10
|
-
|
|
11
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
-
const __dirname = dirname(__filename);
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Create blue-toned gradient effect
|
|
16
|
-
*/
|
|
17
|
-
function createBlueGradient(text: string): string {
|
|
18
|
-
// Blue gradient: deep blue -> sky blue -> cyan
|
|
19
|
-
const blueGradient = gradient([
|
|
20
|
-
{ color: '#1e3a8a', pos: 0 }, // Deep blue
|
|
21
|
-
{ color: '#0ea5e9', pos: 0.5 }, // Sky blue
|
|
22
|
-
{ color: '#06b6d4', pos: 1 } // Cyan
|
|
23
|
-
]);
|
|
24
|
-
return blueGradient(text);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Convert hex color to RGB
|
|
29
|
-
*/
|
|
30
|
-
function hexToRgb(hex: string): [number, number, number] {
|
|
31
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
32
|
-
return result
|
|
33
|
-
? [parseInt(result[1]!, 16), parseInt(result[2]!, 16), parseInt(result[3]!, 16)]
|
|
34
|
-
: [0, 0, 0];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Convert RGB to hex color
|
|
39
|
-
*/
|
|
40
|
-
function rgbToHex(r: number, g: number, b: number): string {
|
|
41
|
-
return '#' + [r, g, b].map(x => {
|
|
42
|
-
const hex = Math.round(x).toString(16);
|
|
43
|
-
return hex.length === 1 ? '0' + hex : hex;
|
|
44
|
-
}).join('');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Linear interpolation between two colors
|
|
49
|
-
*/
|
|
50
|
-
function interpolateColor(color1: string, color2: string, factor: number): string {
|
|
51
|
-
const [r1, g1, b1] = hexToRgb(color1);
|
|
52
|
-
const [r2, g2, b2] = hexToRgb(color2);
|
|
53
|
-
|
|
54
|
-
const r = r1 + (r2 - r1) * factor;
|
|
55
|
-
const g = g1 + (g2 - g1) * factor;
|
|
56
|
-
const b = b1 + (b2 - b1) * factor;
|
|
57
|
-
|
|
58
|
-
return rgbToHex(r, g, b);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Easing function - smooth in-out effect
|
|
63
|
-
*/
|
|
64
|
-
function easeInOutSine(t: number): number {
|
|
65
|
-
return -(Math.cos(Math.PI * t) - 1) / 2;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Display gradient animation effect (optimized - truly smooth animation)
|
|
70
|
-
*/
|
|
71
|
-
async function animateGradient(text: string, duration: number = 1200): Promise<void> {
|
|
72
|
-
const frames = 60; // 60 frames for truly smooth animation
|
|
73
|
-
const frameDelay = duration / frames;
|
|
74
|
-
|
|
75
|
-
// Define color sequence - forms complete blue spectrum cycle
|
|
76
|
-
const colorSequence = [
|
|
77
|
-
'#1e3a8a', // Deep blue
|
|
78
|
-
'#2563eb', // Blue
|
|
79
|
-
'#3b82f6', // Bright blue
|
|
80
|
-
'#0ea5e9', // Sky blue
|
|
81
|
-
'#06b6d4', // Cyan
|
|
82
|
-
'#14b8a6', // Teal
|
|
83
|
-
'#06b6d4', // Cyan
|
|
84
|
-
'#0ea5e9', // Sky blue
|
|
85
|
-
'#3b82f6', // Bright blue
|
|
86
|
-
'#2563eb', // Blue
|
|
87
|
-
'#1e3a8a', // Deep blue
|
|
88
|
-
];
|
|
89
|
-
|
|
90
|
-
for (let i = 0; i < frames; i++) {
|
|
91
|
-
// Use smooth sine easing
|
|
92
|
-
const progress = easeInOutSine(i / frames);
|
|
93
|
-
|
|
94
|
-
// Calculate position in color sequence
|
|
95
|
-
const position = progress * (colorSequence.length - 1);
|
|
96
|
-
const index1 = Math.floor(position);
|
|
97
|
-
const index2 = Math.min(index1 + 1, colorSequence.length - 1);
|
|
98
|
-
const localProgress = position - index1;
|
|
99
|
-
|
|
100
|
-
// Interpolate between adjacent colors, generating three smoothly transitioning colors
|
|
101
|
-
const color1 = interpolateColor(
|
|
102
|
-
colorSequence[index1]!,
|
|
103
|
-
colorSequence[index2]!,
|
|
104
|
-
localProgress
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
const nextIndex1 = Math.min(index2, colorSequence.length - 1);
|
|
108
|
-
const nextIndex2 = Math.min(nextIndex1 + 1, colorSequence.length - 1);
|
|
109
|
-
const color2 = interpolateColor(
|
|
110
|
-
colorSequence[nextIndex1]!,
|
|
111
|
-
colorSequence[nextIndex2]!,
|
|
112
|
-
localProgress
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const nextIndex3 = Math.min(nextIndex2, colorSequence.length - 1);
|
|
116
|
-
const nextIndex4 = Math.min(nextIndex3 + 1, colorSequence.length - 1);
|
|
117
|
-
const color3 = interpolateColor(
|
|
118
|
-
colorSequence[nextIndex3]!,
|
|
119
|
-
colorSequence[nextIndex4]!,
|
|
120
|
-
localProgress
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
// Create gradient for current frame
|
|
124
|
-
const frameGradient = gradient(color1, color2, color3);
|
|
125
|
-
|
|
126
|
-
// Clear current line and display new frame
|
|
127
|
-
process.stdout.write('\r' + frameGradient(text));
|
|
128
|
-
|
|
129
|
-
await new Promise(resolve => setTimeout(resolve, frameDelay));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Finally display static blue gradient
|
|
133
|
-
process.stdout.write('\r' + createBlueGradient(text) + '\n');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Attempt to read and display logo file
|
|
138
|
-
*/
|
|
139
|
-
export async function printLogo(): Promise<void> {
|
|
140
|
-
try {
|
|
141
|
-
// Try to read iTerm2 image format logo
|
|
142
|
-
const logoPath = join(__dirname, '../logo/logo.txt');
|
|
143
|
-
const logoContent = readFileSync(logoPath, 'utf-8');
|
|
144
|
-
|
|
145
|
-
// If successfully read and content is valid, display directly
|
|
146
|
-
if (logoContent && logoContent.length > 100) {
|
|
147
|
-
console.log(logoContent);
|
|
148
|
-
await printDescription();
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
} catch (error) {
|
|
152
|
-
// iTerm2 logo read failed, continue trying ASCII logo
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Fallback: display ASCII art logo
|
|
156
|
-
try {
|
|
157
|
-
const asciiLogoPath = join(__dirname, '../logo/ascii-logo.txt');
|
|
158
|
-
const asciiContent = readFileSync(asciiLogoPath, 'utf-8');
|
|
159
|
-
|
|
160
|
-
// Display ASCII logo with gradient colors
|
|
161
|
-
console.log();
|
|
162
|
-
const lines = asciiContent.split('\n').filter(line => line.trim());
|
|
163
|
-
lines.forEach(line => {
|
|
164
|
-
console.log(createBlueGradient(line));
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
await printDescription();
|
|
168
|
-
} catch (error) {
|
|
169
|
-
// If ASCII logo also fails, display simple text logo
|
|
170
|
-
console.log();
|
|
171
|
-
console.log(createBlueGradient(' NBTCA'));
|
|
172
|
-
await printDescription();
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Display description text (with gradient animation)
|
|
178
|
-
*/
|
|
179
|
-
async function printDescription(): Promise<void> {
|
|
180
|
-
const tagline = 'To be at the intersection of technology and liberal arts.';
|
|
181
|
-
|
|
182
|
-
console.log();
|
|
183
|
-
|
|
184
|
-
// Display gradient animation
|
|
185
|
-
await animateGradient(tagline, 1500);
|
|
186
|
-
|
|
187
|
-
console.log();
|
|
188
|
-
}
|
|
189
|
-
|
package/src/core/menu.ts
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimalist menu system
|
|
3
|
-
* Six core feature menus
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import inquirer from 'inquirer';
|
|
7
|
-
import chalk from 'chalk';
|
|
8
|
-
import { showCalendar } from '../features/calendar.js';
|
|
9
|
-
import { openRepairService } from '../features/repair.js';
|
|
10
|
-
import { showDocsMenu } from '../features/docs.js';
|
|
11
|
-
import { openHomepage, openGithub } from '../features/website.js';
|
|
12
|
-
import { printDivider, printNewLine } from './ui.js';
|
|
13
|
-
import { APP_INFO, URLS } from '../config/data.js';
|
|
14
|
-
import { t, getCurrentLanguage, setLanguage, clearTranslationCache, type Language } from '../i18n/index.js';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Get main menu options
|
|
18
|
-
*/
|
|
19
|
-
function getMainMenuOptions() {
|
|
20
|
-
const trans = t();
|
|
21
|
-
return [
|
|
22
|
-
{
|
|
23
|
-
name: '[*] ' + trans.menu.events.padEnd(16) + ' ' + chalk.gray(trans.menu.eventsDesc),
|
|
24
|
-
value: 'events',
|
|
25
|
-
short: trans.menu.events
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
name: '[*] ' + trans.menu.repair.padEnd(16) + ' ' + chalk.gray(trans.menu.repairDesc),
|
|
29
|
-
value: 'repair',
|
|
30
|
-
short: trans.menu.repair
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: '[*] ' + trans.menu.docs.padEnd(16) + ' ' + chalk.gray(trans.menu.docsDesc),
|
|
34
|
-
value: 'docs',
|
|
35
|
-
short: trans.menu.docs
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
name: '[*] ' + trans.menu.website.padEnd(16) + ' ' + chalk.gray(trans.menu.websiteDesc),
|
|
39
|
-
value: 'website',
|
|
40
|
-
short: trans.menu.website
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
name: '[*] ' + trans.menu.github.padEnd(16) + ' ' + chalk.gray(trans.menu.githubDesc),
|
|
44
|
-
value: 'github',
|
|
45
|
-
short: trans.menu.github
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: '[?] ' + trans.menu.about.padEnd(16) + ' ' + chalk.gray(trans.menu.aboutDesc),
|
|
49
|
-
value: 'about',
|
|
50
|
-
short: trans.menu.about
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
name: '[⚙] ' + trans.menu.language.padEnd(16) + ' ' + chalk.gray(trans.menu.languageDesc),
|
|
54
|
-
value: 'language',
|
|
55
|
-
short: trans.menu.language
|
|
56
|
-
},
|
|
57
|
-
new inquirer.Separator(' '),
|
|
58
|
-
{
|
|
59
|
-
name: chalk.dim('[x] ' + trans.common.exit),
|
|
60
|
-
value: 'exit',
|
|
61
|
-
short: trans.common.exit
|
|
62
|
-
}
|
|
63
|
-
];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Display main menu
|
|
68
|
-
*/
|
|
69
|
-
export async function showMainMenu(): Promise<void> {
|
|
70
|
-
while (true) {
|
|
71
|
-
try {
|
|
72
|
-
const trans = t();
|
|
73
|
-
|
|
74
|
-
// Show keybinding hints
|
|
75
|
-
console.log(chalk.dim(' ' + trans.menu.navigationHint));
|
|
76
|
-
console.log();
|
|
77
|
-
|
|
78
|
-
const { action } = await inquirer.prompt<{ action: string }>([
|
|
79
|
-
{
|
|
80
|
-
type: 'list',
|
|
81
|
-
name: 'action',
|
|
82
|
-
message: trans.menu.chooseAction,
|
|
83
|
-
choices: getMainMenuOptions(),
|
|
84
|
-
pageSize: 15,
|
|
85
|
-
loop: false
|
|
86
|
-
} as any
|
|
87
|
-
]);
|
|
88
|
-
|
|
89
|
-
// Handle user selection
|
|
90
|
-
if (action === 'exit') {
|
|
91
|
-
console.log();
|
|
92
|
-
console.log(chalk.dim(trans.common.goodbye));
|
|
93
|
-
process.exit(0);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
await handleAction(action);
|
|
97
|
-
|
|
98
|
-
// Show divider after operation
|
|
99
|
-
printNewLine();
|
|
100
|
-
printDivider();
|
|
101
|
-
printNewLine();
|
|
102
|
-
} catch (err: any) {
|
|
103
|
-
// Handle Ctrl+C exit
|
|
104
|
-
if (err.message?.includes('User force closed')) {
|
|
105
|
-
console.log();
|
|
106
|
-
console.log(chalk.dim(t().common.goodbye));
|
|
107
|
-
process.exit(0);
|
|
108
|
-
}
|
|
109
|
-
throw err;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Handle user action
|
|
116
|
-
*/
|
|
117
|
-
async function handleAction(action: string): Promise<void> {
|
|
118
|
-
switch (action) {
|
|
119
|
-
case 'events':
|
|
120
|
-
await showCalendar();
|
|
121
|
-
break;
|
|
122
|
-
|
|
123
|
-
case 'repair':
|
|
124
|
-
await openRepairService();
|
|
125
|
-
break;
|
|
126
|
-
|
|
127
|
-
case 'docs':
|
|
128
|
-
await showDocsMenu();
|
|
129
|
-
break;
|
|
130
|
-
|
|
131
|
-
case 'website':
|
|
132
|
-
await openHomepage();
|
|
133
|
-
break;
|
|
134
|
-
|
|
135
|
-
case 'github':
|
|
136
|
-
await openGithub();
|
|
137
|
-
break;
|
|
138
|
-
|
|
139
|
-
case 'about':
|
|
140
|
-
showAbout();
|
|
141
|
-
break;
|
|
142
|
-
|
|
143
|
-
case 'language':
|
|
144
|
-
await showLanguageMenu();
|
|
145
|
-
break;
|
|
146
|
-
|
|
147
|
-
default:
|
|
148
|
-
console.log(chalk.gray('Unknown action'));
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Display about information
|
|
154
|
-
*/
|
|
155
|
-
function showAbout(): void {
|
|
156
|
-
const trans = t();
|
|
157
|
-
console.log();
|
|
158
|
-
console.log(chalk.bold('>> ' + trans.about.title));
|
|
159
|
-
console.log();
|
|
160
|
-
console.log(chalk.dim(trans.about.project.padEnd(12)) + APP_INFO.name);
|
|
161
|
-
console.log(chalk.dim(trans.about.version.padEnd(12)) + `v${APP_INFO.version}`);
|
|
162
|
-
console.log(chalk.dim(trans.about.description.padEnd(12)) + APP_INFO.fullDescription);
|
|
163
|
-
console.log();
|
|
164
|
-
console.log(chalk.dim(trans.about.github.padEnd(12)) + chalk.cyan(APP_INFO.repository));
|
|
165
|
-
console.log(chalk.dim(trans.about.website.padEnd(12)) + chalk.cyan(URLS.homepage));
|
|
166
|
-
console.log(chalk.dim(trans.about.email.padEnd(12)) + chalk.cyan(URLS.email));
|
|
167
|
-
console.log();
|
|
168
|
-
console.log(chalk.dim(trans.about.features));
|
|
169
|
-
console.log(' ' + trans.about.feature1);
|
|
170
|
-
console.log(' ' + trans.about.feature2);
|
|
171
|
-
console.log(' ' + trans.about.feature3);
|
|
172
|
-
console.log(' ' + trans.about.feature4);
|
|
173
|
-
console.log();
|
|
174
|
-
console.log(chalk.dim(trans.about.license.padEnd(12)) + 'MIT License');
|
|
175
|
-
console.log(chalk.dim(trans.about.author.padEnd(12)) + 'm1ngsama');
|
|
176
|
-
console.log();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Display language selection menu
|
|
181
|
-
*/
|
|
182
|
-
async function showLanguageMenu(): Promise<void> {
|
|
183
|
-
const trans = t();
|
|
184
|
-
const currentLang = getCurrentLanguage();
|
|
185
|
-
|
|
186
|
-
console.log();
|
|
187
|
-
console.log(chalk.bold('>> ' + trans.language.title));
|
|
188
|
-
console.log();
|
|
189
|
-
console.log(chalk.dim(trans.language.currentLanguage + ': ') + chalk.cyan(trans.language[currentLang]));
|
|
190
|
-
console.log();
|
|
191
|
-
|
|
192
|
-
const { language } = await inquirer.prompt<{ language: Language }>([
|
|
193
|
-
{
|
|
194
|
-
type: 'list',
|
|
195
|
-
name: 'language',
|
|
196
|
-
message: trans.language.selectLanguage,
|
|
197
|
-
choices: [
|
|
198
|
-
{ name: trans.language.zh, value: 'zh' as Language },
|
|
199
|
-
{ name: trans.language.en, value: 'en' as Language }
|
|
200
|
-
],
|
|
201
|
-
default: currentLang
|
|
202
|
-
}
|
|
203
|
-
]);
|
|
204
|
-
|
|
205
|
-
if (language !== currentLang) {
|
|
206
|
-
setLanguage(language);
|
|
207
|
-
clearTranslationCache();
|
|
208
|
-
console.log();
|
|
209
|
-
console.log(chalk.green('✓ ' + t().language.changed));
|
|
210
|
-
console.log();
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
package/src/core/ui.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimalist UI component library
|
|
3
|
-
* Provides basic terminal UI components
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Display header title
|
|
10
|
-
*/
|
|
11
|
-
export function printHeader(title: string): void {
|
|
12
|
-
console.log(chalk.dim(title));
|
|
13
|
-
console.log();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Display divider line
|
|
18
|
-
*/
|
|
19
|
-
export function printDivider(): void {
|
|
20
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
21
|
-
console.log(chalk.dim('─'.repeat(Math.min(terminalWidth, 80))));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Display loading spinner
|
|
26
|
-
*/
|
|
27
|
-
export async function showSpinner(text: string, duration: number): Promise<void> {
|
|
28
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
29
|
-
let i = 0;
|
|
30
|
-
const startTime = Date.now();
|
|
31
|
-
|
|
32
|
-
return new Promise((resolve) => {
|
|
33
|
-
const interval = setInterval(() => {
|
|
34
|
-
process.stdout.write(`\r${chalk.cyan(frames[i])} ${text}`);
|
|
35
|
-
i = (i + 1) % frames.length;
|
|
36
|
-
|
|
37
|
-
if (Date.now() - startTime >= duration) {
|
|
38
|
-
clearInterval(interval);
|
|
39
|
-
process.stdout.write('\r' + ' '.repeat(text.length + 5) + '\r');
|
|
40
|
-
resolve();
|
|
41
|
-
}
|
|
42
|
-
}, 80);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Display success message
|
|
48
|
-
*/
|
|
49
|
-
export function success(msg: string): void {
|
|
50
|
-
console.log(chalk.green('[✓]') + ' ' + msg);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Display error message
|
|
55
|
-
*/
|
|
56
|
-
export function error(msg: string): void {
|
|
57
|
-
console.log(chalk.red('[✗]') + ' ' + msg);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Display info message
|
|
62
|
-
*/
|
|
63
|
-
export function info(msg: string): void {
|
|
64
|
-
console.log(chalk.blue('[ℹ]') + ' ' + msg);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Display warning message
|
|
69
|
-
*/
|
|
70
|
-
export function warning(msg: string): void {
|
|
71
|
-
console.log(chalk.yellow('[⚠]') + ' ' + msg);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Clear screen
|
|
76
|
-
*/
|
|
77
|
-
export function clearScreen(): void {
|
|
78
|
-
console.clear();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Print empty lines
|
|
83
|
-
*/
|
|
84
|
-
export function printNewLine(count: number = 1): void {
|
|
85
|
-
for (let i = 0; i < count; i++) {
|
|
86
|
-
console.log();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
package/src/core/vim-keys.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Vim keybindings support
|
|
3
|
-
* Intercepts and translates keyboard input for j/k/g/G/q/ESC keys
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Enable Vim key mappings for stdin
|
|
8
|
-
* Maps: j/k (down/up), g/G (home/end), q (quit), ESC (back)
|
|
9
|
-
*/
|
|
10
|
-
export function enableVimKeys() {
|
|
11
|
-
const stdin = process.stdin;
|
|
12
|
-
|
|
13
|
-
// Only enable for TTY sessions
|
|
14
|
-
if (!stdin.isTTY) {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Save original input handler
|
|
19
|
-
const originalEmit = stdin.emit.bind(stdin);
|
|
20
|
-
|
|
21
|
-
// Override emit method to intercept keyboard events
|
|
22
|
-
(stdin.emit as any) = function (event: string, ...args: any[]) {
|
|
23
|
-
if (event === 'keypress') {
|
|
24
|
-
const [, key] = args;
|
|
25
|
-
|
|
26
|
-
if (key && key.name) {
|
|
27
|
-
// j = down (mapped to down arrow)
|
|
28
|
-
if (key.name === 'j' && !key.ctrl && !key.meta) {
|
|
29
|
-
return originalEmit('keypress', null, { name: 'down' });
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// k = up (mapped to up arrow)
|
|
33
|
-
if (key.name === 'k' && !key.ctrl && !key.meta) {
|
|
34
|
-
return originalEmit('keypress', null, { name: 'up' });
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// g = jump to top (mapped to home)
|
|
38
|
-
if (key.name === 'g' && !key.shift && !key.ctrl && !key.meta) {
|
|
39
|
-
return originalEmit('keypress', null, { name: 'home' });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// G (Shift+g) = jump to bottom (mapped to end)
|
|
43
|
-
if (key.name === 'g' && key.shift) {
|
|
44
|
-
return originalEmit('keypress', null, { name: 'end' });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// ESC = back/cancel (pass through for menu handling)
|
|
48
|
-
// Note: Applications should implement back navigation for ESC
|
|
49
|
-
if (key.name === 'escape') {
|
|
50
|
-
return originalEmit('keypress', null, { name: 'escape', sequence: '\x1b' });
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// q = quit (mapped to Ctrl+C for application exit)
|
|
54
|
-
if (key.name === 'q' && !key.ctrl && !key.meta) {
|
|
55
|
-
return originalEmit('keypress', null, { name: 'c', ctrl: true });
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return originalEmit(event, ...args);
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Disable Vim key mappings
|
|
66
|
-
* Currently not implemented as we use Vim keys throughout the application
|
|
67
|
-
*/
|
|
68
|
-
export function disableVimKeys() {
|
|
69
|
-
// Not needed for current implementation
|
|
70
|
-
}
|