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.
Files changed (41) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +1 -1
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/cache/.tsbuildinfo +1 -1
  5. package/.next/cache/config.json +3 -3
  6. package/.next/cache/webpack/client-production/0.pack +0 -0
  7. package/.next/cache/webpack/client-production/1.pack +0 -0
  8. package/.next/cache/webpack/client-production/2.pack +0 -0
  9. package/.next/cache/webpack/client-production/index.pack +0 -0
  10. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  11. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  12. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  13. package/.next/cache/webpack/server-production/0.pack +0 -0
  14. package/.next/cache/webpack/server-production/index.pack +0 -0
  15. package/.next/next-server.js.nft.json +1 -1
  16. package/.next/prerender-manifest.json +1 -1
  17. package/.next/server/app/_not-found.html +1 -1
  18. package/.next/server/app/_not-found.rsc +1 -1
  19. package/.next/server/app/index.html +1 -1
  20. package/.next/server/app/index.rsc +1 -1
  21. package/.next/server/app-paths-manifest.json +6 -6
  22. package/.next/server/functions-config-manifest.json +1 -1
  23. package/.next/server/middleware-manifest.json +5 -5
  24. package/.next/server/pages/404.html +1 -1
  25. package/.next/server/pages/500.html +1 -1
  26. package/.next/server/server-reference-manifest.json +1 -1
  27. package/.next/trace +5 -5
  28. package/dist/cli/commands/init.d.ts +1 -0
  29. package/dist/cli/commands/init.d.ts.map +1 -1
  30. package/dist/cli/commands/init.js +143 -27
  31. package/dist/cli/types/index.d.ts +18 -0
  32. package/dist/cli/types/index.d.ts.map +1 -1
  33. package/dist/cli/utils/env-setup.d.ts +25 -0
  34. package/dist/cli/utils/env-setup.d.ts.map +1 -1
  35. package/dist/cli/utils/env-setup.js +56 -1
  36. package/dist/cli/utils/prompt.d.ts +68 -0
  37. package/dist/cli/utils/prompt.d.ts.map +1 -0
  38. package/dist/cli/utils/prompt.js +208 -0
  39. package/package.json +1 -1
  40. /package/.next/static/{pQTquVjewvoJa7BML07ip → 3jNZMmFnQhc5G7met-OU4}/_buildManifest.js +0 -0
  41. /package/.next/static/{pQTquVjewvoJa7BML07ip → 3jNZMmFnQhc5G7met-OU4}/_ssgManifest.js +0 -0
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Init Command
3
3
  * Issue #96: npm install CLI support
4
+ * Issue #119: Interactive init support
4
5
  * Initialize CommandMate configuration
5
6
  */
6
7
  import { InitOptions } from '../types';
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,WAAW,EAAuB,MAAM,UAAU,CAAC;AAQ5D;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HrE"}
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 path_1 = require("path");
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: Setup environment
57
- const envSetup = new env_setup_1.EnvSetup();
58
- // Create configuration
59
- const config = {
60
- CM_ROOT_DIR: options.defaults
61
- ? (0, path_1.join)((0, os_1.homedir)(), 'repos')
62
- : (0, env_setup_1.sanitizePath)(process.env.CM_ROOT_DIR || (0, path_1.join)((0, os_1.homedir)(), 'repos')),
63
- CM_PORT: env_setup_1.ENV_DEFAULTS.CM_PORT,
64
- CM_BIND: env_setup_1.ENV_DEFAULTS.CM_BIND,
65
- CM_DB_PATH: env_setup_1.ENV_DEFAULTS.CM_DB_PATH,
66
- CM_LOG_LEVEL: env_setup_1.ENV_DEFAULTS.CM_LOG_LEVEL,
67
- CM_LOG_FORMAT: env_setup_1.ENV_DEFAULTS.CM_LOG_FORMAT,
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
- // Backup existing .env if force mode
86
- if (options.force) {
87
- const backupPath = await envSetup.backupExisting();
88
- if (backupPath) {
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 3: Initialize database
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
- logger.blank();
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
- logger.info(' 1. Edit .env to customize your configuration');
105
- logger.info(' 2. Run "commandmate start" to start the server');
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: 'Configuration initialized',
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;AAUH,OAAO,EACL,SAAS,EACT,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX;;;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"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commandmate",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Git worktree management with Claude CLI and tmux sessions",
5
5
  "repository": {
6
6
  "type": "git",