groove-dev 0.24.16 → 0.25.1

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.
@@ -1563,8 +1563,15 @@ Keep responses concise. Help them think, don't lecture them about the system the
1563
1563
  return res.json({ exists: false, agents: [] });
1564
1564
  }
1565
1565
  try {
1566
- const agents = JSON.parse(readFileSync(teamPath, 'utf8'));
1567
- res.json({ exists: true, agents: Array.isArray(agents) ? agents : [] });
1566
+ const raw = JSON.parse(readFileSync(teamPath, 'utf8'));
1567
+ // Support both old format (bare array) and new format ({ projectDir, agents })
1568
+ if (Array.isArray(raw)) {
1569
+ res.json({ exists: true, agents: raw });
1570
+ } else if (raw && Array.isArray(raw.agents)) {
1571
+ res.json({ exists: true, agents: raw.agents, projectDir: raw.projectDir || null });
1572
+ } else {
1573
+ res.json({ exists: false, agents: [] });
1574
+ }
1568
1575
  } catch {
1569
1576
  res.json({ exists: false, agents: [] });
1570
1577
  }
@@ -1576,28 +1583,51 @@ Keep responses concise. Help them think, don't lecture them about the system the
1576
1583
  return res.status(404).json({ error: 'No recommended team found. Run a planner first.' });
1577
1584
  }
1578
1585
  try {
1579
- const agents = JSON.parse(readFileSync(teamPath, 'utf8'));
1580
- if (!Array.isArray(agents) || agents.length === 0) {
1586
+ const raw = JSON.parse(readFileSync(teamPath, 'utf8'));
1587
+
1588
+ // Support both old format (bare array) and new format ({ projectDir, agents })
1589
+ let agentConfigs;
1590
+ let projectDir = null;
1591
+ if (Array.isArray(raw)) {
1592
+ agentConfigs = raw;
1593
+ } else if (raw && Array.isArray(raw.agents)) {
1594
+ agentConfigs = raw.agents;
1595
+ projectDir = raw.projectDir || null;
1596
+ } else {
1597
+ return res.status(400).json({ error: 'Invalid recommended team format' });
1598
+ }
1599
+
1600
+ if (agentConfigs.length === 0) {
1581
1601
  return res.status(400).json({ error: 'Recommended team is empty' });
1582
1602
  }
1583
1603
 
1584
- const defaultDir = daemon.config?.defaultWorkingDir || undefined;
1604
+ const baseDir = daemon.config?.defaultWorkingDir || daemon.projectDir;
1585
1605
  const defaultTeamId = daemon.teams.getDefault()?.id || null;
1586
1606
 
1607
+ // If planner specified a project directory, create it and use it as workingDir
1608
+ let projectWorkingDir = baseDir;
1609
+ if (projectDir) {
1610
+ // Sanitize: kebab-case, no path traversal
1611
+ const safeName = String(projectDir).replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 64);
1612
+ projectWorkingDir = resolve(baseDir, safeName);
1613
+ mkdirSync(projectWorkingDir, { recursive: true });
1614
+ console.log(`[Groove] Project directory: ${projectWorkingDir}`);
1615
+ }
1616
+
1587
1617
  // Separate phase 1 (builders) and phase 2 (QC/finisher)
1588
- const phase1 = agents.filter((a) => !a.phase || a.phase === 1);
1589
- let phase2 = agents.filter((a) => a.phase === 2);
1618
+ const phase1 = agentConfigs.filter((a) => !a.phase || a.phase === 1);
1619
+ let phase2 = agentConfigs.filter((a) => a.phase === 2);
1590
1620
 
1591
1621
  // Safety net: if planner forgot the QC agent, auto-add one
1592
1622
  if (phase2.length === 0 && phase1.length >= 2) {
1593
1623
  phase2 = [{
1594
1624
  name: 'qc-agent',
1595
1625
  role: 'fullstack', phase: 2, scope: [],
1596
- prompt: 'QC Senior Dev: All builder agents have completed. Audit their changes for correctness, fix any issues, run tests, build the project, commit all changes, and launch the dev server. Output the localhost URL where the app can be accessed.',
1626
+ prompt: 'QC Senior Dev: All builder agents have completed. Audit their changes for correctness, fix any issues, run tests, build the project, commit all changes, and launch the dev server. Output the localhost URL where the app can be accessed. IMPORTANT: Do NOT delete files from other projects or directories outside this project.',
1597
1627
  }];
1598
1628
  }
1599
1629
 
1600
- // Spawn phase 1 agents immediately
1630
+ // Spawn phase 1 agents immediately — all scoped to projectWorkingDir
1601
1631
  const spawned = [];
1602
1632
  const failed = [];
1603
1633
  const phase1Ids = [];
@@ -1610,7 +1640,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
1610
1640
  provider: config.provider || 'claude-code',
1611
1641
  model: config.model || 'auto',
1612
1642
  permission: config.permission || 'auto',
1613
- workingDir: config.workingDir || defaultDir,
1643
+ workingDir: config.workingDir || projectWorkingDir,
1614
1644
  name: config.name || undefined,
1615
1645
  });
1616
1646
  validated.teamId = defaultTeamId;
@@ -1623,7 +1653,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
1623
1653
  }
1624
1654
  }
1625
1655
 
1626
- // If there are phase 2 agents, register them for auto-spawn on phase 1 completion
1656
+ // Phase 2 agents also scoped to projectWorkingDir
1627
1657
  if (phase2.length > 0 && phase1Ids.length > 0) {
1628
1658
  daemon._pendingPhase2 = daemon._pendingPhase2 || [];
1629
1659
  daemon._pendingPhase2.push({
@@ -1632,7 +1662,7 @@ Keep responses concise. Help them think, don't lecture them about the system the
1632
1662
  role: c.role, scope: c.scope || [], prompt: c.prompt || '',
1633
1663
  provider: c.provider || 'claude-code', model: c.model || 'auto',
1634
1664
  permission: c.permission || 'auto',
1635
- workingDir: c.workingDir || defaultDir,
1665
+ workingDir: c.workingDir || projectWorkingDir,
1636
1666
  name: c.name || undefined,
1637
1667
  teamId: defaultTeamId,
1638
1668
  })),
@@ -1641,9 +1671,9 @@ Keep responses concise. Help them think, don't lecture them about the system the
1641
1671
 
1642
1672
  daemon.audit.log('team.launch', {
1643
1673
  phase1: spawned.length, phase2Pending: phase2.length, failed: failed.length,
1644
- agents: spawned.map((a) => a.role),
1674
+ agents: spawned.map((a) => a.role), projectDir: projectDir || null,
1645
1675
  });
1646
- res.json({ launched: spawned.length, phase2Pending: phase2.length, agents: spawned, failed });
1676
+ res.json({ launched: spawned.length, phase2Pending: phase2.length, agents: spawned, failed, projectDir: projectDir || null });
1647
1677
  } catch (err) {
1648
1678
  res.status(500).json({ error: err.message });
1649
1679
  }
@@ -127,6 +127,16 @@ export class Introducer {
127
127
  lines.push(`4. Clear your entry from \`.groove/coordination.md\` when done`);
128
128
  }
129
129
 
130
+ // File safety — prevent agents from deleting files they didn't create
131
+ lines.push('');
132
+ lines.push(`## File Safety`);
133
+ lines.push('');
134
+ lines.push(`CRITICAL: NEVER delete files you did not create in this session. Do NOT remove files from other projects, previous work, or unrelated directories.`);
135
+ if (newAgent.workingDir) {
136
+ lines.push(`Your working directory is \`${newAgent.workingDir}\`. Stay inside it. Do NOT modify or delete files outside this directory.`);
137
+ }
138
+ lines.push(`If you see files that seem unrelated to your task, leave them alone — they belong to another project or agent.`);
139
+
130
140
  // Memory containment — prevent agents from reading/writing auto-memory
131
141
  // which can contain stale context from unrelated sessions in the same dir
132
142
  lines.push('');
@@ -50,6 +50,22 @@ Do NOT write code unless explicitly asked. Use your MCP tools to interact with e
50
50
  - Presenting findings in clear, actionable format
51
51
  Do NOT write code unless explicitly asked. Use your MCP tools (database queries, spreadsheets) to analyze data.
52
52
 
53
+ `,
54
+ creative: `You are a Creative Writing agent. You produce professional written content — copy, articles, scripts, proposals, briefs, and documentation. Focus on:
55
+ - Writing clear, compelling, well-structured content
56
+ - Adapting tone and style to the audience (formal, conversational, technical, marketing)
57
+ - Editing and polishing drafts for grammar, flow, and impact
58
+ - Researching topics to produce accurate, substantive writing
59
+ You CAN use code tools to create and edit text files, markdown documents, and structured content. For best results, apply a writing skill from the Marketplace that matches your task.
60
+
61
+ `,
62
+ slides: `You are a Slide Deck agent. You build presentation decks as HTML slides (Reveal.js) with optional PPTX export. Focus on:
63
+ - Creating clean, professional slide layouts with strong visual hierarchy
64
+ - Structuring content into clear sections with concise bullet points
65
+ - Building responsive HTML slides that look polished in the browser
66
+ - Generating a slides.json data file alongside HTML for PPTX conversion
67
+ For best results, apply a slide deck skill from the Marketplace. The skill provides templates, styling, and export automation.
68
+
53
69
  `,
54
70
  home: `You are a Smart Home automation agent. You have MCP integrations for Home Assistant. Focus on:
55
71
  - Monitoring and controlling smart home devices
@@ -74,15 +90,33 @@ After completing your plan, you MUST do two things:
74
90
  1. Write your team recommendation as a clear summary in your output so the user can review it.
75
91
 
76
92
  2. Save a machine-readable team config to .groove/recommended-team.json using this EXACT format:
77
- [
78
- { "role": "frontend", "phase": 1, "scope": ["src/components/**", "src/views/**"], "prompt": "Build the frontend: [specific tasks]" },
79
- { "role": "backend", "phase": 1, "scope": ["src/api/**", "src/server/**"], "prompt": "Build the backend: [specific tasks]" },
80
- { "role": "fullstack", "phase": 2, "scope": [], "prompt": "QC Senior Dev: Audit all changes from phase 1 agents. Verify correctness, fix issues, run tests, build the project, commit, and launch. Output the localhost URL." }
81
- ]
93
+
94
+ For NEW projects (building something from scratch):
95
+ {
96
+ "projectDir": "my-project-name",
97
+ "agents": [
98
+ { "role": "frontend", "phase": 1, "scope": ["src/components/**", "src/views/**"], "prompt": "Build the frontend: [specific tasks]" },
99
+ { "role": "backend", "phase": 1, "scope": ["src/api/**", "src/server/**"], "prompt": "Build the backend: [specific tasks]" },
100
+ { "role": "fullstack", "phase": 2, "scope": [], "prompt": "QC Senior Dev: Audit all changes from phase 1 agents. Verify correctness, fix issues, run tests, build the project, commit, and launch. Output the localhost URL." }
101
+ ]
102
+ }
103
+
104
+ For EXISTING codebases (modifying/extending an existing project):
105
+ {
106
+ "agents": [
107
+ { "role": "frontend", "phase": 1, "scope": ["src/components/**"], "prompt": "Update the frontend: [specific tasks]" },
108
+ { "role": "fullstack", "phase": 2, "scope": [], "prompt": "QC Senior Dev: Audit all changes, fix issues, run tests, build, commit, and launch." }
109
+ ]
110
+ }
111
+
112
+ PROJECT DIRECTORY RULES:
113
+ - For NEW projects: ALWAYS include "projectDir" with a short, clean directory name (kebab-case, e.g. "cat-website", "landing-page", "api-service"). All agents will be spawned inside this directory so each project stays isolated.
114
+ - For EXISTING codebases: Do NOT include "projectDir". Agents work in the current repo root. You can tell an existing codebase by the presence of package.json, .git, or established source directories.
115
+ - NEVER mix projects. Each new project gets its own directory.
82
116
 
83
117
  MANDATORY RULES — NEVER SKIP THESE:
84
118
 
85
- 1. The LAST entry in the array MUST be: { "role": "fullstack", "phase": 2, ... }
119
+ 1. The LAST entry in the agents array MUST be: { "role": "fullstack", "phase": 2, ... }
86
120
  This is the QC Senior Dev. It auto-spawns after all other agents finish.
87
121
  Its prompt: audit changes, fix issues, run tests, build, commit, launch.
88
122
  NEVER omit this agent. Every team needs a QC.
@@ -93,7 +127,7 @@ MANDATORY RULES — NEVER SKIP THESE:
93
127
 
94
128
  4. Set appropriate scopes. Write detailed prompts so each agent knows exactly what to build.
95
129
 
96
- 5. If the project is a monorepo, set "workingDir" for agents that need specific subdirectories.
130
+ 5. NEVER instruct any agent to delete files from other projects or clean up unrelated code. Each agent must ONLY create and modify files relevant to its assigned tasks.
97
131
 
98
132
  IMPORTANT: Do not use markdown formatting like ** or ### in your output. Write in plain text with clean formatting. Use line breaks, dashes, and indentation for structure.
99
133