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.
- package/.allnightai/REQUIREMENTS.md +11 -0
- package/.allnightai/temp/auto-status.json +6 -0
- package/.env +7 -0
- package/.eslintrc.js +16 -0
- package/README.md +85 -0
- package/bin/vibecodingmachine.js +274 -0
- package/jest.config.js +8 -0
- package/logs/audit/2025-11-07.jsonl +2 -0
- package/package.json +64 -0
- package/scripts/README.md +128 -0
- package/scripts/auto-start-wrapper.sh +92 -0
- package/scripts/postinstall.js +81 -0
- package/src/commands/auth.js +96 -0
- package/src/commands/auto-direct.js +1748 -0
- package/src/commands/auto.js +4692 -0
- package/src/commands/auto.js.bak +710 -0
- package/src/commands/ide.js +70 -0
- package/src/commands/repo.js +159 -0
- package/src/commands/requirements.js +161 -0
- package/src/commands/setup.js +91 -0
- package/src/commands/status.js +88 -0
- package/src/components/RequirementPage.js +0 -0
- package/src/file.js +0 -0
- package/src/index.js +5 -0
- package/src/main.js +0 -0
- package/src/ui/requirements-page.js +0 -0
- package/src/utils/auth.js +548 -0
- package/src/utils/auto-mode-ansi-ui.js +238 -0
- package/src/utils/auto-mode-simple-ui.js +161 -0
- package/src/utils/auto-mode-ui.js.bak.blessed +207 -0
- package/src/utils/auto-mode.js +65 -0
- package/src/utils/config.js +64 -0
- package/src/utils/interactive.js +3616 -0
- package/src/utils/keyboard-handler.js +152 -0
- package/src/utils/logger.js +4 -0
- package/src/utils/persistent-header.js +116 -0
- package/src/utils/provider-registry.js +128 -0
- package/src/utils/requirementUtils.js +0 -0
- package/src/utils/status-card.js +120 -0
- package/src/utils/status-manager.js +0 -0
- package/src/utils/status.js +0 -0
- package/src/utils/stdout-interceptor.js +127 -0
- package/tests/auto-mode.test.js +37 -0
- package/tests/config.test.js +34 -0
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
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
|
+
```
|