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.
- package/CENTRAL_COMMAND_REBUILD.md +689 -0
- package/EMBEDDING_DIAGNOSTIC.md +197 -0
- package/TRAINING_DATA_v4.md +3 -0
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/cli/src/commands/team.js +43 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +24 -0
- package/node_modules/@groove-dev/daemon/src/filewatcher.js +45 -0
- package/node_modules/@groove-dev/daemon/src/index.js +14 -2
- package/node_modules/@groove-dev/daemon/src/teams.js +100 -6
- package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +75 -43
- package/node_modules/@groove-dev/gui/dist/assets/{index-BYh6iHqL.js → index-BKCiOUDb.js} +593 -593
- package/node_modules/@groove-dev/gui/dist/assets/index-D4Q72afD.css +1 -0
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +0 -22
- package/node_modules/@groove-dev/gui/src/components/layout/status-bar.jsx +43 -45
- package/node_modules/@groove-dev/gui/src/components/settings/quick-connect.jsx +2 -1
- package/node_modules/@groove-dev/gui/src/stores/groove.js +42 -8
- package/node_modules/@groove-dev/gui/src/views/agents.jsx +31 -3
- package/node_modules/@groove-dev/gui/src/views/editor.jsx +1 -20
- package/node_modules/@groove-dev/gui/src/views/teams.jsx +106 -3
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/commands/team.js +43 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +24 -0
- package/packages/daemon/src/filewatcher.js +45 -0
- package/packages/daemon/src/index.js +14 -2
- package/packages/daemon/src/teams.js +100 -6
- package/packages/daemon/src/tunnel-manager.js +75 -43
- package/packages/gui/dist/assets/{index-BYh6iHqL.js → index-BKCiOUDb.js} +593 -593
- package/packages/gui/dist/assets/index-D4Q72afD.css +1 -0
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/workspace-mode.jsx +0 -22
- package/packages/gui/src/components/layout/status-bar.jsx +43 -45
- package/packages/gui/src/components/settings/quick-connect.jsx +2 -1
- package/packages/gui/src/stores/groove.js +42 -8
- package/packages/gui/src/views/agents.jsx +31 -3
- package/packages/gui/src/views/editor.jsx +1 -20
- package/packages/gui/src/views/teams.jsx +106 -3
- package/TRAINING_DATA_v3.md +0 -11
- package/codex-test/offroad-nitro-racer/dist/assets/index-CuvdKK6U.js +0 -44
- package/codex-test/offroad-nitro-racer/dist/assets/index-DvHn2Thu.css +0 -1
- package/codex-test/offroad-nitro-racer/dist/index.html +0 -23
- package/codex-test/offroad-nitro-racer/index.html +0 -21
- package/codex-test/offroad-nitro-racer/package-lock.json +0 -841
- package/codex-test/offroad-nitro-racer/package.json +0 -15
- package/codex-test/offroad-nitro-racer/src/game/AI.ts +0 -28
- package/codex-test/offroad-nitro-racer/src/game/Audio.ts +0 -63
- package/codex-test/offroad-nitro-racer/src/game/Car.ts +0 -247
- package/codex-test/offroad-nitro-racer/src/game/Effects.ts +0 -62
- package/codex-test/offroad-nitro-racer/src/game/Game.ts +0 -229
- package/codex-test/offroad-nitro-racer/src/game/Input.ts +0 -45
- package/codex-test/offroad-nitro-racer/src/game/Renderer.ts +0 -224
- package/codex-test/offroad-nitro-racer/src/game/Track.ts +0 -158
- package/codex-test/offroad-nitro-racer/src/game/UI.ts +0 -96
- package/codex-test/offroad-nitro-racer/src/game/math.ts +0 -42
- package/codex-test/offroad-nitro-racer/src/main.ts +0 -24
- package/codex-test/offroad-nitro-racer/src/style.css +0 -291
- package/codex-test/offroad-nitro-racer/src/vite-env.d.ts +0 -1
- package/codex-test/offroad-nitro-racer/tsconfig.json +0 -18
- package/codex-test/offroad-nitro-racer/vite.config.ts +0 -7
- package/node_modules/@groove-dev/gui/dist/assets/index-DAlSbVyK.css +0 -1
- 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
|
|
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(
|
|
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
|
-
`
|
|
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,
|
|
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,
|
|
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,
|
|
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;
|
|
442
|
-
const restartResult = execFileSync('ssh', [...sshBase,
|
|
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,
|
|
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
|
-
|
|
494
|
-
|
|
496
|
+
const errOutput = err.stdout?.toString() || err.stderr?.toString() || err.message;
|
|
497
|
+
if (errOutput.includes('ENOTEMPTY')) {
|
|
495
498
|
try {
|
|
496
|
-
execFileSync('ssh', [...sshBase,
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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,
|
|
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}
|
|
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
|
-
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
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(`
|
|
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,
|
|
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,
|
|
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;
|
|
708
|
-
const restartResult = execFileSync('ssh', [...sshBase,
|
|
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'],
|