groove-dev 0.27.113 → 0.27.115

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 (66) hide show
  1. package/CENTRAL_COMMAND_REBUILD.md +689 -0
  2. package/EMBEDDING_DIAGNOSTIC.md +197 -0
  3. package/TRAINING_DATA_v4.md +3 -0
  4. package/node_modules/@groove-dev/cli/package.json +1 -1
  5. package/node_modules/@groove-dev/cli/src/commands/team.js +43 -1
  6. package/node_modules/@groove-dev/daemon/package.json +1 -1
  7. package/node_modules/@groove-dev/daemon/src/api.js +24 -0
  8. package/node_modules/@groove-dev/daemon/src/filewatcher.js +45 -0
  9. package/node_modules/@groove-dev/daemon/src/index.js +14 -2
  10. package/node_modules/@groove-dev/daemon/src/teams.js +100 -6
  11. package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +75 -43
  12. package/node_modules/@groove-dev/gui/dist/assets/{index-BYh6iHqL.js → index-BKCiOUDb.js} +593 -593
  13. package/node_modules/@groove-dev/gui/dist/assets/index-D4Q72afD.css +1 -0
  14. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  15. package/node_modules/@groove-dev/gui/package.json +1 -1
  16. package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +0 -22
  17. package/node_modules/@groove-dev/gui/src/components/layout/status-bar.jsx +43 -45
  18. package/node_modules/@groove-dev/gui/src/components/settings/quick-connect.jsx +2 -1
  19. package/node_modules/@groove-dev/gui/src/stores/groove.js +42 -8
  20. package/node_modules/@groove-dev/gui/src/views/agents.jsx +31 -3
  21. package/node_modules/@groove-dev/gui/src/views/editor.jsx +1 -20
  22. package/node_modules/@groove-dev/gui/src/views/teams.jsx +106 -3
  23. package/package.json +1 -1
  24. package/packages/cli/package.json +1 -1
  25. package/packages/cli/src/commands/team.js +43 -1
  26. package/packages/daemon/package.json +1 -1
  27. package/packages/daemon/src/api.js +24 -0
  28. package/packages/daemon/src/filewatcher.js +45 -0
  29. package/packages/daemon/src/index.js +14 -2
  30. package/packages/daemon/src/teams.js +100 -6
  31. package/packages/daemon/src/tunnel-manager.js +75 -43
  32. package/packages/gui/dist/assets/{index-BYh6iHqL.js → index-BKCiOUDb.js} +593 -593
  33. package/packages/gui/dist/assets/index-D4Q72afD.css +1 -0
  34. package/packages/gui/dist/index.html +2 -2
  35. package/packages/gui/package.json +1 -1
  36. package/packages/gui/src/components/agents/workspace-mode.jsx +0 -22
  37. package/packages/gui/src/components/layout/status-bar.jsx +43 -45
  38. package/packages/gui/src/components/settings/quick-connect.jsx +2 -1
  39. package/packages/gui/src/stores/groove.js +42 -8
  40. package/packages/gui/src/views/agents.jsx +31 -3
  41. package/packages/gui/src/views/editor.jsx +1 -20
  42. package/packages/gui/src/views/teams.jsx +106 -3
  43. package/TRAINING_DATA_v3.md +0 -11
  44. package/codex-test/offroad-nitro-racer/dist/assets/index-CuvdKK6U.js +0 -44
  45. package/codex-test/offroad-nitro-racer/dist/assets/index-DvHn2Thu.css +0 -1
  46. package/codex-test/offroad-nitro-racer/dist/index.html +0 -23
  47. package/codex-test/offroad-nitro-racer/index.html +0 -21
  48. package/codex-test/offroad-nitro-racer/package-lock.json +0 -841
  49. package/codex-test/offroad-nitro-racer/package.json +0 -15
  50. package/codex-test/offroad-nitro-racer/src/game/AI.ts +0 -28
  51. package/codex-test/offroad-nitro-racer/src/game/Audio.ts +0 -63
  52. package/codex-test/offroad-nitro-racer/src/game/Car.ts +0 -247
  53. package/codex-test/offroad-nitro-racer/src/game/Effects.ts +0 -62
  54. package/codex-test/offroad-nitro-racer/src/game/Game.ts +0 -229
  55. package/codex-test/offroad-nitro-racer/src/game/Input.ts +0 -45
  56. package/codex-test/offroad-nitro-racer/src/game/Renderer.ts +0 -224
  57. package/codex-test/offroad-nitro-racer/src/game/Track.ts +0 -158
  58. package/codex-test/offroad-nitro-racer/src/game/UI.ts +0 -96
  59. package/codex-test/offroad-nitro-racer/src/game/math.ts +0 -42
  60. package/codex-test/offroad-nitro-racer/src/main.ts +0 -24
  61. package/codex-test/offroad-nitro-racer/src/style.css +0 -291
  62. package/codex-test/offroad-nitro-racer/src/vite-env.d.ts +0 -1
  63. package/codex-test/offroad-nitro-racer/tsconfig.json +0 -18
  64. package/codex-test/offroad-nitro-racer/vite.config.ts +0 -7
  65. package/node_modules/@groove-dev/gui/dist/assets/index-DAlSbVyK.css +0 -1
  66. package/packages/gui/dist/assets/index-DAlSbVyK.css +0 -1
@@ -3,15 +3,13 @@
3
3
 
4
4
  import { execFileSync, spawn } from 'child_process';
5
5
  import { existsSync, writeFileSync, readFileSync, statSync } from 'fs';
6
- import { resolve, dirname, join } from 'path';
7
- import { fileURLToPath } from 'url';
6
+ import { resolve } from 'path';
8
7
  import { createConnection } from 'net';
9
8
  import crypto from 'crypto';
10
9
 
11
- const __dirname = dirname(fileURLToPath(import.meta.url));
12
10
  function getLocalVersion() {
13
11
  try {
14
- const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', '..', 'package.json'), 'utf8'));
12
+ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
15
13
  return pkg.version || '0.0.0';
16
14
  } catch { return '0.0.0'; }
17
15
  }
@@ -34,6 +32,11 @@ function validateField(value, name) {
34
32
  }
35
33
  }
36
34
 
35
+ function sshCmd(cmd) {
36
+ const nvmProbe = 'export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"; [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"; ';
37
+ return `bash -lc '${nvmProbe}${cmd}'`;
38
+ }
39
+
37
40
  export class TunnelManager {
38
41
  constructor(daemon) {
39
42
  this.daemon = daemon;
@@ -217,7 +220,7 @@ export class TunnelManager {
217
220
  '-o', 'StrictHostKeyChecking=accept-new',
218
221
  '-o', 'BatchMode=yes',
219
222
  target,
220
- `bash -lc 'S=$(curl -sf http://localhost:${REMOTE_PORT}/api/status 2>/dev/null); if [ -n "$S" ]; then echo "__GROOVE_RUNNING__$S__GROOVE_END__"; else which groove >/dev/null 2>&1 && echo __GROOVE_VER__$(groove --version 2>/dev/null || echo unknown)__GROOVE_STOPPED__ || echo __GROOVE_NOT_INSTALLED__; fi'`,
223
+ sshCmd(`S=$(curl -sf http://localhost:${REMOTE_PORT}/api/status 2>/dev/null); if [ -n "$S" ]; then echo "__GROOVE_RUNNING__$S__GROOVE_END__"; else which groove >/dev/null 2>&1 && echo __GROOVE_VER__$(groove --version 2>/dev/null || echo unknown)__GROOVE_STOPPED__ || echo __GROOVE_NOT_INSTALLED__; fi`),
221
224
  ], {
222
225
  encoding: 'utf8',
223
226
  timeout: 20000,
@@ -412,7 +415,7 @@ export class TunnelManager {
412
415
  const installCmd = config.user === 'root' ? `npm i -g --prefer-online ${pinnedPkg}` : `sudo npm i -g --prefer-online ${pinnedPkg}`;
413
416
 
414
417
  try {
415
- execFileSync('ssh', [...sshBase, `bash -lc '${installCmd}'`], {
418
+ execFileSync('ssh', [...sshBase, sshCmd(installCmd)], {
416
419
  encoding: 'utf8',
417
420
  timeout: 120000,
418
421
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -420,14 +423,14 @@ export class TunnelManager {
420
423
  } catch {
421
424
  const fallbackPkg = 'groove-dev';
422
425
  const fallbackCmd = config.user === 'root' ? `npm i -g --prefer-online ${fallbackPkg}` : `sudo npm i -g --prefer-online ${fallbackPkg}`;
423
- execFileSync('ssh', [...sshBase, `bash -lc '${fallbackCmd}'`], {
426
+ execFileSync('ssh', [...sshBase, sshCmd(fallbackCmd)], {
424
427
  encoding: 'utf8',
425
428
  timeout: 120000,
426
429
  stdio: ['pipe', 'pipe', 'pipe'],
427
430
  });
428
431
  }
429
432
 
430
- const verOutput = execFileSync('ssh', [...sshBase, `bash -lc 'groove --version'`], {
433
+ const verOutput = execFileSync('ssh', [...sshBase, sshCmd('groove --version')], {
431
434
  encoding: 'utf8',
432
435
  timeout: 10000,
433
436
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -438,8 +441,8 @@ export class TunnelManager {
438
441
  this.daemon.broadcast({ type: 'tunnel.version-mismatch', data: { id, localVersion: localVer, remoteVersion: installedVer, message: 'Pinned version not available on npm, installed latest' } });
439
442
  }
440
443
 
441
- const restartCmd = `kill $(lsof -t -i:${REMOTE_PORT}) 2>/dev/null || true; sleep 2; nohup groove start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 4; curl -sf http://localhost:${REMOTE_PORT}/api/status`;
442
- const restartResult = execFileSync('ssh', [...sshBase, `bash -lc '${restartCmd}'`], {
444
+ const restartCmd = `kill $(lsof -t -i:${REMOTE_PORT}) 2>/dev/null || true; sleep 2; GROOVE_BIN=$(which groove) && nohup "$GROOVE_BIN" start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 4; curl -sf http://localhost:${REMOTE_PORT}/api/status`;
445
+ const restartResult = execFileSync('ssh', [...sshBase, sshCmd(restartCmd)], {
443
446
  encoding: 'utf8',
444
447
  timeout: 60000,
445
448
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -484,30 +487,40 @@ export class TunnelManager {
484
487
 
485
488
  let usedFallback = false;
486
489
  try {
487
- execFileSync('ssh', [...sshBase, `bash -lc '${installCmd}'`], {
490
+ execFileSync('ssh', [...sshBase, sshCmd(installCmd)], {
488
491
  encoding: 'utf8',
489
492
  timeout: 120000,
490
493
  stdio: ['pipe', 'pipe', 'pipe'],
491
494
  });
492
495
  } catch (err) {
493
- if (localVer !== '0.0.0' && pkg.includes('@')) {
494
- const fallbackCmd = config.user === 'root' ? 'npm i -g --prefer-online groove-dev' : 'sudo npm i -g --prefer-online groove-dev';
496
+ const errOutput = err.stdout?.toString() || err.stderr?.toString() || err.message;
497
+ if (errOutput.includes('ENOTEMPTY')) {
495
498
  try {
496
- execFileSync('ssh', [...sshBase, `bash -lc '${fallbackCmd}'`], {
497
- encoding: 'utf8',
498
- timeout: 120000,
499
- stdio: ['pipe', 'pipe', 'pipe'],
500
- });
501
- usedFallback = true;
502
- } catch { /* fall through to original error */ }
503
- }
504
- if (!usedFallback) {
505
- const output = err.stdout?.toString() || err.stderr?.toString() || err.message;
506
- throw new Error(`Remote upgrade failed: ${output.slice(-400)}`);
499
+ execFileSync('ssh', [...sshBase, sshCmd('rm -rf $(npm root -g)/.groove-dev-* $(npm root -g)/groove-dev 2>/dev/null || true')], { encoding: 'utf8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'] });
500
+ execFileSync('ssh', [...sshBase, sshCmd(installCmd)], { encoding: 'utf8', timeout: 120000, stdio: ['pipe', 'pipe', 'pipe'] });
501
+ } catch (retryErr) {
502
+ const retryOutput = retryErr.stdout?.toString() || retryErr.stderr?.toString() || retryErr.message;
503
+ throw new Error(`Remote upgrade failed after cleanup: ${retryOutput.slice(-400)}`);
504
+ }
505
+ } else {
506
+ if (localVer !== '0.0.0' && pkg.includes('@')) {
507
+ const fallbackCmd = config.user === 'root' ? 'npm i -g --prefer-online groove-dev' : 'sudo npm i -g --prefer-online groove-dev';
508
+ try {
509
+ execFileSync('ssh', [...sshBase, sshCmd(fallbackCmd)], {
510
+ encoding: 'utf8',
511
+ timeout: 120000,
512
+ stdio: ['pipe', 'pipe', 'pipe'],
513
+ });
514
+ usedFallback = true;
515
+ } catch { /* fall through to original error */ }
516
+ }
517
+ if (!usedFallback) {
518
+ throw new Error(`Remote upgrade failed: ${errOutput.slice(-400)}`);
519
+ }
507
520
  }
508
521
  }
509
522
 
510
- const verOutput = execFileSync('ssh', [...sshBase, `bash -lc 'groove --version'`], {
523
+ const verOutput = execFileSync('ssh', [...sshBase, sshCmd('groove --version')], {
511
524
  encoding: 'utf8',
512
525
  timeout: 10000,
513
526
  stdio: ['pipe', 'pipe', 'pipe'],
@@ -537,7 +550,7 @@ export class TunnelManager {
537
550
  ? `curl -sf -X POST -H 'Content-Type: application/json' --data '{"path":"${config.projectDir}"}' http://localhost:${REMOTE_PORT}/api/project-dir > /dev/null 2>&1 || true; `
538
551
  : '';
539
552
  const remoteCmd =
540
- `${cdPrefix}nohup groove start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; ` +
553
+ `${cdPrefix}GROOVE_BIN=$(which groove) && nohup "$GROOVE_BIN" start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; ` +
541
554
  `sleep 5; ` +
542
555
  `curl -sf http://localhost:${REMOTE_PORT}/api/health > /dev/null ` +
543
556
  `&& (${setProjectDir}echo __DAEMON_OK__) ` +
@@ -550,7 +563,7 @@ export class TunnelManager {
550
563
  '-o', 'ConnectTimeout=10',
551
564
  '-o', 'BatchMode=yes',
552
565
  target,
553
- `bash -lc '${remoteCmd}'`,
566
+ sshCmd(remoteCmd),
554
567
  ], {
555
568
  encoding: 'utf8',
556
569
  timeout: 45000,
@@ -585,7 +598,7 @@ export class TunnelManager {
585
598
 
586
599
  // Non-interactive SSH doesn't source shell profiles, so npm/node may not be on PATH.
587
600
  // Use a login shell (-l) to get the user's full environment.
588
- const remoteCmd = (cmd) => `bash -lc '${cmd}'`;
601
+ const remoteCmd = (cmd) => sshCmd(cmd);
589
602
 
590
603
  // Step 1: Check if node/npm are available
591
604
  try {
@@ -623,7 +636,16 @@ export class TunnelManager {
623
636
  stdio: ['pipe', 'pipe', 'pipe'],
624
637
  });
625
638
  } catch (err) {
626
- if (localVer !== '0.0.0' && pkg.includes('@')) {
639
+ const errOutput = err.stdout?.toString() || err.stderr?.toString() || err.message;
640
+ if (errOutput.includes('ENOTEMPTY')) {
641
+ try {
642
+ execFileSync('ssh', [...sshBase, remoteCmd('rm -rf $(npm root -g)/.groove-dev-* $(npm root -g)/groove-dev 2>/dev/null || true')], { encoding: 'utf8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'] });
643
+ execFileSync('ssh', [...sshBase, remoteCmd(installCmd)], { encoding: 'utf8', timeout: 120000, stdio: ['pipe', 'pipe', 'pipe'] });
644
+ } catch (retryErr) {
645
+ const retryOutput = retryErr.stdout?.toString() || retryErr.stderr?.toString() || retryErr.message;
646
+ throw new Error(`npm install failed after cleanup: ${retryOutput.slice(-400)}`);
647
+ }
648
+ } else if (localVer !== '0.0.0' && pkg.includes('@')) {
627
649
  const fallbackCmd = config.user === 'root' ? 'npm i -g --prefer-online groove-dev' : 'sudo npm i -g --prefer-online groove-dev';
628
650
  try {
629
651
  execFileSync('ssh', [...sshBase, remoteCmd(fallbackCmd)], {
@@ -636,8 +658,7 @@ export class TunnelManager {
636
658
  throw new Error(`npm install failed: ${output.slice(-400)}`);
637
659
  }
638
660
  } else {
639
- const output = err.stdout?.toString() || err.stderr?.toString() || err.message;
640
- throw new Error(`npm install failed: ${output.slice(-400)}`);
661
+ throw new Error(`npm install failed: ${errOutput.slice(-400)}`);
641
662
  }
642
663
  }
643
664
 
@@ -645,7 +666,7 @@ export class TunnelManager {
645
666
  try {
646
667
  const result = execFileSync('ssh', [
647
668
  ...sshBase,
648
- remoteCmd(`nohup groove start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 5; curl -sf http://localhost:${REMOTE_PORT}/api/health > /dev/null && echo __DAEMON_OK__ || (echo __DAEMON_FAIL__; tail -20 /tmp/groove-daemon.log 2>/dev/null)`),
669
+ remoteCmd(`GROOVE_BIN=$(which groove) && nohup "$GROOVE_BIN" start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 5; curl -sf http://localhost:${REMOTE_PORT}/api/health > /dev/null && echo __DAEMON_OK__ || (echo __DAEMON_FAIL__; tail -20 /tmp/groove-daemon.log 2>/dev/null)`),
649
670
  ], {
650
671
  encoding: 'utf8',
651
672
  timeout: 45000,
@@ -683,29 +704,40 @@ export class TunnelManager {
683
704
  const installCmd = config.user === 'root' ? `npm i -g --prefer-online ${pinnedPkg}` : `sudo npm i -g --prefer-online ${pinnedPkg}`;
684
705
 
685
706
  try {
686
- execFileSync('ssh', [...sshBase, `bash -lc '${installCmd}'`], {
687
- encoding: 'utf8',
688
- timeout: 120000,
689
- stdio: ['pipe', 'pipe', 'pipe'],
690
- });
691
- } catch {
692
- const fallbackCmd = config.user === 'root' ? 'npm i -g --prefer-online groove-dev' : 'sudo npm i -g --prefer-online groove-dev';
693
- execFileSync('ssh', [...sshBase, `bash -lc '${fallbackCmd}'`], {
707
+ execFileSync('ssh', [...sshBase, sshCmd(installCmd)], {
694
708
  encoding: 'utf8',
695
709
  timeout: 120000,
696
710
  stdio: ['pipe', 'pipe', 'pipe'],
697
711
  });
712
+ } catch (err) {
713
+ const errOutput = err.stdout?.toString() || err.stderr?.toString() || err.message;
714
+ if (errOutput.includes('ENOTEMPTY')) {
715
+ try {
716
+ execFileSync('ssh', [...sshBase, sshCmd('rm -rf $(npm root -g)/.groove-dev-* $(npm root -g)/groove-dev 2>/dev/null || true')], { encoding: 'utf8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'] });
717
+ execFileSync('ssh', [...sshBase, sshCmd(installCmd)], { encoding: 'utf8', timeout: 120000, stdio: ['pipe', 'pipe', 'pipe'] });
718
+ } catch (retryErr) {
719
+ const retryOutput = retryErr.stdout?.toString() || retryErr.stderr?.toString() || retryErr.message;
720
+ throw new Error(`npm install failed after cleanup: ${retryOutput.slice(-400)}`);
721
+ }
722
+ } else {
723
+ const fallbackCmd = config.user === 'root' ? 'npm i -g --prefer-online groove-dev' : 'sudo npm i -g --prefer-online groove-dev';
724
+ execFileSync('ssh', [...sshBase, sshCmd(fallbackCmd)], {
725
+ encoding: 'utf8',
726
+ timeout: 120000,
727
+ stdio: ['pipe', 'pipe', 'pipe'],
728
+ });
729
+ }
698
730
  }
699
731
 
700
- const verOutput = execFileSync('ssh', [...sshBase, `bash -lc 'groove --version'`], {
732
+ const verOutput = execFileSync('ssh', [...sshBase, sshCmd('groove --version')], {
701
733
  encoding: 'utf8',
702
734
  timeout: 10000,
703
735
  stdio: ['pipe', 'pipe', 'pipe'],
704
736
  }).trim();
705
737
  const installedVer = verOutput.replace(/[^0-9.]/g, '') || verOutput.trim();
706
738
 
707
- const restartCmd = `kill $(lsof -t -i:${REMOTE_PORT}) 2>/dev/null || true; sleep 2; nohup groove start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 4; curl -sf http://localhost:${REMOTE_PORT}/api/status`;
708
- const restartResult = execFileSync('ssh', [...sshBase, `bash -lc '${restartCmd}'`], {
739
+ const restartCmd = `kill $(lsof -t -i:${REMOTE_PORT}) 2>/dev/null || true; sleep 2; GROOVE_BIN=$(which groove) && nohup "$GROOVE_BIN" start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown; sleep 4; curl -sf http://localhost:${REMOTE_PORT}/api/status`;
740
+ const restartResult = execFileSync('ssh', [...sshBase, sshCmd(restartCmd)], {
709
741
  encoding: 'utf8',
710
742
  timeout: 60000,
711
743
  stdio: ['pipe', 'pipe', 'pipe'],