repoburg 1.0.65 → 1.0.67

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 (32) hide show
  1. package/.rgignore +1 -0
  2. package/backend/dist/action-execution/action-execution.service.js +28 -0
  3. package/backend/dist/action-execution/action-execution.service.js.map +1 -1
  4. package/backend/dist/ai-actions/ai-actions.service.js +43 -0
  5. package/backend/dist/ai-actions/ai-actions.service.js.map +1 -1
  6. package/backend/dist/context-generation/context-generation.service.js +55 -0
  7. package/backend/dist/context-generation/context-generation.service.js.map +1 -1
  8. package/backend/dist/llm-response-parser/llm-response-parser.service.js +10 -0
  9. package/backend/dist/llm-response-parser/llm-response-parser.service.js.map +1 -1
  10. package/backend/dist/main.js +2 -0
  11. package/backend/dist/main.js.map +1 -1
  12. package/backend/dist/projects/projects.service.js +20 -0
  13. package/backend/dist/projects/projects.service.js.map +1 -1
  14. package/backend/dist/sessions/sessions.service.js +49 -0
  15. package/backend/dist/sessions/sessions.service.js.map +1 -1
  16. package/backend/dist/tracing.d.ts +1 -0
  17. package/backend/dist/tracing.js +53 -0
  18. package/backend/dist/tracing.js.map +1 -0
  19. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  20. package/backend/dist/utils/index.d.ts +1 -0
  21. package/backend/dist/utils/index.js +1 -0
  22. package/backend/dist/utils/index.js.map +1 -1
  23. package/backend/dist/utils/trace.decorator.d.ts +1 -0
  24. package/backend/dist/utils/trace.decorator.js +31 -0
  25. package/backend/dist/utils/trace.decorator.js.map +1 -0
  26. package/backend/dist/workspace/workspace.service.d.ts +1 -0
  27. package/backend/dist/workspace/workspace.service.js +84 -23
  28. package/backend/dist/workspace/workspace.service.js.map +1 -1
  29. package/backend/package.json +8 -1
  30. package/daemon/dist/api/services.js +1 -1
  31. package/package.json +3 -1
  32. package/platform-cli.js +12 -367
package/platform-cli.js CHANGED
@@ -5,11 +5,9 @@ const axios = require('axios');
5
5
  const path = require('path');
6
6
  const fs = require('fs/promises');
7
7
  const packageJson = require('./package.json');
8
- const pm2 = require('pm2');
9
8
  const { spawn } = require('child_process');
10
9
 
11
10
  const DAEMON_BASE_URL = 'http://localhost:9998';
12
- const DAEMON_PM2_NAME = 'repoburg-daemon';
13
11
 
14
12
  // Uncomment the next line to use localhost for development
15
13
  // const FRONTEND_BASE_URL ='http://localhost:3001';
@@ -35,38 +33,6 @@ const handleApiError = async (error) => {
35
33
  process.exit(1);
36
34
  };
37
35
 
38
- const connectToPm2 = () => new Promise((resolve, reject) => {
39
- pm2.connect(err => {
40
- if (err) return reject(new Error(`Could not connect to pm2: ${err.message}`));
41
- resolve();
42
- });
43
- });
44
-
45
- const startDaemon = async () => {
46
- const { default: ora } = await import('ora');
47
- const spinner = ora('Starting daemon process...').start();
48
- try {
49
- await connectToPm2();
50
- await new Promise((resolve, reject) => {
51
- pm2.start({
52
- name: DAEMON_PM2_NAME,
53
- script: 'repoburg-daemon',
54
- }, (err) => {
55
- pm2.disconnect();
56
- if (err) {
57
- const errMsg = err.message || err.msg;
58
- return reject(new Error(`Error starting daemon with pm2: ${errMsg || err}`));
59
- }
60
- resolve();
61
- });
62
- });
63
- spinner.succeed('Daemon process started via pm2.');
64
- } catch (error) {
65
- spinner.fail('Failed to start daemon.');
66
- throw error;
67
- }
68
- };
69
-
70
36
  program
71
37
  .name('repoburg')
72
38
  .description('CLI to manage the Repoburg Platform Daemon and services.')
@@ -172,51 +138,8 @@ program
172
138
  };
173
139
 
174
140
  try {
175
- // 1. Check daemon status and start if not running
176
- let authResponse;
177
- try {
178
- authResponse = await axios.get(`${DAEMON_BASE_URL}/auth/status`);
179
- } catch (error) {
180
- if (error.request && !error.response) {
181
- // console.log(chalk.yellow('Daemon not reachable. Attempting to start it now...'));
182
-
183
- // TODO restore here once pm2 daemon bug is fixed
184
- // await startDaemon();
185
- //
186
- // const pollForDaemonHealth = (timeout = 30000) => {
187
- // const spinner = ora('Waiting for daemon to become healthy...').start();
188
- // return new Promise((resolve, reject) => {
189
- // const startTime = Date.now();
190
- // const pollInterval = setInterval(async () => {
191
- // if (Date.now() - startTime > timeout) {
192
- // clearInterval(pollInterval);
193
- // spinner.fail('Daemon health check timed out.');
194
- // return reject(new Error('Daemon health check timed out. Check logs with `repoburg daemon logs`.'));
195
- // }
196
- // try {
197
- // await axios.get(`${DAEMON_BASE_URL}/health`);
198
- // clearInterval(pollInterval);
199
- // spinner.succeed('Daemon is healthy.');
200
- // resolve();
201
- // } catch (e) {
202
- // // ignore until timeout
203
- // }
204
- // }, 1000)
205
- // });
206
- // };
207
- //
208
- // await pollForDaemonHealth();
209
-
210
- // try {
211
- // authResponse = await axios.get(`${DAEMON_BASE_URL}/auth/status`);
212
- // } catch (retryError) {
213
- // console.error(chalk.red('Daemon started but is not responding correctly.'));
214
- // return handleApiError(retryError);
215
- // }
216
- } else {
217
- // return handleApiError(error);
218
- }
219
- }
141
+ // 1. Check daemon status. This will fail if the daemon isn't running.
142
+ const authResponse = await axios.get(`${DAEMON_BASE_URL}/auth/status`);
220
143
 
221
144
  if (authResponse.data.status !== 'authorized') {
222
145
  console.log(chalk.yellow(`Authentication required. Status: ${authResponse.data.status}.`));
@@ -437,307 +360,29 @@ program
437
360
  });
438
361
  };
439
362
 
440
- const pollForDaemonHealth = (timeout = 30000) => {
441
- const spinner = ora('Waiting for daemon to become healthy...').start();
442
- return new Promise((resolve, reject) => {
443
- const startTime = Date.now();
444
- const pollInterval = setInterval(async () => {
445
- if (Date.now() - startTime > timeout) {
446
- clearInterval(pollInterval);
447
- spinner.fail('Daemon health check timed out.');
448
- return reject(new Error('Daemon health check timed out.'));
449
- }
450
- try {
451
- await axios.get(`${DAEMON_BASE_URL}/health`);
452
- clearInterval(pollInterval);
453
- spinner.succeed('Daemon is healthy.');
454
- resolve();
455
- } catch (e) {
456
- // ignore until timeout
457
- }
458
- }, 1000)
459
- });
460
- };
461
-
462
- let runningServices = [];
463
-
464
363
  try {
465
- // 1. Get list of running services
466
- const listSpinner = ora('Fetching list of running services...').start();
364
+ console.log(chalk.cyan('Stopping any running services before update...'));
467
365
  try {
468
- const response = await axios.get(`${DAEMON_BASE_URL}/services`);
469
- runningServices = response.data.filter(s => s.status === 'running').map(s => s.name);
470
- listSpinner.succeed(`Found ${runningServices.length} running services to restart later.`);
366
+ // We don't care about the result, just that we tried to stop them.
367
+ await axios.post(`${DAEMON_BASE_URL}/services/remove-all`);
368
+ console.log(chalk.cyan('Services stopped.'));
471
369
  } catch (error) {
472
- if (error.request && !error.response) { // Daemon not running
473
- listSpinner.warn('Daemon not reachable, assuming no services are running.');
370
+ if (error.request && !error.response) { // Daemon not running
371
+ console.log(chalk.yellow('Daemon not reachable, skipping service stop.'));
474
372
  } else {
475
- listSpinner.fail('Failed to fetch services.');
476
- throw error;
477
- }
478
- }
479
-
480
- // 2. Stop all running services
481
- if (runningServices.length > 0) {
482
- const stopSpinner = ora('Stopping running backend services...').start();
483
- for (const name of runningServices) {
484
- stopSpinner.text = `Stopping ${name}...`;
485
- await axios.post(`${DAEMON_BASE_URL}/services/${name}/stop`);
373
+ console.warn(chalk.yellow('Could not stop services, continuing with update...'));
486
374
  }
487
- stopSpinner.succeed('All backend services stopped.');
488
375
  }
489
-
490
- // 3. Stop the daemon
491
- const stopDaemonSpinner = ora('Stopping daemon...').start();
492
- await new Promise((resolve, reject) => {
493
- pm2.connect(err => {
494
- if (err) return reject(err);
495
- pm2.stop(DAEMON_PM2_NAME, (err) => {
496
- pm2.disconnect();
497
- const errMsg = err ? (err.message || err.msg) : null;
498
- if (err && !(errMsg && errMsg.includes('not found'))) {
499
- return reject(err);
500
- }
501
- resolve();
502
- });
503
- });
504
- });
505
- stopDaemonSpinner.succeed('Daemon stopped.');
506
-
507
- // 4. Run update
376
+
508
377
  await runCommand('npm', ['i', '-g', 'repoburg@latest']);
509
378
 
510
- // 5. Start the daemon
511
- const startDaemonSpinner = ora('Starting daemon...').start();
512
- await new Promise((resolve, reject) => {
513
- pm2.connect(err => {
514
- if (err) return reject(err);
515
- pm2.start({ name: DAEMON_PM2_NAME, script: 'repoburg-daemon' }, (err) => {
516
- pm2.disconnect();
517
- if (err) return reject(err);
518
- resolve();
519
- });
520
- });
521
- });
522
- startDaemonSpinner.succeed('Daemon process started.');
523
- await pollForDaemonHealth();
524
-
525
- // 6. Restart services
526
- if (runningServices.length > 0) {
527
- const restartSpinner = ora('Restarting backend services...').start();
528
- for (const name of runningServices) {
529
- restartSpinner.text = `Restarting ${name}...`;
530
- await axios.post(`${DAEMON_BASE_URL}/services/${name}/restart`);
531
- }
532
- restartSpinner.succeed('All backend services restarted.');
533
- }
534
-
535
379
  console.log(chalk.green.bold('\n✓ Repoburg update complete!'));
380
+ console.log(chalk.cyan('Please restart the Repoburg Daemon via the desktop application to apply the changes.'));
536
381
 
537
382
  } catch (error) {
538
383
  console.error(chalk.red('\nUpdate process failed:'), error.message);
539
- console.error(chalk.yellow('Your services might be in a stopped state. Please check with `repoburg list` and `repoburg daemon status`.'));
540
- process.exit(1);
541
- }
542
- });
543
-
544
- // --- Daemon Management ---
545
- const daemon = program.command('daemon')
546
- .description('Manage the Repoburg Platform Daemon process (the service running on port 9998).');
547
-
548
- daemon
549
- .command('start')
550
- .description('Start the daemon process in the background using pm2.')
551
- .action(async () => {
552
- const { default: chalk } = await import('chalk');
553
- try {
554
- await startDaemon();
555
- console.log(chalk.cyan(`Run 'repoburg daemon status' to check its state.`));
556
- } catch (error) {
557
- console.error(chalk.red('An error occurred:'), error.message);
558
- process.exit(1);
559
- }
560
- });
561
-
562
- daemon
563
- .command('status')
564
- .description('Show the status of the daemon process.')
565
- .action(async () => {
566
- const { default: chalk } = await import('chalk');
567
- const Table = require('cli-table3');
568
- try {
569
- await connectToPm2();
570
- pm2.list((err, list) => {
571
- if (err) {
572
- console.error(chalk.red('Error listing pm2 processes:'), err.message || err);
573
- pm2.disconnect();
574
- process.exit(1);
575
- }
576
-
577
- const daemonProcess = list.find(p => p.name === DAEMON_PM2_NAME);
578
- if (!daemonProcess) {
579
- console.log(chalk.yellow(`Daemon process "${DAEMON_PM2_NAME}" is not running or not managed by pm2.`));
580
- } else {
581
- const table = new Table({
582
- head: ['NAME', 'STATUS', 'PID', 'CPU', 'MEMORY'].map(h => chalk.cyan(h)),
583
- colWidths: [20, 12, 8, 8, 15]
584
- });
585
- const status = daemonProcess.pm2_env.status;
586
- const statusColor = status === 'online' ? chalk.green : chalk.yellow;
587
- table.push([
588
- daemonProcess.name,
589
- statusColor(status),
590
- daemonProcess.pid,
591
- `${daemonProcess.monit.cpu || 0}%`,
592
- `${(daemonProcess.monit.memory / 1024 / 1024).toFixed(1)} MB`
593
- ]);
594
- console.log(table.toString());
595
- }
596
- pm2.disconnect();
597
- });
598
- } catch (error) {
599
- console.error(chalk.red('An error occurred:'), error.message);
600
- process.exit(1);
601
- }
602
- });
603
-
604
- daemon
605
- .command('stop')
606
- .description('Stop the daemon process.')
607
- .action(async () => {
608
- const { default: chalk } = await import('chalk');
609
- try {
610
- await connectToPm2();
611
- console.log(chalk.cyan(`Stopping daemon process "${DAEMON_PM2_NAME}"...`));
612
- pm2.stop(DAEMON_PM2_NAME, (err) => {
613
- const errMsg = err ? (err.message || err.msg) : null;
614
- if (err) {
615
- if (errMsg && errMsg.includes('not found')) {
616
- console.log(chalk.yellow(`Daemon process "${DAEMON_PM2_NAME}" not found or not running.`));
617
- } else {
618
- console.error(chalk.red('Error stopping daemon:'), errMsg || err);
619
- pm2.disconnect();
620
- process.exit(1);
621
- }
622
- } else {
623
- console.log(chalk.green('✓ Daemon stopped.'));
624
- }
625
- pm2.disconnect();
626
- });
627
- } catch (error) {
628
- console.error(chalk.red('An error occurred:'), error.message);
629
- process.exit(1);
630
- }
631
- });
632
-
633
- daemon
634
- .command('restart')
635
- .description('Restart the daemon process.')
636
- .action(async () => {
637
- const { default: chalk } = await import('chalk');
638
- try {
639
- await connectToPm2();
640
- console.log(chalk.cyan(`Restarting daemon process "${DAEMON_PM2_NAME}"...`));
641
- pm2.restart(DAEMON_PM2_NAME, (err) => {
642
- const errMsg = err ? (err.message || err.msg) : null;
643
- if (err) {
644
- if (errMsg && errMsg.includes('not found')) {
645
- console.log(chalk.yellow(`Daemon process "${DAEMON_PM2_NAME}" not found. Use 'repoburg daemon start' instead.`));
646
- } else {
647
- console.error(chalk.red('Error restarting daemon:'), errMsg || err);
648
- pm2.disconnect();
649
- process.exit(1);
650
- }
651
- } else {
652
- console.log(chalk.green('✓ Daemon restarted.'));
653
- }
654
- pm2.disconnect();
655
- });
656
- } catch (error) {
657
- console.error(chalk.red('An error occurred:'), error.message);
658
- process.exit(1);
659
- }
660
- });
661
-
662
- daemon
663
- .command('delete')
664
- .alias('rm')
665
- .description('Stop and delete the daemon process from pm2.')
666
- .action(async () => {
667
- const { default: chalk } = await import('chalk');
668
- try {
669
- await connectToPm2();
670
- console.log(chalk.cyan(`Deleting daemon process "${DAEMON_PM2_NAME}" from pm2...`));
671
- pm2.delete(DAEMON_PM2_NAME, (err) => {
672
- const errMsg = err ? (err.message || err.msg) : null;
673
- if (err) {
674
- if (errMsg && errMsg.includes('not found')) {
675
- console.log(chalk.yellow(`Daemon process "${DAEMON_PM2_NAME}" not found.`));
676
- } else {
677
- console.error(chalk.red('Error deleting daemon:'), errMsg || err);
678
- pm2.disconnect();
679
- process.exit(1);
680
- }
681
- } else {
682
- console.log(chalk.green('✓ Daemon process deleted from pm2.'));
683
- }
684
- pm2.disconnect();
685
- });
686
- } catch (error) {
687
- console.error(chalk.red('An error occurred:'), error.message);
688
- process.exit(1);
689
- }
690
- });
691
-
692
- daemon
693
- .command('logs')
694
- .description('Display logs for the daemon process.')
695
- .action(async () => {
696
- const { default: chalk } = await import('chalk');
697
- try {
698
- await connectToPm2();
699
- pm2.describe(DAEMON_PM2_NAME, async (err, description) => {
700
- if (err) {
701
- console.error(chalk.red('Error describing daemon process:'), err.message || err);
702
- pm2.disconnect();
703
- process.exit(1);
704
- }
705
-
706
- if (!description || description.length === 0) {
707
- console.log(chalk.yellow(`Daemon process "${DAEMON_PM2_NAME}" not found.`));
708
- pm2.disconnect();
709
- return;
710
- }
711
-
712
- const proc = description[0];
713
- const outLogPath = proc.pm2_env.pm_out_log_path;
714
- const errLogPath = proc.pm2_env.pm_err_log_path;
715
-
716
- console.log(chalk.cyan(`--- Logs for ${DAEMON_PM2_NAME} ---`));
717
-
718
- const readAndPrint = async (filePath, logType) => {
719
- try {
720
- const content = await fs.readFile(filePath, 'utf-8');
721
- console.log(chalk.bold.yellow(`\n--- ${logType} Log (${filePath}) ---\n`));
722
- console.log(content || chalk.gray('(empty)'));
723
- } catch (e) {
724
- if (e.code !== 'ENOENT') {
725
- throw e;
726
- }
727
- console.log(chalk.bold.yellow(`\n--- ${logType} Log (${filePath}) ---\n`));
728
- console.log(chalk.gray('(not found)'));
729
- }
730
- };
731
-
732
- await readAndPrint(outLogPath, 'Output');
733
- await readAndPrint(errLogPath, 'Error');
734
-
735
- pm2.disconnect();
736
- });
737
- } catch (error) {
738
- console.error(chalk.red('An error occurred:'), error.message);
739
384
  process.exit(1);
740
385
  }
741
386
  });
742
387
 
743
- program.parse(process.argv);
388
+ program.parse(process.argv);