commandmate 0.1.6 → 0.1.8

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 (54) 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 +7 -7
  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/commands/start.d.ts +2 -0
  32. package/dist/cli/commands/start.d.ts.map +1 -1
  33. package/dist/cli/commands/start.js +10 -8
  34. package/dist/cli/commands/status.d.ts +2 -0
  35. package/dist/cli/commands/status.d.ts.map +1 -1
  36. package/dist/cli/commands/status.js +11 -4
  37. package/dist/cli/commands/stop.d.ts +2 -0
  38. package/dist/cli/commands/stop.d.ts.map +1 -1
  39. package/dist/cli/commands/stop.js +7 -4
  40. package/dist/cli/types/index.d.ts +26 -0
  41. package/dist/cli/types/index.d.ts.map +1 -1
  42. package/dist/cli/types/index.js +14 -0
  43. package/dist/cli/utils/daemon.d.ts +3 -0
  44. package/dist/cli/utils/daemon.d.ts.map +1 -1
  45. package/dist/cli/utils/daemon.js +34 -2
  46. package/dist/cli/utils/env-setup.d.ts +43 -0
  47. package/dist/cli/utils/env-setup.d.ts.map +1 -1
  48. package/dist/cli/utils/env-setup.js +98 -1
  49. package/dist/cli/utils/prompt.d.ts +68 -0
  50. package/dist/cli/utils/prompt.d.ts.map +1 -0
  51. package/dist/cli/utils/prompt.js +208 -0
  52. package/package.json +2 -1
  53. /package/.next/static/{pQTquVjewvoJa7BML07ip → KtDmF-FzoCLvoKXEcXyU-}/_buildManifest.js +0 -0
  54. /package/.next/static/{pQTquVjewvoJa7BML07ip → KtDmF-FzoCLvoKXEcXyU-}/_ssgManifest.js +0 -0
@@ -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;AAaH,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;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CASpF;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAqBrC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;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,12 @@
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.resolveSecurePath = resolveSecurePath;
12
+ exports.getConfigDir = getConfigDir;
13
+ exports.getPidFilePath = getPidFilePath;
9
14
  exports.sanitizeInput = sanitizeInput;
10
15
  exports.sanitizePath = sanitizePath;
11
16
  exports.validatePort = validatePort;
@@ -13,6 +18,7 @@ exports.escapeEnvValue = escapeEnvValue;
13
18
  const fs_1 = require("fs");
14
19
  const path_1 = require("path");
15
20
  const crypto_1 = require("crypto");
21
+ const os_1 = require("os");
16
22
  /**
17
23
  * Default environment configuration values
18
24
  * SF-4: DRY - Centralized defaults
@@ -24,6 +30,97 @@ exports.ENV_DEFAULTS = {
24
30
  CM_LOG_LEVEL: 'info',
25
31
  CM_LOG_FORMAT: 'text',
26
32
  };
33
+ /**
34
+ * Default root directory for worktrees
35
+ */
36
+ exports.DEFAULT_ROOT_DIR = (0, path_1.join)((0, os_1.homedir)(), 'repos');
37
+ /**
38
+ * Check if running as global npm package
39
+ * Issue #119: Determine .env location based on install type
40
+ *
41
+ * @returns true if running as global npm package
42
+ */
43
+ function isGlobalInstall() {
44
+ // Check if running from global node_modules
45
+ // Global installs typically have paths like:
46
+ // - /usr/local/lib/node_modules/
47
+ // - /Users/xxx/.npm-global/lib/node_modules/
48
+ // - C:\Users\xxx\AppData\Roaming\npm\node_modules\
49
+ const currentPath = (0, path_1.dirname)(__dirname);
50
+ return (currentPath.includes('/lib/node_modules/') ||
51
+ currentPath.includes('\\node_modules\\') ||
52
+ currentPath.includes('/node_modules/commandmate'));
53
+ }
54
+ /**
55
+ * Get the path to .env file based on install type
56
+ * Issue #119: Global install uses ~/.commandmate/, local uses cwd
57
+ *
58
+ * @returns Path to .env file
59
+ */
60
+ function getEnvPath() {
61
+ if (isGlobalInstall()) {
62
+ const configDir = (0, path_1.join)((0, os_1.homedir)(), '.commandmate');
63
+ // Create config directory if it doesn't exist
64
+ if (!(0, fs_1.existsSync)(configDir)) {
65
+ (0, fs_1.mkdirSync)(configDir, { recursive: true, mode: 0o700 });
66
+ }
67
+ return (0, path_1.join)(configDir, '.env');
68
+ }
69
+ // Local install - use current working directory
70
+ return (0, path_1.join)(process.cwd(), '.env');
71
+ }
72
+ /**
73
+ * Resolve path securely by resolving symlinks and verifying within allowed directory
74
+ * Issue #125: Path traversal protection (OWASP A01:2021 - Broken Access Control)
75
+ *
76
+ * @param targetPath - The path to resolve and verify
77
+ * @param allowedBaseDir - The base directory that targetPath must be within
78
+ * @returns The resolved real path
79
+ * @throws Error if path resolves outside allowed directory
80
+ */
81
+ function resolveSecurePath(targetPath, allowedBaseDir) {
82
+ const realPath = (0, fs_1.realpathSync)(targetPath);
83
+ const realBaseDir = (0, fs_1.realpathSync)(allowedBaseDir);
84
+ if (!realPath.startsWith(realBaseDir)) {
85
+ throw new Error(`Path traversal detected: ${targetPath} resolves outside of ${allowedBaseDir}`);
86
+ }
87
+ return realPath;
88
+ }
89
+ /**
90
+ * Get the config directory path
91
+ * Issue #119: Returns ~/.commandmate for global, cwd for local
92
+ * Issue #125: Added symlink resolution for security (path traversal protection)
93
+ *
94
+ * @returns Path to config directory (absolute, with symlinks resolved)
95
+ */
96
+ function getConfigDir() {
97
+ if (isGlobalInstall()) {
98
+ const configDir = (0, path_1.join)((0, os_1.homedir)(), '.commandmate');
99
+ // Verify config directory is within home directory (security check)
100
+ // Only validate if the directory exists (it may not exist yet during init)
101
+ if ((0, fs_1.existsSync)(configDir)) {
102
+ const realPath = (0, fs_1.realpathSync)(configDir);
103
+ const realHome = (0, fs_1.realpathSync)((0, os_1.homedir)());
104
+ if (!realPath.startsWith(realHome)) {
105
+ throw new Error(`Security error: Config directory ${configDir} is outside home directory`);
106
+ }
107
+ return realPath;
108
+ }
109
+ return configDir;
110
+ }
111
+ // Local install - resolve symlinks in cwd
112
+ const cwd = process.cwd();
113
+ return (0, fs_1.realpathSync)(cwd);
114
+ }
115
+ /**
116
+ * Get the PID file path based on install type
117
+ * Issue #125: DRY principle - centralized PID file path resolution
118
+ *
119
+ * @returns Path to PID file (uses getConfigDir for consistency)
120
+ */
121
+ function getPidFilePath() {
122
+ return (0, path_1.join)(getConfigDir(), '.commandmate.pid');
123
+ }
27
124
  /**
28
125
  * Sanitize input by removing control characters
29
126
  * 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.8",
4
4
  "description": "Git worktree management with Claude CLI and tmux sessions",
5
5
  "repository": {
6
6
  "type": "git",
@@ -41,6 +41,7 @@
41
41
  "better-sqlite3": "^12.4.1",
42
42
  "commander": "^14.0.2",
43
43
  "date-fns": "^4.1.0",
44
+ "dotenv": "^17.2.3",
44
45
  "gray-matter": "^4.0.3",
45
46
  "http-proxy": "^1.18.1",
46
47
  "isomorphic-dompurify": "^2.35.0",