groove-dev 0.17.1 → 0.17.2

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.
@@ -235,6 +235,8 @@ export class IntegrationStore {
235
235
  /**
236
236
  * Build MCP config object for a set of integration IDs.
237
237
  * Returns the mcpServers object to merge into .mcp.json.
238
+ * SECURITY: credentials are NOT included in the config file.
239
+ * They are injected at spawn time via process environment only.
238
240
  */
239
241
  buildMcpConfig(integrationIds) {
240
242
  const mcpServers = {};
@@ -244,23 +246,33 @@ export class IntegrationStore {
244
246
  if (!entry) continue;
245
247
  if (!this._isInstalled(id)) continue;
246
248
 
247
- // Build environment with credentials
248
- const env = {};
249
- for (const ek of (entry.envKeys || [])) {
250
- const val = this.getCredential(id, ek.key);
251
- if (val) env[ek.key] = val;
252
- }
253
-
249
+ // No env block credentials stay out of .mcp.json
254
250
  mcpServers[`groove-${id}`] = {
255
251
  command: entry.command || 'npx',
256
252
  args: entry.args || ['-y', entry.npmPackage],
257
- env,
258
253
  };
259
254
  }
260
255
 
261
256
  return mcpServers;
262
257
  }
263
258
 
259
+ /**
260
+ * Get environment variables with decrypted credentials for a set of integration IDs.
261
+ * These are passed to the agent process at spawn time (in-memory only, never written to disk).
262
+ */
263
+ getSpawnEnv(integrationIds) {
264
+ const env = {};
265
+ for (const id of integrationIds) {
266
+ const entry = this.registry.find((s) => s.id === id);
267
+ if (!entry) continue;
268
+ for (const ek of (entry.envKeys || [])) {
269
+ const val = this.getCredential(id, ek.key);
270
+ if (val) env[ek.key] = val;
271
+ }
272
+ }
273
+ return env;
274
+ }
275
+
264
276
  /**
265
277
  * Write/merge MCP config into the project root .mcp.json.
266
278
  * Only adds/updates groove-* entries, preserves user's own MCP configs.
@@ -201,9 +201,12 @@ For normal file edits within your scope, proceed without review.
201
201
  }
202
202
  }
203
203
 
204
- // Write MCP config for agent integrations
204
+ // Write MCP config for agent integrations (command/args only, no secrets)
205
+ // Credentials are injected via process environment below
206
+ let integrationEnv = {};
205
207
  if (config.integrations?.length > 0 && this.daemon.integrations) {
206
208
  this.daemon.integrations.writeMcpJson(config.integrations);
209
+ integrationEnv = this.daemon.integrations.getSpawnEnv(config.integrations);
207
210
  }
208
211
 
209
212
  const { command, args, env } = provider.buildSpawnCommand(spawnConfig);
@@ -232,7 +235,7 @@ For normal file edits within your scope, proceed without review.
232
235
  // Spawn the process
233
236
  const proc = cpSpawn(command, args, {
234
237
  cwd: agent.workingDir || this.daemon.projectDir,
235
- env: { ...process.env, ...env, GROOVE_AGENT_ID: agent.id, GROOVE_AGENT_NAME: agent.name },
238
+ env: { ...process.env, ...env, ...integrationEnv, GROOVE_AGENT_ID: agent.id, GROOVE_AGENT_NAME: agent.name },
236
239
  stdio: ['ignore', 'pipe', 'pipe'],
237
240
  // Don't let agent process prevent daemon from exiting
238
241
  detached: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.17.1",
3
+ "version": "0.17.2",
4
4
  "description": "Open-source agent orchestration layer — the AI company OS. 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.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
@@ -235,6 +235,8 @@ export class IntegrationStore {
235
235
  /**
236
236
  * Build MCP config object for a set of integration IDs.
237
237
  * Returns the mcpServers object to merge into .mcp.json.
238
+ * SECURITY: credentials are NOT included in the config file.
239
+ * They are injected at spawn time via process environment only.
238
240
  */
239
241
  buildMcpConfig(integrationIds) {
240
242
  const mcpServers = {};
@@ -244,23 +246,33 @@ export class IntegrationStore {
244
246
  if (!entry) continue;
245
247
  if (!this._isInstalled(id)) continue;
246
248
 
247
- // Build environment with credentials
248
- const env = {};
249
- for (const ek of (entry.envKeys || [])) {
250
- const val = this.getCredential(id, ek.key);
251
- if (val) env[ek.key] = val;
252
- }
253
-
249
+ // No env block credentials stay out of .mcp.json
254
250
  mcpServers[`groove-${id}`] = {
255
251
  command: entry.command || 'npx',
256
252
  args: entry.args || ['-y', entry.npmPackage],
257
- env,
258
253
  };
259
254
  }
260
255
 
261
256
  return mcpServers;
262
257
  }
263
258
 
259
+ /**
260
+ * Get environment variables with decrypted credentials for a set of integration IDs.
261
+ * These are passed to the agent process at spawn time (in-memory only, never written to disk).
262
+ */
263
+ getSpawnEnv(integrationIds) {
264
+ const env = {};
265
+ for (const id of integrationIds) {
266
+ const entry = this.registry.find((s) => s.id === id);
267
+ if (!entry) continue;
268
+ for (const ek of (entry.envKeys || [])) {
269
+ const val = this.getCredential(id, ek.key);
270
+ if (val) env[ek.key] = val;
271
+ }
272
+ }
273
+ return env;
274
+ }
275
+
264
276
  /**
265
277
  * Write/merge MCP config into the project root .mcp.json.
266
278
  * Only adds/updates groove-* entries, preserves user's own MCP configs.
@@ -201,9 +201,12 @@ For normal file edits within your scope, proceed without review.
201
201
  }
202
202
  }
203
203
 
204
- // Write MCP config for agent integrations
204
+ // Write MCP config for agent integrations (command/args only, no secrets)
205
+ // Credentials are injected via process environment below
206
+ let integrationEnv = {};
205
207
  if (config.integrations?.length > 0 && this.daemon.integrations) {
206
208
  this.daemon.integrations.writeMcpJson(config.integrations);
209
+ integrationEnv = this.daemon.integrations.getSpawnEnv(config.integrations);
207
210
  }
208
211
 
209
212
  const { command, args, env } = provider.buildSpawnCommand(spawnConfig);
@@ -232,7 +235,7 @@ For normal file edits within your scope, proceed without review.
232
235
  // Spawn the process
233
236
  const proc = cpSpawn(command, args, {
234
237
  cwd: agent.workingDir || this.daemon.projectDir,
235
- env: { ...process.env, ...env, GROOVE_AGENT_ID: agent.id, GROOVE_AGENT_NAME: agent.name },
238
+ env: { ...process.env, ...env, ...integrationEnv, GROOVE_AGENT_ID: agent.id, GROOVE_AGENT_NAME: agent.name },
236
239
  stdio: ['ignore', 'pipe', 'pipe'],
237
240
  // Don't let agent process prevent daemon from exiting
238
241
  detached: false,