commandmate 0.1.6 → 0.1.7
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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +1 -1
- package/.next/build-manifest.json +2 -2
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/config.json +3 -3
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/1.pack +0 -0
- package/.next/cache/webpack/client-production/2.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +1 -1
- package/.next/server/app-paths-manifest.json +6 -6
- package/.next/server/functions-config-manifest.json +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/trace +5 -5
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +143 -27
- package/dist/cli/types/index.d.ts +18 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/utils/env-setup.d.ts +25 -0
- package/dist/cli/utils/env-setup.d.ts.map +1 -1
- package/dist/cli/utils/env-setup.js +56 -1
- package/dist/cli/utils/prompt.d.ts +68 -0
- package/dist/cli/utils/prompt.d.ts.map +1 -0
- package/dist/cli/utils/prompt.js +208 -0
- package/package.json +1 -1
- /package/.next/static/{pQTquVjewvoJa7BML07ip → 3jNZMmFnQhc5G7met-OU4}/_buildManifest.js +0 -0
- /package/.next/static/{pQTquVjewvoJa7BML07ip → 3jNZMmFnQhc5G7met-OU4}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,WAAW,EAAuB,MAAM,UAAU,CAAC;AAuI5D;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAyIrE"}
|
|
@@ -2,18 +2,120 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Init Command
|
|
4
4
|
* Issue #96: npm install CLI support
|
|
5
|
+
* Issue #119: Interactive init support
|
|
5
6
|
* Initialize CommandMate configuration
|
|
6
7
|
*/
|
|
7
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
9
|
exports.initCommand = initCommand;
|
|
9
|
-
const
|
|
10
|
+
const fs_1 = require("fs");
|
|
10
11
|
const os_1 = require("os");
|
|
11
12
|
const types_1 = require("../types");
|
|
12
13
|
const logger_1 = require("../utils/logger");
|
|
13
14
|
const preflight_1 = require("../utils/preflight");
|
|
14
15
|
const env_setup_1 = require("../utils/env-setup");
|
|
16
|
+
const prompt_1 = require("../utils/prompt");
|
|
15
17
|
const security_logger_1 = require("../utils/security-logger");
|
|
16
18
|
const logger = new logger_1.CLILogger();
|
|
19
|
+
/**
|
|
20
|
+
* Create default configuration (non-interactive mode)
|
|
21
|
+
*/
|
|
22
|
+
function createDefaultConfig() {
|
|
23
|
+
return {
|
|
24
|
+
CM_ROOT_DIR: (0, env_setup_1.sanitizePath)(process.env.CM_ROOT_DIR || env_setup_1.DEFAULT_ROOT_DIR),
|
|
25
|
+
CM_PORT: env_setup_1.ENV_DEFAULTS.CM_PORT,
|
|
26
|
+
CM_BIND: env_setup_1.ENV_DEFAULTS.CM_BIND,
|
|
27
|
+
CM_DB_PATH: env_setup_1.ENV_DEFAULTS.CM_DB_PATH,
|
|
28
|
+
CM_LOG_LEVEL: env_setup_1.ENV_DEFAULTS.CM_LOG_LEVEL,
|
|
29
|
+
CM_LOG_FORMAT: env_setup_1.ENV_DEFAULTS.CM_LOG_FORMAT,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Prompt user for configuration (interactive mode)
|
|
34
|
+
* Issue #119: Interactive init support
|
|
35
|
+
*/
|
|
36
|
+
async function promptForConfig() {
|
|
37
|
+
logger.info('--- Required Settings ---');
|
|
38
|
+
logger.blank();
|
|
39
|
+
// CM_ROOT_DIR
|
|
40
|
+
const rootDirInput = await (0, prompt_1.prompt)('Repository root directory (CM_ROOT_DIR)', {
|
|
41
|
+
default: env_setup_1.DEFAULT_ROOT_DIR.replace((0, os_1.homedir)(), '~'),
|
|
42
|
+
});
|
|
43
|
+
const rootDir = (0, prompt_1.resolvePath)(rootDirInput || env_setup_1.DEFAULT_ROOT_DIR);
|
|
44
|
+
// Check if path exists
|
|
45
|
+
if (!(0, fs_1.existsSync)(rootDir)) {
|
|
46
|
+
logger.warn(`Directory does not exist: ${rootDir}`);
|
|
47
|
+
const createDir = await (0, prompt_1.confirm)('Directory will be validated when adding repositories. Continue?', {
|
|
48
|
+
default: true,
|
|
49
|
+
});
|
|
50
|
+
if (!createDir) {
|
|
51
|
+
throw new Error('Setup cancelled by user');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
logger.blank();
|
|
55
|
+
logger.info('--- Server Settings ---');
|
|
56
|
+
logger.blank();
|
|
57
|
+
// CM_PORT
|
|
58
|
+
const portInput = await (0, prompt_1.prompt)('Server port (CM_PORT)', {
|
|
59
|
+
default: String(env_setup_1.ENV_DEFAULTS.CM_PORT),
|
|
60
|
+
validate: prompt_1.validatePort,
|
|
61
|
+
});
|
|
62
|
+
const port = parseInt(portInput || String(env_setup_1.ENV_DEFAULTS.CM_PORT), 10);
|
|
63
|
+
// External access
|
|
64
|
+
const enableExternal = await (0, prompt_1.confirm)('Enable external access (bind to 0.0.0.0)?', {
|
|
65
|
+
default: false,
|
|
66
|
+
});
|
|
67
|
+
let bind = env_setup_1.ENV_DEFAULTS.CM_BIND;
|
|
68
|
+
let authToken;
|
|
69
|
+
if (enableExternal) {
|
|
70
|
+
bind = '0.0.0.0';
|
|
71
|
+
const envSetup = new env_setup_1.EnvSetup();
|
|
72
|
+
authToken = envSetup.generateAuthToken();
|
|
73
|
+
logger.blank();
|
|
74
|
+
logger.success('External access enabled');
|
|
75
|
+
logger.info(` Bind address: 0.0.0.0`);
|
|
76
|
+
logger.info(` Auth token generated: ${authToken.substring(0, 8)}...`);
|
|
77
|
+
}
|
|
78
|
+
// CM_DB_PATH
|
|
79
|
+
const dbPathInput = await (0, prompt_1.prompt)('Database path (CM_DB_PATH)', {
|
|
80
|
+
default: env_setup_1.ENV_DEFAULTS.CM_DB_PATH,
|
|
81
|
+
});
|
|
82
|
+
const dbPath = dbPathInput || env_setup_1.ENV_DEFAULTS.CM_DB_PATH;
|
|
83
|
+
return {
|
|
84
|
+
CM_ROOT_DIR: rootDir,
|
|
85
|
+
CM_PORT: port,
|
|
86
|
+
CM_BIND: bind,
|
|
87
|
+
CM_AUTH_TOKEN: authToken,
|
|
88
|
+
CM_DB_PATH: dbPath,
|
|
89
|
+
CM_LOG_LEVEL: env_setup_1.ENV_DEFAULTS.CM_LOG_LEVEL,
|
|
90
|
+
CM_LOG_FORMAT: env_setup_1.ENV_DEFAULTS.CM_LOG_FORMAT,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Display configuration summary
|
|
95
|
+
* Issue #119: Show settings after configuration
|
|
96
|
+
*/
|
|
97
|
+
function displayConfigSummary(config, envPath) {
|
|
98
|
+
logger.blank();
|
|
99
|
+
logger.info('==================================');
|
|
100
|
+
logger.info('Configuration Summary');
|
|
101
|
+
logger.info('==================================');
|
|
102
|
+
logger.blank();
|
|
103
|
+
logger.info(` CM_ROOT_DIR: ${config.CM_ROOT_DIR}`);
|
|
104
|
+
logger.info(` CM_PORT: ${config.CM_PORT}`);
|
|
105
|
+
logger.info(` CM_BIND: ${config.CM_BIND}`);
|
|
106
|
+
if (config.CM_AUTH_TOKEN) {
|
|
107
|
+
logger.info(` CM_AUTH_TOKEN: ${config.CM_AUTH_TOKEN.substring(0, 8)}... (generated)`);
|
|
108
|
+
}
|
|
109
|
+
logger.info(` CM_DB_PATH: ${config.CM_DB_PATH}`);
|
|
110
|
+
logger.blank();
|
|
111
|
+
logger.info(` Config file: ${envPath}`);
|
|
112
|
+
logger.blank();
|
|
113
|
+
if (config.CM_AUTH_TOKEN) {
|
|
114
|
+
logger.warn('IMPORTANT: Save your auth token securely!');
|
|
115
|
+
logger.info(` Token: ${config.CM_AUTH_TOKEN}`);
|
|
116
|
+
logger.blank();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
17
119
|
/**
|
|
18
120
|
* Execute init command
|
|
19
121
|
*/
|
|
@@ -53,19 +155,30 @@ async function initCommand(options) {
|
|
|
53
155
|
logger.blank();
|
|
54
156
|
logger.success('All required dependencies found');
|
|
55
157
|
logger.blank();
|
|
56
|
-
// Step 2:
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
158
|
+
// Step 2: Get environment path
|
|
159
|
+
const envPath = (0, env_setup_1.getEnvPath)();
|
|
160
|
+
const envSetup = new env_setup_1.EnvSetup(envPath);
|
|
161
|
+
// Backup existing .env if force mode
|
|
162
|
+
if (options.force) {
|
|
163
|
+
const backupPath = await envSetup.backupExisting();
|
|
164
|
+
if (backupPath) {
|
|
165
|
+
logger.info(`Backed up existing .env to ${backupPath}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Step 3: Create configuration
|
|
169
|
+
let config;
|
|
170
|
+
// Determine if interactive mode should be used
|
|
171
|
+
// Use interactive mode if:
|
|
172
|
+
// - Not using --defaults flag
|
|
173
|
+
// - Running in a TTY (interactive terminal)
|
|
174
|
+
const useInteractive = !options.defaults && (0, prompt_1.isInteractive)();
|
|
175
|
+
if (useInteractive) {
|
|
176
|
+
config = await promptForConfig();
|
|
177
|
+
(0, prompt_1.closeReadline)(); // Close readline after prompts
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
config = createDefaultConfig();
|
|
181
|
+
}
|
|
69
182
|
// Validate configuration
|
|
70
183
|
const validationResult = envSetup.validateConfig(config);
|
|
71
184
|
if (!validationResult.valid) {
|
|
@@ -82,37 +195,40 @@ async function initCommand(options) {
|
|
|
82
195
|
process.exit(types_1.ExitCode.CONFIG_ERROR);
|
|
83
196
|
return;
|
|
84
197
|
}
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
logger.info(`Backed up existing .env to ${backupPath}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
// Create .env file
|
|
198
|
+
// Step 4: Create .env file
|
|
199
|
+
logger.blank();
|
|
200
|
+
logger.info('--- Generating .env ---');
|
|
201
|
+
logger.blank();
|
|
93
202
|
logger.info('Creating .env file...');
|
|
94
203
|
await envSetup.createEnvFile(config, { force: options.force });
|
|
95
204
|
logger.success('.env file created');
|
|
96
|
-
// Step
|
|
205
|
+
// Step 5: Initialize database message
|
|
97
206
|
logger.info('Initializing database...');
|
|
98
207
|
// Note: Database initialization is handled by the server on startup
|
|
99
208
|
logger.success('Database will be initialized on first server start');
|
|
100
|
-
|
|
209
|
+
// Display configuration summary
|
|
210
|
+
displayConfigSummary(config, envPath);
|
|
101
211
|
logger.success('CommandMate initialized successfully!');
|
|
102
212
|
logger.blank();
|
|
103
213
|
logger.info('Next steps:');
|
|
104
|
-
|
|
105
|
-
|
|
214
|
+
if (!useInteractive) {
|
|
215
|
+
logger.info(' 1. Edit .env to customize your configuration');
|
|
216
|
+
logger.info(' 2. Run "commandmate start" to start the server');
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
logger.info(' 1. Run "commandmate start" to start the server');
|
|
220
|
+
}
|
|
106
221
|
logger.blank();
|
|
107
222
|
(0, security_logger_1.logSecurityEvent)({
|
|
108
223
|
timestamp: new Date().toISOString(),
|
|
109
224
|
command: 'init',
|
|
110
225
|
action: 'success',
|
|
111
|
-
details:
|
|
226
|
+
details: `Configuration initialized (interactive: ${useInteractive})`,
|
|
112
227
|
});
|
|
113
228
|
process.exit(types_1.ExitCode.SUCCESS);
|
|
114
229
|
}
|
|
115
230
|
catch (error) {
|
|
231
|
+
(0, prompt_1.closeReadline)(); // Ensure readline is closed on error
|
|
116
232
|
const message = error instanceof Error ? error.message : String(error);
|
|
117
233
|
logger.error(`Initialization failed: ${message}`);
|
|
118
234
|
(0, security_logger_1.logSecurityEvent)({
|
|
@@ -121,4 +121,22 @@ export interface ValidationResult {
|
|
|
121
121
|
valid: boolean;
|
|
122
122
|
errors: string[];
|
|
123
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Options for prompt function
|
|
126
|
+
* Issue #119: Interactive init support
|
|
127
|
+
*/
|
|
128
|
+
export interface PromptOptions {
|
|
129
|
+
/** Default value if user presses Enter */
|
|
130
|
+
default?: string;
|
|
131
|
+
/** Validation function - returns error message or true if valid */
|
|
132
|
+
validate?: (input: string) => string | true;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Options for confirm function
|
|
136
|
+
* Issue #119: Interactive init support
|
|
137
|
+
*/
|
|
138
|
+
export interface ConfirmOptions {
|
|
139
|
+
/** Default value if user presses Enter (true = Y, false = N) */
|
|
140
|
+
default?: boolean;
|
|
141
|
+
}
|
|
124
142
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,oBAAY,QAAQ;IAClB,OAAO,IAAI;IACX,gBAAgB,IAAI;IACpB,YAAY,IAAI;IAChB,YAAY,IAAI;IAChB,WAAW,IAAI;IACf,gBAAgB,KAAK;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,EAAE,OAAO,CAAC;IAClB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,kBAAkB,CAAC;IAC9C,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/types/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,oBAAY,QAAQ;IAClB,OAAO,IAAI;IACX,gBAAgB,IAAI;IACpB,YAAY,IAAI;IAChB,YAAY,IAAI;IAChB,WAAW,IAAI;IACf,gBAAgB,KAAK;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,wBAAwB;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,QAAQ,EAAE,OAAO,CAAC;IAClB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,kBAAkB,CAAC;IAC9C,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,OAAO,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,gEAAgE;IAChE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB"}
|
|
@@ -15,6 +15,31 @@ export declare const ENV_DEFAULTS: {
|
|
|
15
15
|
readonly CM_LOG_LEVEL: "info";
|
|
16
16
|
readonly CM_LOG_FORMAT: "text";
|
|
17
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Default root directory for worktrees
|
|
20
|
+
*/
|
|
21
|
+
export declare const DEFAULT_ROOT_DIR: string;
|
|
22
|
+
/**
|
|
23
|
+
* Check if running as global npm package
|
|
24
|
+
* Issue #119: Determine .env location based on install type
|
|
25
|
+
*
|
|
26
|
+
* @returns true if running as global npm package
|
|
27
|
+
*/
|
|
28
|
+
export declare function isGlobalInstall(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Get the path to .env file based on install type
|
|
31
|
+
* Issue #119: Global install uses ~/.commandmate/, local uses cwd
|
|
32
|
+
*
|
|
33
|
+
* @returns Path to .env file
|
|
34
|
+
*/
|
|
35
|
+
export declare function getEnvPath(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Get the config directory path
|
|
38
|
+
* Issue #119: Returns ~/.commandmate for global, cwd for local
|
|
39
|
+
*
|
|
40
|
+
* @returns Path to config directory
|
|
41
|
+
*/
|
|
42
|
+
export declare function getConfigDir(): string;
|
|
18
43
|
/**
|
|
19
44
|
* Sanitize input by removing control characters
|
|
20
45
|
* SF-SEC-3: Input sanitization
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-setup.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/env-setup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"env-setup.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/env-setup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,EACL,SAAS,EACT,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAA2B,CAAC;AAEzD;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAYzC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAcnC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAKrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAUpD;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,CAAC,EAAE,MAAM;IAI5B;;;OAGG;IACG,aAAa,CACjB,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAiChB;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAY9C;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB;CAoCpD"}
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* Migrated from scripts/setup-env.sh
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.EnvSetup = exports.ENV_DEFAULTS = void 0;
|
|
8
|
+
exports.EnvSetup = exports.DEFAULT_ROOT_DIR = exports.ENV_DEFAULTS = void 0;
|
|
9
|
+
exports.isGlobalInstall = isGlobalInstall;
|
|
10
|
+
exports.getEnvPath = getEnvPath;
|
|
11
|
+
exports.getConfigDir = getConfigDir;
|
|
9
12
|
exports.sanitizeInput = sanitizeInput;
|
|
10
13
|
exports.sanitizePath = sanitizePath;
|
|
11
14
|
exports.validatePort = validatePort;
|
|
@@ -13,6 +16,7 @@ exports.escapeEnvValue = escapeEnvValue;
|
|
|
13
16
|
const fs_1 = require("fs");
|
|
14
17
|
const path_1 = require("path");
|
|
15
18
|
const crypto_1 = require("crypto");
|
|
19
|
+
const os_1 = require("os");
|
|
16
20
|
/**
|
|
17
21
|
* Default environment configuration values
|
|
18
22
|
* SF-4: DRY - Centralized defaults
|
|
@@ -24,6 +28,57 @@ exports.ENV_DEFAULTS = {
|
|
|
24
28
|
CM_LOG_LEVEL: 'info',
|
|
25
29
|
CM_LOG_FORMAT: 'text',
|
|
26
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Default root directory for worktrees
|
|
33
|
+
*/
|
|
34
|
+
exports.DEFAULT_ROOT_DIR = (0, path_1.join)((0, os_1.homedir)(), 'repos');
|
|
35
|
+
/**
|
|
36
|
+
* Check if running as global npm package
|
|
37
|
+
* Issue #119: Determine .env location based on install type
|
|
38
|
+
*
|
|
39
|
+
* @returns true if running as global npm package
|
|
40
|
+
*/
|
|
41
|
+
function isGlobalInstall() {
|
|
42
|
+
// Check if running from global node_modules
|
|
43
|
+
// Global installs typically have paths like:
|
|
44
|
+
// - /usr/local/lib/node_modules/
|
|
45
|
+
// - /Users/xxx/.npm-global/lib/node_modules/
|
|
46
|
+
// - C:\Users\xxx\AppData\Roaming\npm\node_modules\
|
|
47
|
+
const currentPath = (0, path_1.dirname)(__dirname);
|
|
48
|
+
return (currentPath.includes('/lib/node_modules/') ||
|
|
49
|
+
currentPath.includes('\\node_modules\\') ||
|
|
50
|
+
currentPath.includes('/node_modules/commandmate'));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get the path to .env file based on install type
|
|
54
|
+
* Issue #119: Global install uses ~/.commandmate/, local uses cwd
|
|
55
|
+
*
|
|
56
|
+
* @returns Path to .env file
|
|
57
|
+
*/
|
|
58
|
+
function getEnvPath() {
|
|
59
|
+
if (isGlobalInstall()) {
|
|
60
|
+
const configDir = (0, path_1.join)((0, os_1.homedir)(), '.commandmate');
|
|
61
|
+
// Create config directory if it doesn't exist
|
|
62
|
+
if (!(0, fs_1.existsSync)(configDir)) {
|
|
63
|
+
(0, fs_1.mkdirSync)(configDir, { recursive: true, mode: 0o700 });
|
|
64
|
+
}
|
|
65
|
+
return (0, path_1.join)(configDir, '.env');
|
|
66
|
+
}
|
|
67
|
+
// Local install - use current working directory
|
|
68
|
+
return (0, path_1.join)(process.cwd(), '.env');
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the config directory path
|
|
72
|
+
* Issue #119: Returns ~/.commandmate for global, cwd for local
|
|
73
|
+
*
|
|
74
|
+
* @returns Path to config directory
|
|
75
|
+
*/
|
|
76
|
+
function getConfigDir() {
|
|
77
|
+
if (isGlobalInstall()) {
|
|
78
|
+
return (0, path_1.join)((0, os_1.homedir)(), '.commandmate');
|
|
79
|
+
}
|
|
80
|
+
return process.cwd();
|
|
81
|
+
}
|
|
27
82
|
/**
|
|
28
83
|
* Sanitize input by removing control characters
|
|
29
84
|
* SF-SEC-3: Input sanitization
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive Prompt Utilities
|
|
3
|
+
* Issue #119: Interactive init support
|
|
4
|
+
*
|
|
5
|
+
* Provides readline-based prompts for CLI commands.
|
|
6
|
+
* Reference implementation: scripts/setup-env.sh
|
|
7
|
+
*/
|
|
8
|
+
import { PromptOptions, ConfirmOptions } from '../types';
|
|
9
|
+
/**
|
|
10
|
+
* Close readline interface
|
|
11
|
+
* Should be called when all prompts are done
|
|
12
|
+
*/
|
|
13
|
+
export declare function closeReadline(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Expand tilde (~) to home directory
|
|
16
|
+
*
|
|
17
|
+
* @param path - Path that may contain tilde
|
|
18
|
+
* @returns Path with tilde expanded to home directory
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* expandTilde('~/repos') // '/Users/xxx/repos'
|
|
22
|
+
* expandTilde('/absolute/path') // '/absolute/path'
|
|
23
|
+
*/
|
|
24
|
+
export declare function expandTilde(path: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Resolve path to absolute path
|
|
27
|
+
* Handles tilde expansion and relative paths
|
|
28
|
+
*
|
|
29
|
+
* @param path - Path to resolve
|
|
30
|
+
* @returns Absolute path
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolvePath(path: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Validate port number
|
|
35
|
+
*
|
|
36
|
+
* @param input - Port number as string
|
|
37
|
+
* @returns Error message or true if valid
|
|
38
|
+
*/
|
|
39
|
+
export declare function validatePort(input: string): string | true;
|
|
40
|
+
/**
|
|
41
|
+
* Interactive prompt with default value and validation
|
|
42
|
+
*
|
|
43
|
+
* @param question - Question to display
|
|
44
|
+
* @param options - Prompt options (default, validate)
|
|
45
|
+
* @returns User input or default value
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* const port = await prompt('Server port', { default: '3000', validate: validatePort });
|
|
49
|
+
*/
|
|
50
|
+
export declare function prompt(question: string, options?: PromptOptions): Promise<string>;
|
|
51
|
+
/**
|
|
52
|
+
* Interactive Yes/No confirmation
|
|
53
|
+
*
|
|
54
|
+
* @param question - Question to display
|
|
55
|
+
* @param options - Confirm options (default)
|
|
56
|
+
* @returns true for Yes, false for No
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const enableExternal = await confirm('Enable external access?', { default: false });
|
|
60
|
+
*/
|
|
61
|
+
export declare function confirm(question: string, options?: ConfirmOptions): Promise<boolean>;
|
|
62
|
+
/**
|
|
63
|
+
* Check if running in interactive mode (TTY)
|
|
64
|
+
*
|
|
65
|
+
* @returns true if stdin is a TTY (interactive terminal)
|
|
66
|
+
*/
|
|
67
|
+
export declare function isInteractive(): boolean;
|
|
68
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/prompt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAqBzD;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASzD;AAED;;;;;;;;;GASG;AACH,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,OAAO,CAAC,CAmClB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Interactive Prompt Utilities
|
|
4
|
+
* Issue #119: Interactive init support
|
|
5
|
+
*
|
|
6
|
+
* Provides readline-based prompts for CLI commands.
|
|
7
|
+
* Reference implementation: scripts/setup-env.sh
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.closeReadline = closeReadline;
|
|
44
|
+
exports.expandTilde = expandTilde;
|
|
45
|
+
exports.resolvePath = resolvePath;
|
|
46
|
+
exports.validatePort = validatePort;
|
|
47
|
+
exports.prompt = prompt;
|
|
48
|
+
exports.confirm = confirm;
|
|
49
|
+
exports.isInteractive = isInteractive;
|
|
50
|
+
const readline = __importStar(require("readline"));
|
|
51
|
+
const os_1 = require("os");
|
|
52
|
+
const path_1 = require("path");
|
|
53
|
+
/**
|
|
54
|
+
* Readline interface singleton
|
|
55
|
+
* Reused across prompts to avoid creating multiple interfaces
|
|
56
|
+
*/
|
|
57
|
+
let rlInstance = null;
|
|
58
|
+
/**
|
|
59
|
+
* Get or create readline interface
|
|
60
|
+
*/
|
|
61
|
+
function getReadlineInterface() {
|
|
62
|
+
if (!rlInstance) {
|
|
63
|
+
rlInstance = readline.createInterface({
|
|
64
|
+
input: process.stdin,
|
|
65
|
+
output: process.stdout,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return rlInstance;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Close readline interface
|
|
72
|
+
* Should be called when all prompts are done
|
|
73
|
+
*/
|
|
74
|
+
function closeReadline() {
|
|
75
|
+
if (rlInstance) {
|
|
76
|
+
rlInstance.close();
|
|
77
|
+
rlInstance = null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Expand tilde (~) to home directory
|
|
82
|
+
*
|
|
83
|
+
* @param path - Path that may contain tilde
|
|
84
|
+
* @returns Path with tilde expanded to home directory
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* expandTilde('~/repos') // '/Users/xxx/repos'
|
|
88
|
+
* expandTilde('/absolute/path') // '/absolute/path'
|
|
89
|
+
*/
|
|
90
|
+
function expandTilde(path) {
|
|
91
|
+
if (path.startsWith('~/')) {
|
|
92
|
+
return path.replace(/^~/, (0, os_1.homedir)());
|
|
93
|
+
}
|
|
94
|
+
if (path === '~') {
|
|
95
|
+
return (0, os_1.homedir)();
|
|
96
|
+
}
|
|
97
|
+
return path;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Resolve path to absolute path
|
|
101
|
+
* Handles tilde expansion and relative paths
|
|
102
|
+
*
|
|
103
|
+
* @param path - Path to resolve
|
|
104
|
+
* @returns Absolute path
|
|
105
|
+
*/
|
|
106
|
+
function resolvePath(path) {
|
|
107
|
+
const expanded = expandTilde(path);
|
|
108
|
+
return (0, path_1.resolve)(expanded);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validate port number
|
|
112
|
+
*
|
|
113
|
+
* @param input - Port number as string
|
|
114
|
+
* @returns Error message or true if valid
|
|
115
|
+
*/
|
|
116
|
+
function validatePort(input) {
|
|
117
|
+
const port = parseInt(input, 10);
|
|
118
|
+
if (isNaN(port)) {
|
|
119
|
+
return 'Port must be a number';
|
|
120
|
+
}
|
|
121
|
+
if (port < 1 || port > 65535) {
|
|
122
|
+
return 'Port must be between 1 and 65535';
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Interactive prompt with default value and validation
|
|
128
|
+
*
|
|
129
|
+
* @param question - Question to display
|
|
130
|
+
* @param options - Prompt options (default, validate)
|
|
131
|
+
* @returns User input or default value
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* const port = await prompt('Server port', { default: '3000', validate: validatePort });
|
|
135
|
+
*/
|
|
136
|
+
async function prompt(question, options = {}) {
|
|
137
|
+
const rl = getReadlineInterface();
|
|
138
|
+
const { default: defaultValue, validate } = options;
|
|
139
|
+
const displayQuestion = defaultValue
|
|
140
|
+
? `? ${question} [${defaultValue}]: `
|
|
141
|
+
: `? ${question}: `;
|
|
142
|
+
return new Promise((resolvePromise) => {
|
|
143
|
+
const askQuestion = () => {
|
|
144
|
+
rl.question(displayQuestion, (answer) => {
|
|
145
|
+
const trimmedAnswer = answer.trim();
|
|
146
|
+
const result = trimmedAnswer || defaultValue || '';
|
|
147
|
+
// Validate if validator provided
|
|
148
|
+
if (validate && result) {
|
|
149
|
+
const validationResult = validate(result);
|
|
150
|
+
if (validationResult !== true) {
|
|
151
|
+
console.log(` Error: ${validationResult}`);
|
|
152
|
+
askQuestion(); // Re-ask
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
resolvePromise(result);
|
|
157
|
+
});
|
|
158
|
+
};
|
|
159
|
+
askQuestion();
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Interactive Yes/No confirmation
|
|
164
|
+
*
|
|
165
|
+
* @param question - Question to display
|
|
166
|
+
* @param options - Confirm options (default)
|
|
167
|
+
* @returns true for Yes, false for No
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* const enableExternal = await confirm('Enable external access?', { default: false });
|
|
171
|
+
*/
|
|
172
|
+
async function confirm(question, options = {}) {
|
|
173
|
+
const rl = getReadlineInterface();
|
|
174
|
+
const defaultValue = options.default ?? false;
|
|
175
|
+
const hint = defaultValue ? '(Y/n)' : '(y/N)';
|
|
176
|
+
const displayQuestion = `? ${question} ${hint}: `;
|
|
177
|
+
return new Promise((resolvePromise) => {
|
|
178
|
+
const askQuestion = () => {
|
|
179
|
+
rl.question(displayQuestion, (answer) => {
|
|
180
|
+
const trimmedAnswer = answer.trim().toLowerCase();
|
|
181
|
+
if (trimmedAnswer === '') {
|
|
182
|
+
resolvePromise(defaultValue);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (trimmedAnswer === 'y' || trimmedAnswer === 'yes') {
|
|
186
|
+
resolvePromise(true);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (trimmedAnswer === 'n' || trimmedAnswer === 'no') {
|
|
190
|
+
resolvePromise(false);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
// Invalid input - re-ask
|
|
194
|
+
console.log(' Please answer with y/n or yes/no');
|
|
195
|
+
askQuestion();
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
askQuestion();
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Check if running in interactive mode (TTY)
|
|
203
|
+
*
|
|
204
|
+
* @returns true if stdin is a TTY (interactive terminal)
|
|
205
|
+
*/
|
|
206
|
+
function isInteractive() {
|
|
207
|
+
return process.stdin.isTTY === true;
|
|
208
|
+
}
|
package/package.json
CHANGED
|
File without changes
|