groove-dev 0.27.50 → 0.27.52
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 +136 -19
- package/node_modules/@groove-dev/daemon/src/firstrun.js +1 -1
- package/node_modules/@groove-dev/daemon/src/process.js +2 -2
- package/node_modules/@groove-dev/daemon/src/providers/groove-network.js +22 -5
- package/node_modules/@groove-dev/gui/dist/assets/{index-Dd4u8X70.js → index-De-OWmBX.js} +1 -1
- 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/stores/groove.js +10 -10
- 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 +136 -19
- package/packages/daemon/src/firstrun.js +1 -1
- package/packages/daemon/src/process.js +2 -2
- package/packages/daemon/src/providers/groove-network.js +22 -5
- package/packages/gui/dist/assets/{index-Dd4u8X70.js → index-De-OWmBX.js} +1 -1
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/stores/groove.js +10 -10
|
@@ -3866,7 +3866,14 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
3866
3866
|
// so revoked or expired codes lock the feature automatically. Non-blocking.
|
|
3867
3867
|
daemon.revalidateBetaCode = async function revalidateBetaCode() {
|
|
3868
3868
|
const cfg = daemon.config?.networkBeta;
|
|
3869
|
-
if (!cfg?.unlocked
|
|
3869
|
+
if (!cfg?.unlocked) return;
|
|
3870
|
+
if (!cfg?.code) {
|
|
3871
|
+
daemon.config.networkBeta = { ...cfg, unlocked: false, expiresAt: null, features: [] };
|
|
3872
|
+
await persistConfig();
|
|
3873
|
+
daemon.audit.log('beta.revoked', { reason: 'missing code' });
|
|
3874
|
+
daemon.broadcast({ type: 'config:updated' });
|
|
3875
|
+
return;
|
|
3876
|
+
}
|
|
3870
3877
|
const remote = await validateCodeWithServer(cfg.code);
|
|
3871
3878
|
// If we couldn't reach the server, keep the current unlocked state —
|
|
3872
3879
|
// network failures must not lock out beta users.
|
|
@@ -3999,7 +4006,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
3999
4006
|
}
|
|
4000
4007
|
|
|
4001
4008
|
const cfg = daemon.config.networkBeta || {};
|
|
4002
|
-
const signal = cfg.signalUrl
|
|
4009
|
+
const signal = stripScheme(cfg.signalUrl);
|
|
4003
4010
|
if (!isAllowedSignalHost(signal)) {
|
|
4004
4011
|
return res.status(400).json({ error: 'Invalid signal host' });
|
|
4005
4012
|
}
|
|
@@ -4017,18 +4024,22 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4017
4024
|
if (!existsSync(deployPath)) {
|
|
4018
4025
|
return res.status(400).json({ error: `Deploy path not found: ${deployPath}` });
|
|
4019
4026
|
}
|
|
4027
|
+
if (!isInsideGrooveHome(deployPath) && !deployPath.startsWith(resolve(process.env.HOME || '', 'Desktop'))) {
|
|
4028
|
+
return res.status(400).json({ error: 'Deploy path outside allowed directories' });
|
|
4029
|
+
}
|
|
4020
4030
|
|
|
4021
4031
|
const signalFlag = supportsSignalFlag(cfg.version) ? '--signal' : '--relay';
|
|
4022
4032
|
const args = [
|
|
4023
4033
|
'-m', 'src.node.server',
|
|
4024
4034
|
signalFlag, signal,
|
|
4035
|
+
'--tls',
|
|
4025
4036
|
'--device', device,
|
|
4026
4037
|
'--max-context', String(maxContext),
|
|
4027
4038
|
];
|
|
4028
4039
|
|
|
4029
4040
|
let proc;
|
|
4030
4041
|
try {
|
|
4031
|
-
proc = spawn(join(deployPath, 'venv', 'bin', 'python3
|
|
4042
|
+
proc = spawn(join(deployPath, 'venv', 'bin', 'python3'), args, {
|
|
4032
4043
|
cwd: deployPath,
|
|
4033
4044
|
env: { ...process.env, PYTHONUNBUFFERED: '1' },
|
|
4034
4045
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -4063,7 +4074,33 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4063
4074
|
stderrBuf = stderrBuf.slice(idx + 1);
|
|
4064
4075
|
if (!line) continue;
|
|
4065
4076
|
if (line[0] !== '{') {
|
|
4077
|
+
// Python node emits plain-text logs like "Node identity: abc123",
|
|
4078
|
+
// "shard loaded: layers 0-12", "registered with signal". Parse those
|
|
4079
|
+
// here so the GUI reflects reality even without structured logging.
|
|
4080
|
+
let changed = false;
|
|
4081
|
+
const idMatch = line.match(/Node identity:\s*([A-Za-z0-9_\-:.]+)/i);
|
|
4082
|
+
if (idMatch && idMatch[1] !== daemon.networkNode.nodeId) {
|
|
4083
|
+
daemon.networkNode.nodeId = idMatch[1]; changed = true;
|
|
4084
|
+
}
|
|
4085
|
+
const layerMatch = line.match(/layers?\s*(\d+)\s*[-–to]+\s*(\d+)/i);
|
|
4086
|
+
if (layerMatch) {
|
|
4087
|
+
const start = parseInt(layerMatch[1], 10);
|
|
4088
|
+
const end = parseInt(layerMatch[2], 10);
|
|
4089
|
+
if (Number.isFinite(start) && Number.isFinite(end)) {
|
|
4090
|
+
daemon.networkNode.layers = [start, end]; changed = true;
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
const modelMatch = line.match(/model[:\s]+([A-Za-z0-9_\-./]+\/[A-Za-z0-9_\-.]+)/i);
|
|
4094
|
+
if (modelMatch && modelMatch[1] !== daemon.networkNode.model) {
|
|
4095
|
+
daemon.networkNode.model = modelMatch[1]; changed = true;
|
|
4096
|
+
}
|
|
4097
|
+
if (/\bregistered\b/i.test(line) || /\bconnected\b/i.test(line)) {
|
|
4098
|
+
if (daemon.networkNode.status !== 'connected') {
|
|
4099
|
+
daemon.networkNode.status = 'connected'; changed = true;
|
|
4100
|
+
}
|
|
4101
|
+
}
|
|
4066
4102
|
pushNodeEvent('log', { line });
|
|
4103
|
+
if (changed) broadcastNodeStatus();
|
|
4067
4104
|
continue;
|
|
4068
4105
|
}
|
|
4069
4106
|
let entry;
|
|
@@ -4138,10 +4175,18 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4138
4175
|
});
|
|
4139
4176
|
|
|
4140
4177
|
function isAllowedSignalHost(host) {
|
|
4141
|
-
const h = (host || '').replace(/^https
|
|
4178
|
+
const h = (host || '').replace(/^(wss?|https?):\/\//i, '').replace(/\/.*$/, '').toLowerCase();
|
|
4142
4179
|
return h === 'signal.groovedev.ai' || h.endsWith('.groovedev.ai');
|
|
4143
4180
|
}
|
|
4144
4181
|
|
|
4182
|
+
// The Python node/client code prepends the scheme itself from `--tls`.
|
|
4183
|
+
// Daemon must pass a BARE host to --relay/--signal; otherwise the Python
|
|
4184
|
+
// side ends up with a double-scheme URI like wss://wss://host.
|
|
4185
|
+
function stripScheme(url) {
|
|
4186
|
+
if (!url) return 'signal.groovedev.ai';
|
|
4187
|
+
return url.replace(/^wss?:\/\//i, '').replace(/\/.*$/, '');
|
|
4188
|
+
}
|
|
4189
|
+
|
|
4145
4190
|
app.get('/api/network/status', networkGate, async (req, res) => {
|
|
4146
4191
|
const cfg = daemon.config.networkBeta || {};
|
|
4147
4192
|
const signalHost = cfg.signalUrl || 'signal.groovedev.ai';
|
|
@@ -4150,9 +4195,8 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4150
4195
|
return res.status(400).json({ error: 'Invalid signal host' });
|
|
4151
4196
|
}
|
|
4152
4197
|
|
|
4153
|
-
const
|
|
4154
|
-
|
|
4155
|
-
: `https://${signalHost}/status`;
|
|
4198
|
+
const bareHost = signalHost.replace(/^(wss?|https?):\/\//i, '').replace(/\/.*$/, '');
|
|
4199
|
+
const statusUrl = `https://${bareHost}/status`;
|
|
4156
4200
|
|
|
4157
4201
|
try {
|
|
4158
4202
|
const controller = new AbortController();
|
|
@@ -4161,7 +4205,70 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4161
4205
|
clearTimeout(timer);
|
|
4162
4206
|
if (r.ok) {
|
|
4163
4207
|
const data = await r.json();
|
|
4164
|
-
|
|
4208
|
+
// Signal service returns snake_case; GUI expects camelCase.
|
|
4209
|
+
const models = Array.isArray(data.models) ? data.models.map((m) => {
|
|
4210
|
+
if (!m || typeof m !== 'object') return m;
|
|
4211
|
+
const { covered_layers, total_layers, ...rest } = m;
|
|
4212
|
+
return {
|
|
4213
|
+
...rest,
|
|
4214
|
+
...(covered_layers !== undefined ? { coveredLayers: covered_layers } : {}),
|
|
4215
|
+
...(total_layers !== undefined ? { totalLayers: total_layers } : {}),
|
|
4216
|
+
};
|
|
4217
|
+
}) : [];
|
|
4218
|
+
const primaryModel = Array.isArray(data.models) && data.models[0] ? data.models[0] : {};
|
|
4219
|
+
|
|
4220
|
+
// Enrich local node state from signal's authoritative topology.
|
|
4221
|
+
// Signal truncates IDs (e.g. "0xf608fd..."), so match by prefix.
|
|
4222
|
+
if (daemon.networkNode?.active && daemon.networkNode.nodeId) {
|
|
4223
|
+
const selfId = daemon.networkNode.nodeId;
|
|
4224
|
+
const signalNodes = Array.isArray(data.nodes) ? data.nodes : [];
|
|
4225
|
+
const self = signalNodes.find((n) => {
|
|
4226
|
+
const nid = n.node_id || n.nodeId || '';
|
|
4227
|
+
const prefix = nid.replace(/\.{2,}$/, '');
|
|
4228
|
+
return selfId === nid || (prefix.length >= 6 && selfId.startsWith(prefix));
|
|
4229
|
+
});
|
|
4230
|
+
let changed = false;
|
|
4231
|
+
if (self) {
|
|
4232
|
+
if (Array.isArray(self.layers) && self.layers.length === 2) {
|
|
4233
|
+
daemon.networkNode.layers = self.layers;
|
|
4234
|
+
changed = true;
|
|
4235
|
+
}
|
|
4236
|
+
if (self.device) {
|
|
4237
|
+
daemon.networkNode.hardware = {
|
|
4238
|
+
device: self.device,
|
|
4239
|
+
memory: daemon.networkNode.hardware?.memory || null,
|
|
4240
|
+
gpu: daemon.networkNode.hardware?.gpu || null,
|
|
4241
|
+
};
|
|
4242
|
+
changed = true;
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
const availModel = Array.isArray(data.models)
|
|
4246
|
+
? data.models.find((m) => m && m.available !== false)
|
|
4247
|
+
: null;
|
|
4248
|
+
if (availModel && !daemon.networkNode.model) {
|
|
4249
|
+
daemon.networkNode.model = availModel.name || null;
|
|
4250
|
+
changed = true;
|
|
4251
|
+
}
|
|
4252
|
+
if (changed) broadcastNodeStatus();
|
|
4253
|
+
}
|
|
4254
|
+
|
|
4255
|
+
const capStr = (s, max = 200) => (typeof s === 'string' ? s.slice(0, max) : s);
|
|
4256
|
+
const safeNodes = (Array.isArray(data.nodes) ? data.nodes : []).map((n) => ({
|
|
4257
|
+
node_id: capStr(n.node_id || n.nodeId),
|
|
4258
|
+
device: capStr(n.device),
|
|
4259
|
+
layers: Array.isArray(n.layers) ? n.layers.slice(0, 2) : n.layers,
|
|
4260
|
+
status: capStr(n.status, 50),
|
|
4261
|
+
active_sessions: n.active_sessions ?? 0,
|
|
4262
|
+
}));
|
|
4263
|
+
|
|
4264
|
+
return res.json({
|
|
4265
|
+
nodes: safeNodes,
|
|
4266
|
+
models,
|
|
4267
|
+
coverage: data.covered_layers ?? primaryModel.covered_layers ?? data.coverage ?? 0,
|
|
4268
|
+
totalLayers: data.total_layers ?? primaryModel.total_layers ?? data.totalLayers ?? 24,
|
|
4269
|
+
activeSessions: data.active_sessions ?? data.activeSessions ?? 0,
|
|
4270
|
+
totalNodes: data.total_nodes ?? data.totalNodes ?? (Array.isArray(data.nodes) ? data.nodes.length : 0),
|
|
4271
|
+
});
|
|
4165
4272
|
}
|
|
4166
4273
|
} catch { /* fall through to local snapshot */ }
|
|
4167
4274
|
|
|
@@ -4180,13 +4287,14 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4180
4287
|
coverage,
|
|
4181
4288
|
totalLayers: 24,
|
|
4182
4289
|
activeSessions: node.sessions || 0,
|
|
4290
|
+
totalNodes: selfNode.length,
|
|
4183
4291
|
});
|
|
4184
4292
|
});
|
|
4185
4293
|
|
|
4186
4294
|
// --- Network package install/uninstall ---
|
|
4187
4295
|
|
|
4188
4296
|
const NETWORK_REPO_URL = 'https://github.com/grooveai-dev/groove-network.git';
|
|
4189
|
-
const NETWORK_VERSION = 'v0.
|
|
4297
|
+
const NETWORK_VERSION = 'v0.2.0';
|
|
4190
4298
|
|
|
4191
4299
|
function networkRoot() {
|
|
4192
4300
|
return resolve(homedir(), '.groove', 'network');
|
|
@@ -4260,18 +4368,27 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4260
4368
|
};
|
|
4261
4369
|
|
|
4262
4370
|
try {
|
|
4263
|
-
// Build clone URL with optional PAT
|
|
4264
4371
|
const pat = daemon.credentials?.getKey?.('github-pat') || null;
|
|
4265
|
-
const cloneUrl = pat
|
|
4266
|
-
? NETWORK_REPO_URL.replace('https://', `https://${pat}@`)
|
|
4267
|
-
: NETWORK_REPO_URL;
|
|
4268
4372
|
|
|
4269
|
-
|
|
4373
|
+
let installVersion;
|
|
4374
|
+
try {
|
|
4375
|
+
installVersion = (await getLatestNetworkTag()) || NETWORK_VERSION;
|
|
4376
|
+
} catch {
|
|
4377
|
+
installVersion = NETWORK_VERSION;
|
|
4378
|
+
}
|
|
4379
|
+
|
|
4380
|
+
broadcastInstallProgress('cloning', `Cloning network package ${installVersion}...`, 0);
|
|
4270
4381
|
|
|
4271
|
-
const cloneArgs = ['clone', '--branch',
|
|
4382
|
+
const cloneArgs = ['clone', '--branch', installVersion, '--depth', '1', NETWORK_REPO_URL, installPath];
|
|
4383
|
+
const cloneEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0' };
|
|
4384
|
+
if (pat) {
|
|
4385
|
+
cloneEnv.GIT_CONFIG_COUNT = '1';
|
|
4386
|
+
cloneEnv.GIT_CONFIG_KEY_0 = 'http.extraHeader';
|
|
4387
|
+
cloneEnv.GIT_CONFIG_VALUE_0 = `Authorization: token ${pat}`;
|
|
4388
|
+
}
|
|
4272
4389
|
const clone = spawn('git', cloneArgs, {
|
|
4273
4390
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
4274
|
-
env:
|
|
4391
|
+
env: cloneEnv,
|
|
4275
4392
|
});
|
|
4276
4393
|
|
|
4277
4394
|
const stripCredentials = (s) => s.replace(/https:\/\/[^@]+@/g, 'https://***@');
|
|
@@ -4344,12 +4461,12 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
4344
4461
|
...(daemon.config.networkBeta || {}),
|
|
4345
4462
|
installed: true,
|
|
4346
4463
|
deployPath: installPath,
|
|
4347
|
-
version:
|
|
4464
|
+
version: installVersion,
|
|
4348
4465
|
};
|
|
4349
4466
|
await persistConfig();
|
|
4350
4467
|
daemon.broadcast({ type: 'config:updated' });
|
|
4351
|
-
broadcastInstallProgress('done',
|
|
4352
|
-
daemon.audit.log('network.install', { path: installPath, version:
|
|
4468
|
+
broadcastInstallProgress('done', `Network package ${installVersion} installed`, 100);
|
|
4469
|
+
daemon.audit.log('network.install', { path: installPath, version: installVersion });
|
|
4353
4470
|
daemon.networkInstall = { running: false };
|
|
4354
4471
|
} catch (err) {
|
|
4355
4472
|
fail(err?.message || 'Install failed');
|
|
@@ -155,5 +155,5 @@ export function loadConfig(grooveDir) {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
export function saveConfig(grooveDir, config) {
|
|
158
|
-
writeFileSync(resolve(grooveDir, 'config.json'), JSON.stringify(config, null, 2));
|
|
158
|
+
writeFileSync(resolve(grooveDir, 'config.json'), JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
159
159
|
}
|
|
@@ -740,7 +740,7 @@ For normal file edits within your scope, proceed without review.
|
|
|
740
740
|
}
|
|
741
741
|
|
|
742
742
|
const spawnCmd = provider.buildSpawnCommand(spawnConfig);
|
|
743
|
-
const { command, args, env, stdin: stdinData } = spawnCmd;
|
|
743
|
+
const { command, args, env, stdin: stdinData, cwd: providerCwd } = spawnCmd;
|
|
744
744
|
|
|
745
745
|
// Log the spawn command (mask anything that looks like an API key)
|
|
746
746
|
const maskArg = (a) => /^(sk-|AIza|key-|token-)/.test(a) ? '***' : a;
|
|
@@ -765,7 +765,7 @@ For normal file edits within your scope, proceed without review.
|
|
|
765
765
|
|
|
766
766
|
// Spawn the process (use pipe for stdin if provider needs to send prompt via stdin)
|
|
767
767
|
const proc = cpSpawn(command, args, {
|
|
768
|
-
cwd: agent.workingDir || this.daemon.projectDir,
|
|
768
|
+
cwd: providerCwd || agent.workingDir || this.daemon.projectDir,
|
|
769
769
|
env: { ...process.env, ...env, ...integrationEnv, GROOVE_AGENT_ID: agent.id, GROOVE_AGENT_NAME: agent.name, GROOVE_DAEMON_HOST: this.daemon.host || '127.0.0.1', GROOVE_DAEMON_PORT: String(this.daemon.port || 31415) },
|
|
770
770
|
stdio: [stdinData ? 'pipe' : 'ignore', 'pipe', 'pipe'],
|
|
771
771
|
detached: false,
|
|
@@ -58,10 +58,23 @@ function signalFlagName() {
|
|
|
58
58
|
return supportsSignalFlag(cfg.version) ? '--signal' : '--relay';
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// The Python client prepends the scheme itself — daemon passes a bare host
|
|
62
|
+
// and adds `--tls` to request wss://. Strip any ws:// or wss:// a user may
|
|
63
|
+
// have left in the stored signalUrl (e.g. from an older daemon default).
|
|
64
|
+
function stripScheme(url) {
|
|
65
|
+
if (!url) return 'signal.groovedev.ai';
|
|
66
|
+
return url.replace(/^wss?:\/\//i, '').replace(/\/.*$/, '');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isAllowedSignalHost(host) {
|
|
70
|
+
const h = (host || '').replace(/^(wss?|https?):\/\//i, '').replace(/\/.*$/, '').toLowerCase();
|
|
71
|
+
return h === 'signal.groovedev.ai' || h.endsWith('.groovedev.ai');
|
|
72
|
+
}
|
|
73
|
+
|
|
61
74
|
export class GrooveNetworkProvider extends Provider {
|
|
62
75
|
static name = 'groove-network';
|
|
63
76
|
static displayName = 'Groove Network';
|
|
64
|
-
static command = 'python3
|
|
77
|
+
static command = 'python3';
|
|
65
78
|
static authType = 'none';
|
|
66
79
|
|
|
67
80
|
static models = [
|
|
@@ -79,7 +92,8 @@ export class GrooveNetworkProvider extends Provider {
|
|
|
79
92
|
|
|
80
93
|
buildSpawnCommand(agent) {
|
|
81
94
|
const cfg = getConfig() || {};
|
|
82
|
-
const signal = cfg.signalUrl
|
|
95
|
+
const signal = stripScheme(cfg.signalUrl);
|
|
96
|
+
if (!isAllowedSignalHost(signal)) throw new Error('Invalid signal host');
|
|
83
97
|
const model = agent.model || GrooveNetworkProvider.models[0].id;
|
|
84
98
|
const maxTokens = agent.maxTokens || 500;
|
|
85
99
|
const prompt = agent.prompt || '';
|
|
@@ -89,6 +103,7 @@ export class GrooveNetworkProvider extends Provider {
|
|
|
89
103
|
const args = [
|
|
90
104
|
'-m', 'src.consumer.client',
|
|
91
105
|
signalFlagName(), signal,
|
|
106
|
+
'--tls',
|
|
92
107
|
'--model', model,
|
|
93
108
|
'--prompt', prompt,
|
|
94
109
|
'--max-tokens', String(maxTokens),
|
|
@@ -96,7 +111,7 @@ export class GrooveNetworkProvider extends Provider {
|
|
|
96
111
|
];
|
|
97
112
|
|
|
98
113
|
return {
|
|
99
|
-
command: join(deployPath, 'venv', 'bin', 'python3
|
|
114
|
+
command: join(deployPath, 'venv', 'bin', 'python3'),
|
|
100
115
|
args,
|
|
101
116
|
env: { PYTHONUNBUFFERED: '1' },
|
|
102
117
|
cwd: deployPath,
|
|
@@ -105,14 +120,16 @@ export class GrooveNetworkProvider extends Provider {
|
|
|
105
120
|
|
|
106
121
|
buildHeadlessCommand(prompt, model) {
|
|
107
122
|
const cfg = getConfig() || {};
|
|
108
|
-
const signal = cfg.signalUrl
|
|
123
|
+
const signal = stripScheme(cfg.signalUrl);
|
|
124
|
+
if (!isAllowedSignalHost(signal)) throw new Error('Invalid signal host');
|
|
109
125
|
const m = model || GrooveNetworkProvider.models[0].id;
|
|
110
126
|
const deployPath = expandHome(cfg.deployPath) || resolve(homedir(), 'Desktop/groove-deploy');
|
|
111
127
|
return {
|
|
112
|
-
command: join(deployPath, 'venv', 'bin', 'python3
|
|
128
|
+
command: join(deployPath, 'venv', 'bin', 'python3'),
|
|
113
129
|
args: [
|
|
114
130
|
'-m', 'src.consumer.client',
|
|
115
131
|
signalFlagName(), signal,
|
|
132
|
+
'--tls',
|
|
116
133
|
'--model', m,
|
|
117
134
|
'--prompt', prompt,
|
|
118
135
|
'--max-tokens', '500',
|