vibecodingmachine-cli 1.0.0

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 (44) hide show
  1. package/.allnightai/REQUIREMENTS.md +11 -0
  2. package/.allnightai/temp/auto-status.json +6 -0
  3. package/.env +7 -0
  4. package/.eslintrc.js +16 -0
  5. package/README.md +85 -0
  6. package/bin/vibecodingmachine.js +274 -0
  7. package/jest.config.js +8 -0
  8. package/logs/audit/2025-11-07.jsonl +2 -0
  9. package/package.json +64 -0
  10. package/scripts/README.md +128 -0
  11. package/scripts/auto-start-wrapper.sh +92 -0
  12. package/scripts/postinstall.js +81 -0
  13. package/src/commands/auth.js +96 -0
  14. package/src/commands/auto-direct.js +1748 -0
  15. package/src/commands/auto.js +4692 -0
  16. package/src/commands/auto.js.bak +710 -0
  17. package/src/commands/ide.js +70 -0
  18. package/src/commands/repo.js +159 -0
  19. package/src/commands/requirements.js +161 -0
  20. package/src/commands/setup.js +91 -0
  21. package/src/commands/status.js +88 -0
  22. package/src/components/RequirementPage.js +0 -0
  23. package/src/file.js +0 -0
  24. package/src/index.js +5 -0
  25. package/src/main.js +0 -0
  26. package/src/ui/requirements-page.js +0 -0
  27. package/src/utils/auth.js +548 -0
  28. package/src/utils/auto-mode-ansi-ui.js +238 -0
  29. package/src/utils/auto-mode-simple-ui.js +161 -0
  30. package/src/utils/auto-mode-ui.js.bak.blessed +207 -0
  31. package/src/utils/auto-mode.js +65 -0
  32. package/src/utils/config.js +64 -0
  33. package/src/utils/interactive.js +3616 -0
  34. package/src/utils/keyboard-handler.js +152 -0
  35. package/src/utils/logger.js +4 -0
  36. package/src/utils/persistent-header.js +116 -0
  37. package/src/utils/provider-registry.js +128 -0
  38. package/src/utils/requirementUtils.js +0 -0
  39. package/src/utils/status-card.js +120 -0
  40. package/src/utils/status-manager.js +0 -0
  41. package/src/utils/status.js +0 -0
  42. package/src/utils/stdout-interceptor.js +127 -0
  43. package/tests/auto-mode.test.js +37 -0
  44. package/tests/config.test.js +34 -0
@@ -0,0 +1,11 @@
1
+
2
+
3
+ ## ✅ Requirements completed
4
+ - TEST
5
+ - Add Cline CLI IDE
6
+
7
+ ### Add Cline CLI to list of IDEs
8
+
9
+ ### NEW REQUIREMENT
10
+
11
+ ### Add Cline CLI to list of IDEs
@@ -0,0 +1,6 @@
1
+ {
2
+ "running": false,
3
+ "startedAt": "2025-11-05T00:44:44.363Z",
4
+ "chatCount": 1,
5
+ "ide": "continue"
6
+ }
package/.env ADDED
@@ -0,0 +1,7 @@
1
+ # AllNightAI AWS Cognito Configuration
2
+ AWS_REGION=us-east-1
3
+ COGNITO_USER_POOL_ID=us-east-1_EjZ4Kbtgd
4
+ COGNITO_APP_CLIENT_ID=igc6madjovggt89cmv17h5p15
5
+ COGNITO_DOMAIN=allnightai-auth-1763598779.auth.us-east-1.amazoncognito.com
6
+ AUTH_URL=https://allnightai-auth-1763598779.auth.us-east-1.amazoncognito.com
7
+ GOOGLE_CLIENT_ID=820601514351-tcjvhvugi4225pdkhrnq8bht8c5gkvm0.apps.googleusercontent.com
package/.eslintrc.js ADDED
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ env: {
3
+ node: true,
4
+ es2021: true,
5
+ jest: true
6
+ },
7
+ extends: 'eslint:recommended',
8
+ parserOptions: {
9
+ ecmaVersion: 2021,
10
+ sourceType: 'module'
11
+ },
12
+ rules: {
13
+ 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
14
+ 'no-console': 'off'
15
+ }
16
+ };
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Vibe Coding Machine CLI
2
+
3
+ Vibe Coding Machine command-line interface for managing repositories, auto mode, requirements, IDE actions, and status.
4
+
5
+ ## Install
6
+
7
+ From the monorepo root:
8
+
9
+ ```bash
10
+ npm install
11
+ # optional: link locally for global access
12
+ npm run --workspaces --if-present build
13
+ npm link ./packages/cli
14
+ ```
15
+
16
+ Then run `allnightai` or `vcm` (short version).
17
+
18
+ **Note**: The `vcm` shortcut will only be installed if you don't already have another `vcm` command on your system. If a conflict is detected, you can still use the full `allnightai` command.
19
+
20
+ ## Usage
21
+
22
+ ```bash
23
+ allnightai --help # or: ana --help (if installed)
24
+ allnightai -v # or: ana -v (if installed)
25
+ ```
26
+
27
+ **Note**: You can use either `allnightai` or `vcm` - they're the same command!
28
+
29
+ ### Repository
30
+ ```bash
31
+ ana repo:init # initialize .vibecodingmachine in CWD and set repo
32
+ ana repo:set /path/to/repo # set active repository
33
+ ana repo:get # print current repo path
34
+ ```
35
+
36
+ ### Auto Mode
37
+ ```bash
38
+ ana auto:start --ide cursor --max-chats 10
39
+ ana auto:status
40
+ ana auto:config --max-chats 25 --never-stop
41
+ ana auto:stop
42
+ ```
43
+
44
+ ### Requirements
45
+ ```bash
46
+ ana req:list
47
+ ana req:add "Build initial CLI MVP"
48
+ ana req:current
49
+ ana req:next
50
+ ana req:edit
51
+ ana req:watch
52
+ ```
53
+
54
+ ### IDE
55
+ ```bash
56
+ ana ide:list
57
+ ana ide:open cursor # or vscode, windsurf
58
+ ana ide:send "Summarize failures" -i cursor
59
+ ```
60
+
61
+ ### Status
62
+ ```bash
63
+ ana status
64
+ ana progress
65
+ ana logs -n 100
66
+ ```
67
+
68
+ ### Interactive
69
+ ```bash
70
+ ana interactive
71
+ ```
72
+
73
+ ## Configuration
74
+ - Stored at `~/.config/allnightai/config.json` by default
75
+ - Override for testing with env var `ALLNIGHTAI_CONFIG_PATH=/tmp/your-test-config.json`
76
+
77
+ ## Development
78
+ ```bash
79
+ # format and lint
80
+ npm run -w @allnightai/cli format
81
+ npm run -w @allnightai/cli lint
82
+
83
+ # tests
84
+ npm run -w @allnightai/cli test
85
+ ```
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+
6
+ // Auto-load .env.auth if it exists
7
+ const envAuthPath = path.join(__dirname, '..', '..', '.env.auth');
8
+ if (fs.existsSync(envAuthPath)) {
9
+ const envContent = fs.readFileSync(envAuthPath, 'utf8');
10
+ envContent.split('\n').forEach(line => {
11
+ const trimmed = line.trim();
12
+ if (trimmed && !trimmed.startsWith('#')) {
13
+ const [key, ...valueParts] = trimmed.split('=');
14
+ if (key && valueParts.length > 0) {
15
+ process.env[key.trim()] = valueParts.join('=').trim();
16
+ }
17
+ }
18
+ });
19
+ }
20
+
21
+ /**
22
+ * Vibe Coding Machine CLI - Command-line interface for autonomous AI development
23
+ * "Big Dreams + AI + VibeCodingMachine.com = Your money making apps"
24
+ */
25
+
26
+ const { program } = require('commander');
27
+ const chalk = require('chalk');
28
+ // const path = require('path'); // Moved to top for .env.auth loading
29
+ const packageJson = require('../package.json');
30
+
31
+ // Import command modules
32
+ const repoCommands = require('../src/commands/repo');
33
+ const autoCommands = require('../src/commands/auto');
34
+ const reqCommands = require('../src/commands/requirements');
35
+ const ideCommands = require('../src/commands/ide');
36
+ const statusCommands = require('../src/commands/status');
37
+
38
+ // Detect which command was used (vcm or vibecodingmachine)
39
+ const commandName = path.basename(process.argv[1], '.js');
40
+ const altCommandName = commandName === 'vcm' ? 'vibecodingmachine' : 'vcm';
41
+
42
+ // Configure CLI
43
+ program
44
+ .name(commandName)
45
+ .usage(`[options] [command]\n\n You can use '${commandName}' or '${altCommandName}'`)
46
+ .description('Vibe Coding Machine CLI - Autonomous development')
47
+ .version(packageJson.version, '-v, --version', 'output the current version')
48
+ .helpOption('-h, --help', 'display help for command');
49
+
50
+ // Repository management commands
51
+ program
52
+ .command('repo')
53
+ .description('Manage repository settings')
54
+ .action(() => {
55
+ program.outputHelp();
56
+ });
57
+
58
+ program
59
+ .command('repo:set <path>')
60
+ .description('Set the active repository path')
61
+ .action(repoCommands.setRepo);
62
+
63
+ program
64
+ .command('repo:get')
65
+ .description('Get the current repository path')
66
+ .action(repoCommands.getRepo);
67
+
68
+ program
69
+ .command('repo:init')
70
+ .description('Initialize Vibe Coding Machine in current directory')
71
+ .action(repoCommands.initRepo);
72
+
73
+ // Auto mode commands
74
+ program
75
+ .command('auto:start')
76
+ .description('Start autonomous development mode')
77
+ .option('-i, --ide <ide>', 'IDE to use (claude-code, aider, cursor, vscode, windsurf, cline)')
78
+ .option('-m, --max-chats <number>', 'Maximum number of chat iterations', parseInt)
79
+ .option('-n, --never-stop', 'Run indefinitely without stopping')
80
+ .option('-f, --force-provider-setup', 'Force provider selection even if already configured')
81
+ .action(autoCommands.start);
82
+
83
+ // Direct LLM auto mode (new simplified implementation)
84
+ const { handleAutoStart: handleDirectAutoStart } = require('../src/commands/auto-direct');
85
+ program
86
+ .command('auto:direct')
87
+ .description('Start autonomous mode with direct LLM API calls (recommended)')
88
+ .option('-m, --max-chats <number>', 'Maximum number of iterations', parseInt)
89
+ .action(handleDirectAutoStart);
90
+
91
+ program
92
+ .command('auto:stop')
93
+ .description('Stop autonomous development mode')
94
+ .action(autoCommands.stop);
95
+
96
+ program
97
+ .command('auto:status')
98
+ .description('Check autonomous mode status')
99
+ .action(autoCommands.status);
100
+
101
+ program
102
+ .command('auto:config')
103
+ .description('Configure auto mode settings')
104
+ .option('--max-chats <number>', 'Set maximum chat iterations', parseInt)
105
+ .option('--never-stop', 'Enable never stop mode')
106
+ .option('--no-never-stop', 'Disable never stop mode')
107
+ .action(autoCommands.config);
108
+
109
+ // Requirements management commands
110
+ program
111
+ .command('req:list')
112
+ .description('List all requirements')
113
+ .option('-s, --status <status>', 'Filter by status (pending, in-progress, completed)')
114
+ .action(reqCommands.list);
115
+
116
+ program
117
+ .command('req:add <requirement>')
118
+ .description('Add a new requirement')
119
+ .action(reqCommands.add);
120
+
121
+ program
122
+ .command('req:current')
123
+ .description('Show current requirement being worked on')
124
+ .action(reqCommands.current);
125
+
126
+ program
127
+ .command('req:next')
128
+ .description('Move to next requirement')
129
+ .action(reqCommands.next);
130
+
131
+ program
132
+ .command('req:edit')
133
+ .description('Open requirements file in editor')
134
+ .action(reqCommands.edit);
135
+
136
+ program
137
+ .command('req:watch')
138
+ .description('Watch requirements file for changes')
139
+ .action(reqCommands.watch);
140
+
141
+ // IDE integration commands
142
+ program
143
+ .command('ide:list')
144
+ .description('List available IDEs')
145
+ .action(ideCommands.list);
146
+
147
+ program
148
+ .command('ide:open <ide>')
149
+ .description('Open IDE with current repository')
150
+ .action(ideCommands.open);
151
+
152
+ program
153
+ .command('ide:send <message>')
154
+ .description('Send message to IDE AI chat')
155
+ .option('-i, --ide <ide>', 'IDE to use (cursor, vscode, windsurf)', 'cursor')
156
+ .action(ideCommands.send);
157
+
158
+ // Status and monitoring commands
159
+ program
160
+ .command('status')
161
+ .description('Show Vibe Coding Machine status and progress')
162
+ .action(statusCommands.show);
163
+
164
+ program
165
+ .command('progress')
166
+ .description('Show development progress')
167
+ .action(statusCommands.progress);
168
+
169
+ program
170
+ .command('logs')
171
+ .description('Show recent activity logs')
172
+ .option('-n, --lines <number>', 'Number of log lines to show', '50')
173
+ .action(statusCommands.logs);
174
+
175
+ // Setup command
176
+ program
177
+ .command('setup')
178
+ .description('Setup "vcm" alias for shell')
179
+ .action(async () => {
180
+ const { setupAlias } = require('../src/commands/setup');
181
+ await setupAlias();
182
+ });
183
+
184
+ // Authentication commands
185
+ const authCommands = require('../src/commands/auth');
186
+ program
187
+ .command('auth:login')
188
+ .description('Login with Google')
189
+ .option('--headless', 'Use headless mode (manual URL paste) for SSH/no-GUI environments')
190
+ .action((options) => authCommands.login(options));
191
+
192
+ program
193
+ .command('auth:logout')
194
+ .description('Logout')
195
+ .action(authCommands.logout);
196
+
197
+ program
198
+ .command('auth:status')
199
+ .description('Check authentication status')
200
+ .action(authCommands.status);
201
+
202
+ // Interactive mode
203
+ program
204
+ .command('interactive')
205
+ .alias('i')
206
+ .description('Start interactive mode')
207
+ .action(async () => {
208
+ const { startInteractive } = require('../src/utils/interactive');
209
+ await startInteractive();
210
+ });
211
+
212
+ // Error handling
213
+ process.on('uncaughtException', (error) => {
214
+ console.error(chalk.red('Error:'), error.message);
215
+ process.exit(1);
216
+ });
217
+
218
+ process.on('unhandledRejection', (error) => {
219
+ console.error(chalk.red('Error:'), error.message);
220
+ process.exit(1);
221
+ });
222
+
223
+ // Check for updates and display notification
224
+ async function checkForUpdates() {
225
+ try {
226
+ const { checkForUpdatesWithCache } = require('@vibecodingmachine/core');
227
+ const updateInfo = await checkForUpdatesWithCache('allnightai-cli', packageJson.version);
228
+
229
+ if (updateInfo.hasUpdate) {
230
+ // Store update info globally for when auto mode starts
231
+ global.pendingUpdate = updateInfo;
232
+
233
+ // Display update notification
234
+ console.log(chalk.cyan(`\n📦 Update available: v${updateInfo.currentVersion} → v${updateInfo.latestVersion}`));
235
+ console.log(chalk.gray(` Published: ${updateInfo.publishedDate}`));
236
+ console.log(chalk.yellow(` Will be installed next time auto mode is started\n`));
237
+ }
238
+ } catch (error) {
239
+ // Silently fail - don't block CLI usage
240
+ }
241
+ }
242
+
243
+ // Start interactive mode if no command provided (check BEFORE parsing)
244
+ if (!process.argv.slice(2).length) {
245
+ (async () => {
246
+ // Check for updates first
247
+ await checkForUpdates();
248
+
249
+ // Check authentication before allowing interactive mode
250
+ const auth = require('../src/utils/auth');
251
+ const isAuth = await auth.isAuthenticated();
252
+
253
+ if (!isAuth) {
254
+ console.log(chalk.cyan('\n🔐 Opening browser for authentication...\n'));
255
+ try {
256
+ await auth.login();
257
+ console.log(chalk.green('\n✓ Authentication successful!\n'));
258
+ } catch (error) {
259
+ console.log(chalk.red('\n✗ Authentication failed:'), error.message);
260
+ process.exit(1);
261
+ }
262
+ }
263
+
264
+ const { startInteractive } = require('../src/utils/interactive');
265
+ await startInteractive();
266
+ })();
267
+ } else {
268
+ // Check for updates before parsing commands
269
+ (async () => {
270
+ await checkForUpdates();
271
+ // Parse arguments only if commands were provided
272
+ program.parse(process.argv);
273
+ })();
274
+ }
package/jest.config.js ADDED
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ testEnvironment: 'node',
3
+ testMatch: ['**/tests/**/*.test.js'],
4
+ testPathIgnorePatterns: ['/node_modules/'],
5
+ collectCoverageFrom: ['src/**/*.js'],
6
+ coverageDirectory: 'coverage',
7
+ verbose: true
8
+ };
@@ -0,0 +1,2 @@
1
+ {"timestamp":"2025-11-07T12:33:10.966Z","type":"auto-mode-stop","reason":"startup","message":"Auto Mode stopped (startup)"}
2
+ {"timestamp":"2025-11-07T12:33:47.590Z","type":"auto-mode-stop","reason":"startup","message":"Auto Mode stopped (startup)"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "vibecodingmachine-cli",
3
+ "version": "1.0.0",
4
+ "description": "Command-line interface for Vibe Coding Machine - Autonomous development",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "vibecodingmachine": "./bin/vibecodingmachine.js",
8
+ "vcm": "./bin/vibecodingmachine.js"
9
+ },
10
+ "scripts": {
11
+ "postinstall": "node scripts/postinstall.js",
12
+ "test": "jest",
13
+ "test:watch": "jest --watch",
14
+ "lint": "eslint src/ --ext .js",
15
+ "format": "prettier --write \"src/**/*.js\""
16
+ },
17
+ "keywords": [
18
+ "vibecodingmachine",
19
+ "cli",
20
+ "ai",
21
+ "autonomous",
22
+ "development",
23
+ "ide"
24
+ ],
25
+ "author": "Vibe Coding Machine Team",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "vibecodingmachine-core": "^1.0.0",
29
+ "blessed": "^0.1.81",
30
+ "boxen": "^5.1.2",
31
+ "chalk": "^4.1.2",
32
+ "chokidar": "^3.6.0",
33
+ "commander": "^11.1.0",
34
+ "fs-extra": "^11.2.0",
35
+ "ink": "^6.4.0",
36
+ "inquirer": "^8.2.6",
37
+ "js-yaml": "^4.1.0",
38
+ "jsonwebtoken": "^9.0.2",
39
+ "jwks-rsa": "^3.2.0",
40
+ "node-fetch": "^2.7.0",
41
+ "node-pty": "^1.0.0",
42
+ "open": "^11.0.0",
43
+ "ora": "^5.4.1",
44
+ "react": "^19.2.0",
45
+ "table": "^6.8.1"
46
+ },
47
+ "devDependencies": {
48
+ "eslint": "^8.57.0",
49
+ "jest": "^29.7.0",
50
+ "prettier": "^3.2.5"
51
+ },
52
+ "engines": {
53
+ "node": ">=18.0.0"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/mediawink/vibecodingmachine.git",
58
+ "directory": "packages/cli"
59
+ },
60
+ "homepage": "http://vibecodingmachine-website.s3-website-us-east-1.amazonaws.com",
61
+ "bugs": {
62
+ "url": "https://github.com/mediawink/vibecodingmachine/issues"
63
+ }
64
+ }
@@ -0,0 +1,128 @@
1
+ # Auto Start Wrapper Script
2
+
3
+ ## Overview
4
+
5
+ The `auto-start-wrapper.sh` script provides **reliable Ctrl+C handling** for `ana auto:start`.
6
+
7
+ ## Problem
8
+
9
+ Due to a Node.js limitation, SIGINT (Ctrl+C) signals don't reliably reach the event loop when Node.js is blocked waiting for child processes (like Aider). **This means Ctrl+C does NOT work when running `ana auto:start` directly.**
10
+
11
+ ## Recommended Usage
12
+
13
+ **If you want Ctrl+C to work**, use the wrapper script instead of running `ana auto:start` directly:
14
+
15
+ ```bash
16
+ # From anywhere (recommended)
17
+ ~/.asdf/installs/nodejs/20.19.5/lib/node_modules/@allnightai/cli/scripts/auto-start-wrapper.sh
18
+
19
+ # Or if you know the package location
20
+ /path/to/allnightai/packages/cli/scripts/auto-start-wrapper.sh
21
+ ```
22
+
23
+ ### Creating a Convenient Alias
24
+
25
+ Add this to your `~/.zshrc` or `~/.bashrc`:
26
+
27
+ ```bash
28
+ # Alias for ana auto:start with Ctrl+C support
29
+ alias ana-start='~/.asdf/installs/nodejs/20.19.5/lib/node_modules/@allnightai/cli/scripts/auto-start-wrapper.sh'
30
+ ```
31
+
32
+ Then you can simply run:
33
+ ```bash
34
+ ana-start
35
+ ana-start --max-chats 10
36
+ ```
37
+
38
+ ## Solution
39
+
40
+ This wrapper script:
41
+ 1. Runs `ana auto:start` in the background
42
+ 2. Monitors keyboard input in the foreground (in the wrapper's process)
43
+ 3. When Ctrl+C, Esc, or 'x' is pressed, creates a `.stop` file
44
+ 4. The running `ana` process detects the file (via watchdog timer) and exits gracefully
45
+
46
+ ## Usage
47
+
48
+ ### Direct Usage
49
+ ```bash
50
+ # From the project root
51
+ ./packages/cli/scripts/auto-start-wrapper.sh
52
+
53
+ # Or with options
54
+ ./packages/cli/scripts/auto-start-wrapper.sh --max-chats 5
55
+ ```
56
+
57
+ ### How to Stop
58
+ - **Ctrl+C**: Stops the process (most common)
59
+ - **Esc key**: Stops the process
60
+ - **'x' key**: Stops the process
61
+ - **`ana auto:stop`**: From another terminal
62
+
63
+ ## How It Works
64
+
65
+ 1. **Wrapper starts**: Spawns `node ana auto:start` as a background process
66
+ 2. **Wrapper monitors**: Uses `read -t 0.5 -n 1` to check for key presses every 500ms
67
+ 3. **Key pressed**: Creates `~/.config/allnightai/.stop` file
68
+ 4. **Watchdog detects**: The running ana process has a watchdog that checks for this file every 500ms
69
+ 5. **Graceful exit**: When detected, ana kills Aider processes and exits the main loop
70
+ 6. **Cleanup**: Wrapper removes the stop file and exits
71
+
72
+ ## Alternative: Manual Stop File
73
+
74
+ You can also create the stop file manually:
75
+ ```bash
76
+ # Create stop file
77
+ touch ~/.config/allnightai/.stop
78
+
79
+ # Or use the stop command
80
+ ana auto:stop
81
+ ```
82
+
83
+ ## Technical Details
84
+
85
+ ### Watchdog Timer
86
+ The watchdog runs every 500ms in the Node.js process:
87
+ ```javascript
88
+ const watchdog = setInterval(async () => {
89
+ if (await fs.pathExists(stopFilePath)) {
90
+ console.log('🛑 Stop signal detected (via .stop file)');
91
+ shouldExit = true;
92
+ exitReason = 'user-stop';
93
+ await fs.unlink(stopFilePath);
94
+ }
95
+
96
+ if (shouldExit) {
97
+ clearInterval(watchdog);
98
+ aiderManager.killAllProcesses();
99
+ // Loop breaks naturally
100
+ }
101
+ }, 500);
102
+ ```
103
+
104
+ ### Why Not Direct SIGINT?
105
+ Node.js SIGINT handlers aren't called when:
106
+ - `await` is blocked on a child process
107
+ - The event loop is not running (waiting for I/O)
108
+ - Child processes intercept signals first
109
+
110
+ The wrapper script solves this by handling signals at the shell level (outside Node.js).
111
+
112
+ ## Testing
113
+
114
+ Test the wrapper with Ctrl+C:
115
+ ```bash
116
+ ./packages/cli/scripts/auto-start-wrapper.sh &
117
+ sleep 5
118
+ # Press Ctrl+C
119
+ # Should see: "🛑 Stop signal detected" and process exits
120
+ ```
121
+
122
+ Test with stop command:
123
+ ```bash
124
+ ./packages/cli/scripts/auto-start-wrapper.sh &
125
+ sleep 5
126
+ ana auto:stop
127
+ # Should see process exit within 2 seconds
128
+ ```