devbonzai 2.0.4 → 2.0.6

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 (2) hide show
  1. package/cli.js +137 -5
  2. package/package.json +1 -1
package/cli.js CHANGED
@@ -91,6 +91,7 @@ app.get('/', (req, res) => {
91
91
  'POST /delete': 'Delete file or directory (body: {path})',
92
92
  'POST /move': 'Move file or folder (body: {source, destination})',
93
93
  'POST /open-cursor': 'Open Cursor (body: {path, line?})',
94
+ 'POST /analyze_prompt': 'Analyze what files would be modified (body: {prompt})',
94
95
  'POST /prompt_agent': 'Execute cursor-agent command (body: {prompt})',
95
96
  'POST /revert_job': 'Revert to a previous commit (body: {beforeCommit})',
96
97
  'POST /shutdown': 'Gracefully shutdown the server'
@@ -1275,6 +1276,120 @@ app.post('/open-cursor', (req, res) => {
1275
1276
  }
1276
1277
  });
1277
1278
 
1279
+ // Analyze prompt endpoint - asks agent what files it would modify without making changes
1280
+ app.post('/analyze_prompt', (req, res) => {
1281
+ console.log('🔵 [analyze_prompt] Endpoint hit');
1282
+ const { prompt } = req.body;
1283
+ console.log('🔵 [analyze_prompt] Received prompt:', prompt ? \`\${prompt.substring(0, 50)}...\` : 'none');
1284
+
1285
+ if (!prompt || typeof prompt !== 'string') {
1286
+ console.log('❌ [analyze_prompt] Error: prompt required');
1287
+ return res.status(400).json({ error: 'prompt required' });
1288
+ }
1289
+
1290
+ // Configurable timeout (default 2 minutes for analysis)
1291
+ const timeoutMs = parseInt(req.body.timeout) || 2 * 60 * 1000;
1292
+ let timeoutId = null;
1293
+ let responseSent = false;
1294
+
1295
+ // Build analysis prompt - ask agent to list files without making changes
1296
+ const analysisPrompt = \`You are analyzing a coding task. Do NOT make any changes to any files. Only analyze and list the files you would need to modify to complete this task.
1297
+
1298
+ Respond ONLY with valid JSON in this exact format (no other text):
1299
+ {"files": [{"path": "path/to/file.ext", "reason": "brief reason for modification"}]}
1300
+
1301
+ If no files need modification, respond with: {"files": []}
1302
+
1303
+ Task to analyze: \${prompt}\`;
1304
+
1305
+ const args = ['--print', '--force', '--workspace', '.', analysisPrompt];
1306
+
1307
+ console.log('🔵 [analyze_prompt] Spawning cursor-agent process...');
1308
+ const proc = spawn(
1309
+ 'cursor-agent',
1310
+ args,
1311
+ {
1312
+ cwd: ROOT,
1313
+ env: process.env,
1314
+ stdio: ['ignore', 'pipe', 'pipe']
1315
+ }
1316
+ );
1317
+
1318
+ console.log('🔵 [analyze_prompt] Process spawned, PID:', proc.pid);
1319
+
1320
+ let stdout = '';
1321
+ let stderr = '';
1322
+
1323
+ timeoutId = setTimeout(() => {
1324
+ if (!responseSent && proc && !proc.killed) {
1325
+ console.log('⏱️ [analyze_prompt] Timeout reached, killing process...');
1326
+ proc.kill('SIGTERM');
1327
+ setTimeout(() => {
1328
+ if (!proc.killed) proc.kill('SIGKILL');
1329
+ }, 5000);
1330
+
1331
+ if (!responseSent) {
1332
+ responseSent = true;
1333
+ res.status(500).json({
1334
+ error: 'Process timeout',
1335
+ message: \`Analysis exceeded timeout of \${timeoutMs / 1000} seconds\`
1336
+ });
1337
+ }
1338
+ }
1339
+ }, timeoutMs);
1340
+
1341
+ proc.stdout.on('data', (d) => {
1342
+ stdout += d.toString();
1343
+ });
1344
+
1345
+ proc.stderr.on('data', (d) => {
1346
+ stderr += d.toString();
1347
+ });
1348
+
1349
+ proc.on('error', (error) => {
1350
+ console.log('❌ [analyze_prompt] Process error:', error.message);
1351
+ if (timeoutId) clearTimeout(timeoutId);
1352
+ if (!responseSent) {
1353
+ responseSent = true;
1354
+ return res.status(500).json({ error: error.message });
1355
+ }
1356
+ });
1357
+
1358
+ proc.on('close', (code, signal) => {
1359
+ console.log('🔵 [analyze_prompt] Process closed with code:', code);
1360
+ if (timeoutId) clearTimeout(timeoutId);
1361
+
1362
+ if (!responseSent) {
1363
+ responseSent = true;
1364
+
1365
+ // Try to parse JSON from the output
1366
+ try {
1367
+ // Look for JSON in the output - it might be wrapped in other text
1368
+ const jsonMatch = stdout.match(/\\{[\\s\\S]*"files"[\\s\\S]*\\}/);
1369
+ if (jsonMatch) {
1370
+ const parsed = JSON.parse(jsonMatch[0]);
1371
+ console.log('✅ [analyze_prompt] Parsed files:', parsed.files);
1372
+ res.json({ files: parsed.files || [] });
1373
+ } else {
1374
+ console.log('⚠️ [analyze_prompt] No JSON found in output, returning raw');
1375
+ res.json({
1376
+ files: [],
1377
+ raw: stdout,
1378
+ warning: 'Could not parse structured response'
1379
+ });
1380
+ }
1381
+ } catch (parseError) {
1382
+ console.log('⚠️ [analyze_prompt] JSON parse error:', parseError.message);
1383
+ res.json({
1384
+ files: [],
1385
+ raw: stdout,
1386
+ warning: 'Could not parse JSON: ' + parseError.message
1387
+ });
1388
+ }
1389
+ }
1390
+ });
1391
+ });
1392
+
1278
1393
  app.post('/prompt_agent', (req, res) => {
1279
1394
  console.log('🔵 [prompt_agent] Endpoint hit');
1280
1395
  const { prompt } = req.body;
@@ -1294,18 +1409,35 @@ app.post('/prompt_agent', (req, res) => {
1294
1409
  console.log('⚠️ [prompt_agent] Could not get beforeCommit:', e.message);
1295
1410
  }
1296
1411
 
1297
- // Set up file change tracking
1412
+ // Capture initial state of modified files (files already dirty before job starts)
1413
+ const initiallyModifiedFiles = new Set();
1414
+ try {
1415
+ const initialStatus = execSync('git status --short', { cwd: ROOT }).toString();
1416
+ initialStatus.split('\\n').filter(Boolean).forEach(line => {
1417
+ const filePath = line.substring(3).trim();
1418
+ if (filePath) initiallyModifiedFiles.add(filePath);
1419
+ });
1420
+ console.log('🔵 [prompt_agent] Initially modified files:', Array.from(initiallyModifiedFiles));
1421
+ } catch (e) {
1422
+ console.log('⚠️ [prompt_agent] Could not get initial status:', e.message);
1423
+ }
1424
+
1425
+ // Set up file change tracking - only track NEW changes during job
1298
1426
  const changedFiles = new Set();
1299
1427
  const pollInterval = setInterval(() => {
1300
1428
  try {
1301
1429
  const status = execSync('git status --short', { cwd: ROOT }).toString();
1302
1430
  status.split('\\n').filter(Boolean).forEach(line => {
1303
1431
  const filePath = line.substring(3).trim(); // Remove status prefix (XY + space)
1304
- if (filePath) changedFiles.add(filePath);
1432
+ // Only add if this file was NOT already modified before the job started
1433
+ if (filePath && !initiallyModifiedFiles.has(filePath)) {
1434
+ const wasNew = !changedFiles.has(filePath);
1435
+ changedFiles.add(filePath);
1436
+ if (wasNew) {
1437
+ console.log('📁 [prompt_agent] New file changed:', filePath);
1438
+ }
1439
+ }
1305
1440
  });
1306
- if (changedFiles.size > 0) {
1307
- console.log('📁 [prompt_agent] Changed files:', Array.from(changedFiles));
1308
- }
1309
1441
  } catch (e) {
1310
1442
  // Ignore git status errors
1311
1443
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devbonzai",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "description": "Quickly set up a local file server in any repository for browser-based file access",
5
5
  "main": "cli.js",
6
6
  "bin": {