groove-dev 0.27.165 → 0.27.168
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/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/adaptive.js +37 -10
- package/node_modules/@groove-dev/daemon/src/classifier.js +3 -1
- package/node_modules/@groove-dev/daemon/src/index.js +10 -9
- package/node_modules/@groove-dev/daemon/src/memory.js +9 -1
- package/node_modules/@groove-dev/daemon/src/process.js +14 -5
- package/node_modules/@groove-dev/daemon/src/registry.js +18 -3
- package/node_modules/@groove-dev/daemon/src/rotator.js +81 -10
- package/node_modules/@groove-dev/daemon/src/routes/agents.js +38 -25
- package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +28 -21
- package/node_modules/@groove-dev/daemon/test/rotator.test.js +1 -1
- package/node_modules/@groove-dev/gui/dist/assets/{index-SZBexPhJ.js → index-CSMIQsrG.js} +94 -94
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/editor/terminal.jsx +32 -2
- package/node_modules/@groove-dev/gui/src/components/fleet/fleet-content.jsx +4 -1
- package/node_modules/@groove-dev/gui/src/components/fleet/fleet-pane.jsx +11 -6
- package/node_modules/@groove-dev/gui/src/stores/groove.js +8 -4
- package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +9 -0
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/adaptive.js +37 -10
- package/packages/daemon/src/classifier.js +3 -1
- package/packages/daemon/src/index.js +10 -9
- package/packages/daemon/src/memory.js +9 -1
- package/packages/daemon/src/process.js +14 -5
- package/packages/daemon/src/registry.js +18 -3
- package/packages/daemon/src/rotator.js +81 -10
- package/packages/daemon/src/routes/agents.js +38 -25
- package/packages/daemon/src/tunnel-manager.js +28 -21
- package/packages/gui/dist/assets/{index-SZBexPhJ.js → index-CSMIQsrG.js} +94 -94
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-panel.jsx +1 -1
- package/packages/gui/src/components/editor/terminal.jsx +32 -2
- package/packages/gui/src/components/fleet/fleet-content.jsx +4 -1
- package/packages/gui/src/components/fleet/fleet-pane.jsx +11 -6
- package/packages/gui/src/stores/groove.js +8 -4
- package/packages/gui/src/stores/slices/agents-slice.js +9 -0
- package/terminal/Screenshot_2026-05-19_at_12.20.15_PM.png +0 -0
|
@@ -428,6 +428,7 @@ export function registerAgentRoutes(app, daemon) {
|
|
|
428
428
|
|
|
429
429
|
// Record user feedback so the journalist can include it in future agent context
|
|
430
430
|
if (daemon.journalist) daemon.journalist.recordUserFeedback(agent, finalMessage);
|
|
431
|
+
if (daemon.rotator) daemon.rotator.recordUserMessage(req.params.id);
|
|
431
432
|
|
|
432
433
|
// Agent loop path — send message directly to the running loop
|
|
433
434
|
const wrappedMessage = wrapWithRoleReminder(agent.role, finalMessage);
|
|
@@ -449,20 +450,26 @@ export function registerAgentRoutes(app, daemon) {
|
|
|
449
450
|
if (daemon.processes.isRunning(req.params.id)) {
|
|
450
451
|
await daemon.processes.kill(req.params.id);
|
|
451
452
|
}
|
|
452
|
-
daemon.registry.remove(req.params.id);
|
|
453
|
+
daemon.registry.remove(req.params.id, { silent: true });
|
|
453
454
|
daemon.locks.release(req.params.id);
|
|
454
455
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
456
|
+
let newAgent;
|
|
457
|
+
try {
|
|
458
|
+
newAgent = await daemon.processes.spawn({
|
|
459
|
+
role: oldConfig.role,
|
|
460
|
+
scope: oldConfig.scope,
|
|
461
|
+
provider: oldConfig.provider,
|
|
462
|
+
model: oldConfig.model,
|
|
463
|
+
prompt: finalMessage,
|
|
464
|
+
permission: oldConfig.permission || 'full',
|
|
465
|
+
workingDir: oldConfig.workingDir,
|
|
466
|
+
name: oldConfig.name,
|
|
467
|
+
teamId: oldConfig.teamId,
|
|
468
|
+
});
|
|
469
|
+
} catch (spawnErr) {
|
|
470
|
+
daemon.registry.flushPendingRemovals();
|
|
471
|
+
throw spawnErr;
|
|
472
|
+
}
|
|
466
473
|
daemon.audit.log('agent.instruct', { id: req.params.id, newId: newAgent.id, resumed: false });
|
|
467
474
|
return res.json(newAgent);
|
|
468
475
|
}
|
|
@@ -472,21 +479,27 @@ export function registerAgentRoutes(app, daemon) {
|
|
|
472
479
|
// run one prompt per spawn and cannot resume sessions.
|
|
473
480
|
if (provider?.constructor?.nonInteractive && !daemon.processes.isRunning(req.params.id)) {
|
|
474
481
|
const oldConfig = { ...agent };
|
|
475
|
-
daemon.registry.remove(req.params.id);
|
|
482
|
+
daemon.registry.remove(req.params.id, { silent: true });
|
|
476
483
|
daemon.locks.release(req.params.id);
|
|
477
484
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
485
|
+
let newAgent;
|
|
486
|
+
try {
|
|
487
|
+
newAgent = await daemon.processes.spawn({
|
|
488
|
+
role: oldConfig.role,
|
|
489
|
+
scope: oldConfig.scope,
|
|
490
|
+
provider: oldConfig.provider,
|
|
491
|
+
model: oldConfig.model,
|
|
492
|
+
prompt: finalMessage,
|
|
493
|
+
introContext: oldConfig.introContext,
|
|
494
|
+
permission: oldConfig.permission || 'full',
|
|
495
|
+
workingDir: oldConfig.workingDir,
|
|
496
|
+
name: oldConfig.name,
|
|
497
|
+
teamId: oldConfig.teamId,
|
|
498
|
+
});
|
|
499
|
+
} catch (spawnErr) {
|
|
500
|
+
daemon.registry.flushPendingRemovals();
|
|
501
|
+
throw spawnErr;
|
|
502
|
+
}
|
|
490
503
|
daemon.audit.log('agent.instruct', { id: req.params.id, newId: newAgent.id, resumed: false });
|
|
491
504
|
return res.json(newAgent);
|
|
492
505
|
}
|
|
@@ -479,6 +479,10 @@ export class TunnelManager {
|
|
|
479
479
|
// Remote is behind npm — upgrade
|
|
480
480
|
this.daemon.broadcast({ type: 'tunnel.status', data: { id, step: 'upgrading', from: remoteVer, to: npmVer } });
|
|
481
481
|
|
|
482
|
+
const target = `${config.user}@${config.host}`;
|
|
483
|
+
const keyArgs = config.sshKeyPath ? ['-i', config.sshKeyPath] : [];
|
|
484
|
+
const sshBase = [...keyArgs, '-p', String(config.port || 22), '-o', 'ConnectTimeout=10', '-o', 'BatchMode=yes', target];
|
|
485
|
+
|
|
482
486
|
const installCmd = npmGlobalInstall(`groove-dev@${npmVer}`, config.user);
|
|
483
487
|
const cleanupCmd = 'rm -rf $(npm root -g)/.groove-dev-* $(npm root -g)/groove-dev 2>/dev/null || true';
|
|
484
488
|
|
|
@@ -496,40 +500,43 @@ export class TunnelManager {
|
|
|
496
500
|
}
|
|
497
501
|
}
|
|
498
502
|
|
|
499
|
-
// Restart remote daemon
|
|
503
|
+
// Restart remote daemon — fire and forget the SSH, verify through the tunnel
|
|
500
504
|
const cdPrefix = config.projectDir ? `cd "${config.projectDir}" && ` : '';
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
encoding: 'utf8', timeout: 60000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
507
|
-
});
|
|
505
|
+
try {
|
|
506
|
+
execFileSync('ssh', [...sshBase, sshCmd(`kill $(lsof -t -i:${REMOTE_PORT}) 2>/dev/null || true; sleep 1; ${cdPrefix}GROOVE_BIN=$(which groove) && nohup "$GROOVE_BIN" start > /tmp/groove-daemon.log 2>&1 < /dev/null & disown`)], {
|
|
507
|
+
encoding: 'utf8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
508
|
+
});
|
|
509
|
+
} catch { /* SSH may close before nohup finishes — that's fine */ }
|
|
508
510
|
|
|
509
|
-
//
|
|
511
|
+
// Wait for daemon to come back up through the existing tunnel
|
|
512
|
+
this.daemon.broadcast({ type: 'tunnel.status', data: { id, step: 'starting' } });
|
|
510
513
|
let daemonVer = null;
|
|
511
|
-
for (let i = 0; i <
|
|
514
|
+
for (let i = 0; i < 8; i++) {
|
|
515
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
512
516
|
try {
|
|
513
|
-
const check = await fetch(`http://localhost:${localPort}/api/status`, {
|
|
514
|
-
signal: AbortSignal.timeout(3000),
|
|
515
|
-
});
|
|
517
|
+
const check = await fetch(`http://localhost:${localPort}/api/status`, { signal: AbortSignal.timeout(3000) });
|
|
516
518
|
if (check.ok) {
|
|
517
519
|
daemonVer = (await check.json()).version || null;
|
|
518
520
|
break;
|
|
519
521
|
}
|
|
520
|
-
} catch { /*
|
|
521
|
-
await new Promise(r => setTimeout(r, 2000));
|
|
522
|
+
} catch { /* not up yet */ }
|
|
522
523
|
}
|
|
523
524
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
525
|
+
if (config.projectDir && daemonVer) {
|
|
526
|
+
try {
|
|
527
|
+
await fetch(`http://localhost:${localPort}/api/project-dir`, {
|
|
528
|
+
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
|
529
|
+
body: JSON.stringify({ path: config.projectDir }),
|
|
530
|
+
signal: AbortSignal.timeout(3000),
|
|
531
|
+
});
|
|
532
|
+
} catch { /* best effort */ }
|
|
529
533
|
}
|
|
530
534
|
|
|
535
|
+
const localVer = getLocalVersion();
|
|
536
|
+
this.daemon.broadcast({ type: 'tunnel.version-info', data: { id, localVersion: localVer, remoteVersion: daemonVer || npmVer, match: (daemonVer || npmVer) === localVer } });
|
|
531
537
|
this.daemon.audit.log('tunnel.upgrade', { id, from: remoteVer, to: daemonVer || npmVer });
|
|
532
538
|
} catch (err) {
|
|
539
|
+
// Upgrade failed but tunnel may still work — check before reporting failure
|
|
533
540
|
try {
|
|
534
541
|
const verify = await fetch(`http://localhost:${localPort}/api/status`, { signal: AbortSignal.timeout(5000) });
|
|
535
542
|
if (verify.ok) {
|
|
@@ -537,7 +544,7 @@ export class TunnelManager {
|
|
|
537
544
|
this.daemon.broadcast({ type: 'tunnel.version-info', data: { id, localVersion: getLocalVersion(), remoteVersion: verifyData.version, match: false } });
|
|
538
545
|
return;
|
|
539
546
|
}
|
|
540
|
-
} catch { /* tunnel
|
|
547
|
+
} catch { /* tunnel down */ }
|
|
541
548
|
this.daemon.broadcast({ type: 'tunnel.upgrade-failed', data: { id, error: err.message } });
|
|
542
549
|
}
|
|
543
550
|
}
|