@tamyla/clodo-framework 2.0.9 → 2.0.11
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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [2.0.11](https://github.com/tamylaa/clodo-framework/compare/v2.0.10...v2.0.11) (2025-10-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* correct domain selection parsing in auto-discovery ([ea80443](https://github.com/tamylaa/clodo-framework/commit/ea80443bf9968d592f066e7d5d13ee47d6fde889))
|
|
7
|
+
|
|
8
|
+
## [2.0.10](https://github.com/tamylaa/clodo-framework/compare/v2.0.9...v2.0.10) (2025-10-12)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* move interactive-prompts to src/ to fix published package imports ([94fc31c](https://github.com/tamylaa/clodo-framework/commit/94fc31c0afa91c52f2073b3ab9f766693c5f68e0))
|
|
14
|
+
|
|
1
15
|
## [2.0.9](https://github.com/tamylaa/clodo-framework/compare/v2.0.8...v2.0.9) (2025-10-12)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* User input-driven configuration setup for deployment workflows
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { askChoice, askUser } from '
|
|
6
|
+
import { askChoice, askUser } from '../utils/interactive-prompts.js';
|
|
7
7
|
export class InteractiveDeploymentConfigurator {
|
|
8
8
|
/**
|
|
9
9
|
* Generate configuration from user input
|
|
@@ -387,14 +387,17 @@ export class InputCollector {
|
|
|
387
387
|
|
|
388
388
|
// Format zones for display
|
|
389
389
|
const formatted = formatZonesForDisplay(zones);
|
|
390
|
-
|
|
390
|
+
formatted.forEach((line, index) => {
|
|
391
|
+
console.log(chalk.white(` ${index + 1}. ${line}`));
|
|
392
|
+
});
|
|
391
393
|
|
|
392
394
|
// Let user select a domain
|
|
393
395
|
const selection = await this.prompt('\nSelect domain (enter number or name): ');
|
|
394
|
-
const
|
|
395
|
-
if (
|
|
396
|
+
const selectedIndex = parseZoneSelection(selection, zones);
|
|
397
|
+
if (selectedIndex === -1) {
|
|
396
398
|
throw new Error('Invalid domain selection');
|
|
397
399
|
}
|
|
400
|
+
const selectedZone = zones[selectedIndex];
|
|
398
401
|
console.log(chalk.green(`\n✓ Selected: ${selectedZone.name}`));
|
|
399
402
|
|
|
400
403
|
// Get full zone details
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
|
|
4
4
|
export { ConfigurationCacheManager } from './config-cache.js';
|
|
5
5
|
export { EnhancedSecretManager } from './secret-generator.js';
|
|
6
|
-
export { askUser, askYesNo, askChoice, closePrompts } from '
|
|
6
|
+
export { askUser, askYesNo, askChoice, closePrompts } from '../interactive-prompts.js';
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive Prompts Module
|
|
3
|
+
* Standardized user input functions for all scripts
|
|
4
|
+
*
|
|
5
|
+
* Replaces duplicate prompt code across 10+ scripts
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import readline from 'readline';
|
|
9
|
+
|
|
10
|
+
// Create readline interface (singleton)
|
|
11
|
+
let rl = null;
|
|
12
|
+
function getReadlineInterface() {
|
|
13
|
+
if (!rl) {
|
|
14
|
+
rl = readline.createInterface({
|
|
15
|
+
input: process.stdin,
|
|
16
|
+
output: process.stdout
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return rl;
|
|
20
|
+
}
|
|
21
|
+
export function askUser(question, defaultValue = null) {
|
|
22
|
+
return new Promise(resolve => {
|
|
23
|
+
const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
|
|
24
|
+
getReadlineInterface().question(prompt, answer => {
|
|
25
|
+
resolve(answer.trim() || defaultValue);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function askYesNo(question, defaultValue = 'n') {
|
|
30
|
+
return new Promise(resolve => {
|
|
31
|
+
const prompt = `${question} [y/N]: `;
|
|
32
|
+
getReadlineInterface().question(prompt, answer => {
|
|
33
|
+
const response = answer.trim().toLowerCase() || defaultValue;
|
|
34
|
+
resolve(response === 'y' || response === 'yes');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export function askChoice(question, choices, defaultIndex = 0) {
|
|
39
|
+
return new Promise(resolve => {
|
|
40
|
+
console.log(`\n${question}`);
|
|
41
|
+
choices.forEach((choice, index) => {
|
|
42
|
+
const marker = index === defaultIndex ? '>' : ' ';
|
|
43
|
+
console.log(`${marker} ${index + 1}. ${choice}`);
|
|
44
|
+
});
|
|
45
|
+
getReadlineInterface().question(`\nSelect option [1-${choices.length}]: `, answer => {
|
|
46
|
+
const choice = parseInt(answer) - 1;
|
|
47
|
+
if (isNaN(choice) || choice < 0 || choice >= choices.length) {
|
|
48
|
+
resolve(defaultIndex);
|
|
49
|
+
} else {
|
|
50
|
+
resolve(choice);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
export function askMultiChoice(question, choices, defaultIndices = []) {
|
|
56
|
+
return new Promise(resolve => {
|
|
57
|
+
console.log(`\n${question}`);
|
|
58
|
+
console.log('(Enter comma-separated numbers, e.g., "1,3,5")');
|
|
59
|
+
choices.forEach((choice, index) => {
|
|
60
|
+
const marker = defaultIndices.includes(index) ? '>' : ' ';
|
|
61
|
+
console.log(`${marker} ${index + 1}. ${choice}`);
|
|
62
|
+
});
|
|
63
|
+
const defaultStr = defaultIndices.map(i => i + 1).join(',');
|
|
64
|
+
getReadlineInterface().question(`\nSelect options [${defaultStr}]: `, answer => {
|
|
65
|
+
if (!answer.trim()) {
|
|
66
|
+
resolve(defaultIndices);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const selected = answer.split(',').map(s => parseInt(s.trim()) - 1).filter(i => !isNaN(i) && i >= 0 && i < choices.length);
|
|
70
|
+
resolve(selected.length > 0 ? selected : defaultIndices);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export function closePrompts() {
|
|
75
|
+
if (rl) {
|
|
76
|
+
rl.close();
|
|
77
|
+
rl = null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Utility function for progress indicators
|
|
82
|
+
export function showProgress(message, steps = ['⏳', '⚡', '✅']) {
|
|
83
|
+
return new Promise(resolve => {
|
|
84
|
+
let stepIndex = 0;
|
|
85
|
+
const interval = setInterval(() => {
|
|
86
|
+
process.stdout.write(`\r${steps[stepIndex]} ${message}`);
|
|
87
|
+
stepIndex = (stepIndex + 1) % steps.length;
|
|
88
|
+
}, 500);
|
|
89
|
+
|
|
90
|
+
// Auto-resolve after 2 seconds or when manually resolved
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
clearInterval(interval);
|
|
93
|
+
process.stdout.write(`\r✅ ${message}\n`);
|
|
94
|
+
resolve();
|
|
95
|
+
}, 2000);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Ask for sensitive input (like API tokens) with hidden input
|
|
101
|
+
*/
|
|
102
|
+
export function askPassword(question) {
|
|
103
|
+
return new Promise(resolve => {
|
|
104
|
+
const prompt = `${question}: `;
|
|
105
|
+
process.stdout.write(prompt);
|
|
106
|
+
|
|
107
|
+
// Hide input for sensitive data
|
|
108
|
+
process.stdin.setRawMode(true);
|
|
109
|
+
process.stdin.resume();
|
|
110
|
+
let password = '';
|
|
111
|
+
const onData = char => {
|
|
112
|
+
const charCode = char[0];
|
|
113
|
+
if (charCode === 13) {
|
|
114
|
+
// Enter key
|
|
115
|
+
process.stdin.setRawMode(false);
|
|
116
|
+
process.stdin.pause();
|
|
117
|
+
process.stdin.removeListener('data', onData);
|
|
118
|
+
process.stdout.write('\n');
|
|
119
|
+
resolve(password);
|
|
120
|
+
} else if (charCode === 127 || charCode === 8) {
|
|
121
|
+
// Backspace
|
|
122
|
+
if (password.length > 0) {
|
|
123
|
+
password = password.slice(0, -1);
|
|
124
|
+
process.stdout.write('\b \b');
|
|
125
|
+
}
|
|
126
|
+
} else if (charCode >= 32 && charCode <= 126) {
|
|
127
|
+
// Printable characters
|
|
128
|
+
password += char.toString();
|
|
129
|
+
process.stdout.write('*');
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
process.stdin.on('data', onData);
|
|
133
|
+
});
|
|
134
|
+
}
|