groove-dev 0.27.52 → 0.27.54
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/api.js +27 -8
- package/node_modules/@groove-dev/daemon/src/providers/groove-network.js +24 -12
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +27 -8
- package/packages/daemon/src/providers/groove-network.js +24 -12
- package/packages/gui/package.json +1 -1
|
@@ -4029,11 +4029,13 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4029
4029
|
}
|
|
4030
4030
|
|
|
4031
4031
|
const signalFlag = supportsSignalFlag(cfg.version) ? '--signal' : '--relay';
|
|
4032
|
+
const model = cfg.model || 'Qwen/Qwen2.5-0.5B';
|
|
4032
4033
|
const args = [
|
|
4033
4034
|
'-m', 'src.node.server',
|
|
4034
4035
|
signalFlag, signal,
|
|
4035
4036
|
'--tls',
|
|
4036
4037
|
'--device', device,
|
|
4038
|
+
'--model', model,
|
|
4037
4039
|
'--max-context', String(maxContext),
|
|
4038
4040
|
];
|
|
4039
4041
|
|
|
@@ -4300,6 +4302,22 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4300
4302
|
return resolve(homedir(), '.groove', 'network');
|
|
4301
4303
|
}
|
|
4302
4304
|
|
|
4305
|
+
function getInstalledNetworkVersion() {
|
|
4306
|
+
const configured = daemon.config?.networkBeta?.version || null;
|
|
4307
|
+
if (configured) return configured;
|
|
4308
|
+
const installPath = networkRoot();
|
|
4309
|
+
if (!existsSync(resolve(installPath, 'setup.sh'))) return null;
|
|
4310
|
+
try {
|
|
4311
|
+
const { execSync } = require('child_process');
|
|
4312
|
+
const v = execSync('git describe --tags --abbrev=0', {
|
|
4313
|
+
cwd: installPath, stdio: ['ignore', 'pipe', 'ignore'], timeout: 5000,
|
|
4314
|
+
}).toString().trim();
|
|
4315
|
+
return parseSemver(v) ? v : null;
|
|
4316
|
+
} catch {
|
|
4317
|
+
return null;
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
|
|
4303
4321
|
// Defensive: only permit fs ops on paths that resolve inside ~/.groove/.
|
|
4304
4322
|
// Uses realpathSync when the path exists to defeat symlink escapes.
|
|
4305
4323
|
function isInsideGrooveHome(target) {
|
|
@@ -4325,7 +4343,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4325
4343
|
res.json({
|
|
4326
4344
|
installed,
|
|
4327
4345
|
path: installed ? installPath : null,
|
|
4328
|
-
version: installed ? (
|
|
4346
|
+
version: installed ? getInstalledNetworkVersion() : null,
|
|
4329
4347
|
});
|
|
4330
4348
|
});
|
|
4331
4349
|
|
|
@@ -4565,7 +4583,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4565
4583
|
}
|
|
4566
4584
|
|
|
4567
4585
|
app.get('/api/network/update/check', networkGate, async (req, res) => {
|
|
4568
|
-
const installed =
|
|
4586
|
+
const installed = getInstalledNetworkVersion();
|
|
4569
4587
|
const force = req.query.force === '1' || req.query.force === 'true';
|
|
4570
4588
|
const latest = await getLatestNetworkTag(force);
|
|
4571
4589
|
if (!latest) {
|
|
@@ -4591,11 +4609,11 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4591
4609
|
if (daemon.networkInstall?.running) {
|
|
4592
4610
|
return res.status(409).json({ error: 'Install/update already in progress' });
|
|
4593
4611
|
}
|
|
4594
|
-
|
|
4612
|
+
const installPath = networkRoot();
|
|
4613
|
+
const hasInstall = daemon.config?.networkBeta?.installed || existsSync(resolve(installPath, 'setup.sh'));
|
|
4614
|
+
if (!hasInstall) {
|
|
4595
4615
|
return res.status(400).json({ error: 'Network package not installed' });
|
|
4596
4616
|
}
|
|
4597
|
-
|
|
4598
|
-
const installPath = networkRoot();
|
|
4599
4617
|
if (!existsSync(installPath) || !isInsideGrooveHome(installPath)) {
|
|
4600
4618
|
return res.status(400).json({ error: 'Install path missing or invalid' });
|
|
4601
4619
|
}
|
|
@@ -4604,7 +4622,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4604
4622
|
if (!latest) {
|
|
4605
4623
|
return res.status(502).json({ error: 'Could not reach github.com to check for updates' });
|
|
4606
4624
|
}
|
|
4607
|
-
const current =
|
|
4625
|
+
const current = getInstalledNetworkVersion();
|
|
4608
4626
|
if (current && compareSemver(latest, current) <= 0) {
|
|
4609
4627
|
return res.status(400).json({ error: 'Already at latest version', installed: current, latest });
|
|
4610
4628
|
}
|
|
@@ -4730,11 +4748,12 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4730
4748
|
// Startup hook — called from index.js once the server is up. Non-blocking;
|
|
4731
4749
|
// updates daemon.networkUpdateAvailable and broadcasts so the GUI can badge.
|
|
4732
4750
|
daemon.checkNetworkUpdate = async function checkNetworkUpdate() {
|
|
4733
|
-
|
|
4751
|
+
const hasInstall = daemon.config?.networkBeta?.installed || existsSync(resolve(networkRoot(), 'setup.sh'));
|
|
4752
|
+
if (!hasInstall) return;
|
|
4734
4753
|
try {
|
|
4735
4754
|
const latest = await getLatestNetworkTag(true);
|
|
4736
4755
|
if (!latest) return;
|
|
4737
|
-
const installed =
|
|
4756
|
+
const installed = getInstalledNetworkVersion();
|
|
4738
4757
|
const updateAvailable = !!installed && compareSemver(latest, installed) > 0;
|
|
4739
4758
|
daemon.networkUpdateAvailable = { installed, latest, updateAvailable };
|
|
4740
4759
|
daemon.broadcast({ type: 'network:update:available', data: daemon.networkUpdateAvailable });
|
|
@@ -152,19 +152,31 @@ export class GrooveNetworkProvider extends Provider {
|
|
|
152
152
|
}
|
|
153
153
|
try {
|
|
154
154
|
const msg = JSON.parse(trimmed);
|
|
155
|
-
if (msg
|
|
156
|
-
return {
|
|
157
|
-
type: msg.type,
|
|
158
|
-
text: msg.text,
|
|
159
|
-
sessionId: msg.session_id,
|
|
160
|
-
tokensGenerated: msg.tokens_generated,
|
|
161
|
-
error: msg.error,
|
|
162
|
-
signal: msg.signal,
|
|
163
|
-
nodesAvailable: msg.nodes_available,
|
|
164
|
-
nodes: msg.nodes,
|
|
165
|
-
raw: msg,
|
|
166
|
-
};
|
|
155
|
+
if (!msg || typeof msg !== 'object' || typeof msg.type !== 'string') {
|
|
156
|
+
return { type: 'activity', data: trimmed };
|
|
167
157
|
}
|
|
158
|
+
|
|
159
|
+
if (msg.type === 'token' && msg.text) {
|
|
160
|
+
return { type: 'activity', subtype: 'text', data: msg.text, tokensGenerated: msg.tokens_generated };
|
|
161
|
+
}
|
|
162
|
+
if (msg.type === 'complete' || msg.type === 'result') {
|
|
163
|
+
return { type: 'result', text: msg.text || '', tokensGenerated: msg.tokens_generated, sessionId: msg.session_id };
|
|
164
|
+
}
|
|
165
|
+
if (msg.type === 'error') {
|
|
166
|
+
return { type: 'activity', subtype: 'error', data: msg.error || msg.message || 'Unknown error' };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const labels = {
|
|
170
|
+
signal_connected: `Connected to ${msg.signal || 'signal'}`,
|
|
171
|
+
matched: `Matched with ${Array.isArray(msg.nodes) ? msg.nodes.length : '?'} nodes`,
|
|
172
|
+
connected: `Session ${(msg.session_id || '').slice(0, 8) || 'started'}`,
|
|
173
|
+
pipeline: `Pipeline ready — ${Array.isArray(msg.nodes) ? msg.nodes.length : '?'} nodes`,
|
|
174
|
+
};
|
|
175
|
+
if (labels[msg.type]) {
|
|
176
|
+
return { type: 'activity', data: labels[msg.type], sessionId: msg.session_id };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return { type: 'activity', data: msg.text || msg.message || msg.type, raw: msg };
|
|
168
180
|
} catch { /* not JSON, fall through */ }
|
|
169
181
|
return { type: 'activity', data: trimmed };
|
|
170
182
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groove-dev",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.54",
|
|
4
4
|
"description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
|
|
5
5
|
"license": "FSL-1.1-Apache-2.0",
|
|
6
6
|
"author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
|
|
@@ -4029,11 +4029,13 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4029
4029
|
}
|
|
4030
4030
|
|
|
4031
4031
|
const signalFlag = supportsSignalFlag(cfg.version) ? '--signal' : '--relay';
|
|
4032
|
+
const model = cfg.model || 'Qwen/Qwen2.5-0.5B';
|
|
4032
4033
|
const args = [
|
|
4033
4034
|
'-m', 'src.node.server',
|
|
4034
4035
|
signalFlag, signal,
|
|
4035
4036
|
'--tls',
|
|
4036
4037
|
'--device', device,
|
|
4038
|
+
'--model', model,
|
|
4037
4039
|
'--max-context', String(maxContext),
|
|
4038
4040
|
];
|
|
4039
4041
|
|
|
@@ -4300,6 +4302,22 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4300
4302
|
return resolve(homedir(), '.groove', 'network');
|
|
4301
4303
|
}
|
|
4302
4304
|
|
|
4305
|
+
function getInstalledNetworkVersion() {
|
|
4306
|
+
const configured = daemon.config?.networkBeta?.version || null;
|
|
4307
|
+
if (configured) return configured;
|
|
4308
|
+
const installPath = networkRoot();
|
|
4309
|
+
if (!existsSync(resolve(installPath, 'setup.sh'))) return null;
|
|
4310
|
+
try {
|
|
4311
|
+
const { execSync } = require('child_process');
|
|
4312
|
+
const v = execSync('git describe --tags --abbrev=0', {
|
|
4313
|
+
cwd: installPath, stdio: ['ignore', 'pipe', 'ignore'], timeout: 5000,
|
|
4314
|
+
}).toString().trim();
|
|
4315
|
+
return parseSemver(v) ? v : null;
|
|
4316
|
+
} catch {
|
|
4317
|
+
return null;
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
|
|
4303
4321
|
// Defensive: only permit fs ops on paths that resolve inside ~/.groove/.
|
|
4304
4322
|
// Uses realpathSync when the path exists to defeat symlink escapes.
|
|
4305
4323
|
function isInsideGrooveHome(target) {
|
|
@@ -4325,7 +4343,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4325
4343
|
res.json({
|
|
4326
4344
|
installed,
|
|
4327
4345
|
path: installed ? installPath : null,
|
|
4328
|
-
version: installed ? (
|
|
4346
|
+
version: installed ? getInstalledNetworkVersion() : null,
|
|
4329
4347
|
});
|
|
4330
4348
|
});
|
|
4331
4349
|
|
|
@@ -4565,7 +4583,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4565
4583
|
}
|
|
4566
4584
|
|
|
4567
4585
|
app.get('/api/network/update/check', networkGate, async (req, res) => {
|
|
4568
|
-
const installed =
|
|
4586
|
+
const installed = getInstalledNetworkVersion();
|
|
4569
4587
|
const force = req.query.force === '1' || req.query.force === 'true';
|
|
4570
4588
|
const latest = await getLatestNetworkTag(force);
|
|
4571
4589
|
if (!latest) {
|
|
@@ -4591,11 +4609,11 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4591
4609
|
if (daemon.networkInstall?.running) {
|
|
4592
4610
|
return res.status(409).json({ error: 'Install/update already in progress' });
|
|
4593
4611
|
}
|
|
4594
|
-
|
|
4612
|
+
const installPath = networkRoot();
|
|
4613
|
+
const hasInstall = daemon.config?.networkBeta?.installed || existsSync(resolve(installPath, 'setup.sh'));
|
|
4614
|
+
if (!hasInstall) {
|
|
4595
4615
|
return res.status(400).json({ error: 'Network package not installed' });
|
|
4596
4616
|
}
|
|
4597
|
-
|
|
4598
|
-
const installPath = networkRoot();
|
|
4599
4617
|
if (!existsSync(installPath) || !isInsideGrooveHome(installPath)) {
|
|
4600
4618
|
return res.status(400).json({ error: 'Install path missing or invalid' });
|
|
4601
4619
|
}
|
|
@@ -4604,7 +4622,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4604
4622
|
if (!latest) {
|
|
4605
4623
|
return res.status(502).json({ error: 'Could not reach github.com to check for updates' });
|
|
4606
4624
|
}
|
|
4607
|
-
const current =
|
|
4625
|
+
const current = getInstalledNetworkVersion();
|
|
4608
4626
|
if (current && compareSemver(latest, current) <= 0) {
|
|
4609
4627
|
return res.status(400).json({ error: 'Already at latest version', installed: current, latest });
|
|
4610
4628
|
}
|
|
@@ -4730,11 +4748,12 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4730
4748
|
// Startup hook — called from index.js once the server is up. Non-blocking;
|
|
4731
4749
|
// updates daemon.networkUpdateAvailable and broadcasts so the GUI can badge.
|
|
4732
4750
|
daemon.checkNetworkUpdate = async function checkNetworkUpdate() {
|
|
4733
|
-
|
|
4751
|
+
const hasInstall = daemon.config?.networkBeta?.installed || existsSync(resolve(networkRoot(), 'setup.sh'));
|
|
4752
|
+
if (!hasInstall) return;
|
|
4734
4753
|
try {
|
|
4735
4754
|
const latest = await getLatestNetworkTag(true);
|
|
4736
4755
|
if (!latest) return;
|
|
4737
|
-
const installed =
|
|
4756
|
+
const installed = getInstalledNetworkVersion();
|
|
4738
4757
|
const updateAvailable = !!installed && compareSemver(latest, installed) > 0;
|
|
4739
4758
|
daemon.networkUpdateAvailable = { installed, latest, updateAvailable };
|
|
4740
4759
|
daemon.broadcast({ type: 'network:update:available', data: daemon.networkUpdateAvailable });
|
|
@@ -152,19 +152,31 @@ export class GrooveNetworkProvider extends Provider {
|
|
|
152
152
|
}
|
|
153
153
|
try {
|
|
154
154
|
const msg = JSON.parse(trimmed);
|
|
155
|
-
if (msg
|
|
156
|
-
return {
|
|
157
|
-
type: msg.type,
|
|
158
|
-
text: msg.text,
|
|
159
|
-
sessionId: msg.session_id,
|
|
160
|
-
tokensGenerated: msg.tokens_generated,
|
|
161
|
-
error: msg.error,
|
|
162
|
-
signal: msg.signal,
|
|
163
|
-
nodesAvailable: msg.nodes_available,
|
|
164
|
-
nodes: msg.nodes,
|
|
165
|
-
raw: msg,
|
|
166
|
-
};
|
|
155
|
+
if (!msg || typeof msg !== 'object' || typeof msg.type !== 'string') {
|
|
156
|
+
return { type: 'activity', data: trimmed };
|
|
167
157
|
}
|
|
158
|
+
|
|
159
|
+
if (msg.type === 'token' && msg.text) {
|
|
160
|
+
return { type: 'activity', subtype: 'text', data: msg.text, tokensGenerated: msg.tokens_generated };
|
|
161
|
+
}
|
|
162
|
+
if (msg.type === 'complete' || msg.type === 'result') {
|
|
163
|
+
return { type: 'result', text: msg.text || '', tokensGenerated: msg.tokens_generated, sessionId: msg.session_id };
|
|
164
|
+
}
|
|
165
|
+
if (msg.type === 'error') {
|
|
166
|
+
return { type: 'activity', subtype: 'error', data: msg.error || msg.message || 'Unknown error' };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const labels = {
|
|
170
|
+
signal_connected: `Connected to ${msg.signal || 'signal'}`,
|
|
171
|
+
matched: `Matched with ${Array.isArray(msg.nodes) ? msg.nodes.length : '?'} nodes`,
|
|
172
|
+
connected: `Session ${(msg.session_id || '').slice(0, 8) || 'started'}`,
|
|
173
|
+
pipeline: `Pipeline ready — ${Array.isArray(msg.nodes) ? msg.nodes.length : '?'} nodes`,
|
|
174
|
+
};
|
|
175
|
+
if (labels[msg.type]) {
|
|
176
|
+
return { type: 'activity', data: labels[msg.type], sessionId: msg.session_id };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return { type: 'activity', data: msg.text || msg.message || msg.type, raw: msg };
|
|
168
180
|
} catch { /* not JSON, fall through */ }
|
|
169
181
|
return { type: 'activity', data: trimmed };
|
|
170
182
|
}
|