groove-dev 0.27.174 → 0.27.179

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.
Files changed (68) hide show
  1. package/AUTONOMOUS_AGENT_FRAMEWORK.md +654 -0
  2. package/innerchat/Screenshot_2026-06-09_at_12.09.42_PM.png +0 -0
  3. package/innerchat/Screenshot_2026-06-09_at_2.19.42_PM.png +0 -0
  4. package/node_modules/@groove-dev/cli/package.json +1 -1
  5. package/node_modules/@groove-dev/daemon/package.json +1 -1
  6. package/node_modules/@groove-dev/daemon/src/api.js +3 -1
  7. package/node_modules/@groove-dev/daemon/src/autostate.js +198 -0
  8. package/node_modules/@groove-dev/daemon/src/index.js +6 -0
  9. package/node_modules/@groove-dev/daemon/src/orchestrator.js +585 -0
  10. package/node_modules/@groove-dev/daemon/src/process.js +27 -2
  11. package/node_modules/@groove-dev/daemon/src/registry.js +2 -1
  12. package/node_modules/@groove-dev/daemon/src/routes/auto-agents.js +264 -0
  13. package/node_modules/@groove-dev/daemon/src/validate.js +6 -0
  14. package/node_modules/@groove-dev/gui/dist/assets/index-CTer01Vg.js +1065 -0
  15. package/node_modules/@groove-dev/gui/dist/assets/index-DTFtRtkx.css +1 -0
  16. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  17. package/node_modules/@groove-dev/gui/package.json +1 -1
  18. package/node_modules/@groove-dev/gui/src/App.jsx +2 -0
  19. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +53 -0
  20. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +4 -4
  21. package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +95 -2
  22. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +50 -1
  23. package/node_modules/@groove-dev/gui/src/components/auto-agents/auto-agent-card.jsx +139 -0
  24. package/node_modules/@groove-dev/gui/src/components/auto-agents/auto-agent-detail.jsx +286 -0
  25. package/node_modules/@groove-dev/gui/src/components/auto-agents/setup-wizard.jsx +284 -0
  26. package/node_modules/@groove-dev/gui/src/components/fleet/fleet-pane.jsx +16 -3
  27. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -1
  28. package/node_modules/@groove-dev/gui/src/stores/groove.js +14 -0
  29. package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +2 -0
  30. package/node_modules/@groove-dev/gui/src/stores/slices/auto-agents-slice.js +149 -0
  31. package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +14 -11
  32. package/node_modules/@groove-dev/gui/src/views/auto-agents.jsx +70 -0
  33. package/node_modules/@groove-dev/gui/src/views/settings.jsx +13 -6
  34. package/package.json +1 -1
  35. package/packages/cli/package.json +1 -1
  36. package/packages/daemon/package.json +1 -1
  37. package/packages/daemon/src/api.js +3 -1
  38. package/packages/daemon/src/autostate.js +198 -0
  39. package/packages/daemon/src/index.js +6 -0
  40. package/packages/daemon/src/orchestrator.js +585 -0
  41. package/packages/daemon/src/process.js +27 -2
  42. package/packages/daemon/src/registry.js +2 -1
  43. package/packages/daemon/src/routes/auto-agents.js +264 -0
  44. package/packages/daemon/src/validate.js +6 -0
  45. package/packages/gui/dist/assets/index-CTer01Vg.js +1065 -0
  46. package/packages/gui/dist/assets/index-DTFtRtkx.css +1 -0
  47. package/packages/gui/dist/index.html +2 -2
  48. package/packages/gui/package.json +1 -1
  49. package/packages/gui/src/App.jsx +2 -0
  50. package/packages/gui/src/components/agents/agent-config.jsx +53 -0
  51. package/packages/gui/src/components/agents/agent-feed.jsx +4 -4
  52. package/packages/gui/src/components/agents/agent-panel.jsx +95 -2
  53. package/packages/gui/src/components/agents/spawn-wizard.jsx +50 -1
  54. package/packages/gui/src/components/auto-agents/auto-agent-card.jsx +139 -0
  55. package/packages/gui/src/components/auto-agents/auto-agent-detail.jsx +286 -0
  56. package/packages/gui/src/components/auto-agents/setup-wizard.jsx +284 -0
  57. package/packages/gui/src/components/fleet/fleet-pane.jsx +16 -3
  58. package/packages/gui/src/components/layout/activity-bar.jsx +2 -1
  59. package/packages/gui/src/stores/groove.js +14 -0
  60. package/packages/gui/src/stores/slices/agents-slice.js +2 -0
  61. package/packages/gui/src/stores/slices/auto-agents-slice.js +149 -0
  62. package/packages/gui/src/stores/slices/ui-slice.js +14 -11
  63. package/packages/gui/src/views/auto-agents.jsx +70 -0
  64. package/packages/gui/src/views/settings.jsx +13 -6
  65. package/node_modules/@groove-dev/gui/dist/assets/index-BvJwMNAX.css +0 -1
  66. package/node_modules/@groove-dev/gui/dist/assets/index-DZY-EWPs.js +0 -1030
  67. package/packages/gui/dist/assets/index-BvJwMNAX.css +0 -1
  68. package/packages/gui/dist/assets/index-DZY-EWPs.js +0 -1030
@@ -0,0 +1,264 @@
1
+ // GROOVE — Auto Agent API Routes
2
+ // FSL-1.1-Apache-2.0 — see LICENSE
3
+
4
+ import { spawn } from 'child_process';
5
+ import { getProvider, resolveProviderCommand } from '../providers/index.js';
6
+
7
+ function execHeadlessChat(daemon, messages, systemPrompt) {
8
+ const provider = getProvider('claude-code');
9
+ if (!provider) return Promise.reject(new Error('Claude Code provider not available'));
10
+
11
+ const fullPrompt = systemPrompt + '\n\n' + messages.map(m =>
12
+ `${m.role === 'user' ? 'Human' : 'Assistant'}: ${m.content}`
13
+ ).join('\n\n') + '\n\nAssistant:';
14
+
15
+ const cmd = resolveProviderCommand('claude-code') || 'claude';
16
+ const args = ['-p', '--output-format', 'text'];
17
+
18
+ return new Promise((resolve, reject) => {
19
+ let stdout = '';
20
+ const proc = spawn(cmd, args, {
21
+ env: process.env,
22
+ cwd: daemon.projectDir,
23
+ stdio: ['pipe', 'pipe', 'pipe'],
24
+ });
25
+ proc.on('error', reject);
26
+ proc.stdin.write(fullPrompt);
27
+ proc.stdin.end();
28
+ proc.stdout.on('data', (d) => { stdout += d.toString(); });
29
+ const timer = setTimeout(() => { proc.kill(); reject(new Error('Setup chat timeout')); }, 120_000);
30
+ proc.on('exit', (code) => {
31
+ clearTimeout(timer);
32
+ if (code !== 0) return reject(new Error(`Headless exited with code ${code}`));
33
+
34
+ // Try to parse stream-json output
35
+ let response = '';
36
+ for (const line of stdout.split('\n')) {
37
+ try {
38
+ const json = JSON.parse(line);
39
+ if (typeof json.result === 'string') { response = json.result; break; }
40
+ if (json.type === 'assistant' && typeof json.message?.content === 'string') {
41
+ response = json.message.content;
42
+ }
43
+ if (json.type === 'assistant' && Array.isArray(json.message?.content)) {
44
+ const text = json.message.content.filter(b => b.type === 'text').map(b => b.text).join('');
45
+ if (text) response = text;
46
+ }
47
+ } catch { /* not json */ }
48
+ }
49
+ if (!response) response = stdout.trim();
50
+
51
+ // Extract config if present
52
+ let config = null;
53
+ const jsonMatch = response.match(/```json\s*([\s\S]*?)```/);
54
+ if (jsonMatch) {
55
+ try {
56
+ const parsed = JSON.parse(jsonMatch[1]);
57
+ if (parsed.ready) config = parsed;
58
+ } catch { /* not valid json */ }
59
+ }
60
+
61
+ resolve({ response, config });
62
+ });
63
+ });
64
+ }
65
+
66
+ export function registerAutoAgentRoutes(app, daemon) {
67
+
68
+ // AI-assisted setup chat (must be before :id routes)
69
+ app.post('/api/auto-agents/setup-chat', async (req, res) => {
70
+ const { messages, systemPrompt } = req.body;
71
+ if (!messages || !Array.isArray(messages)) {
72
+ return res.status(400).json({ error: 'messages array is required' });
73
+ }
74
+ try {
75
+ const result = await execHeadlessChat(daemon, messages, systemPrompt || '');
76
+ res.json(result);
77
+ } catch (err) {
78
+ res.status(500).json({ error: err.message });
79
+ }
80
+ });
81
+
82
+ // List all auto agent definitions
83
+ app.get('/api/auto-agents', (req, res) => {
84
+ const defs = daemon.orchestrator.list();
85
+ const enriched = defs.map(def => {
86
+ const state = daemon.autoState.getState(def.id);
87
+ const activeAgentId = daemon.orchestrator.activeAgents.get(def.id);
88
+ let activeAgent = null;
89
+ if (activeAgentId) {
90
+ const agent = daemon.registry.get(activeAgentId);
91
+ if (agent) activeAgent = { id: agent.id, status: agent.status, spawnedAt: agent.spawnedAt };
92
+ }
93
+ return { ...def, state, activeAgent };
94
+ });
95
+ res.json(enriched);
96
+ });
97
+
98
+ // Create a new auto agent
99
+ app.post('/api/auto-agents', (req, res) => {
100
+ try {
101
+ const def = daemon.orchestrator.create(req.body);
102
+ res.status(201).json(def);
103
+ } catch (err) {
104
+ res.status(400).json({ error: err.message });
105
+ }
106
+ });
107
+
108
+ // Get a single auto agent with full status
109
+ app.get('/api/auto-agents/:id', (req, res) => {
110
+ const status = daemon.orchestrator.getStatus(req.params.id);
111
+ if (!status) return res.status(404).json({ error: 'Auto agent not found' });
112
+ res.json(status);
113
+ });
114
+
115
+ // Update an auto agent definition
116
+ app.patch('/api/auto-agents/:id', (req, res) => {
117
+ try {
118
+ const def = daemon.orchestrator.update(req.params.id, req.body);
119
+ res.json(def);
120
+ } catch (err) {
121
+ res.status(400).json({ error: err.message });
122
+ }
123
+ });
124
+
125
+ // Delete an auto agent
126
+ app.delete('/api/auto-agents/:id', (req, res) => {
127
+ try {
128
+ daemon.orchestrator.delete(req.params.id);
129
+ res.json({ ok: true });
130
+ } catch (err) {
131
+ res.status(400).json({ error: err.message });
132
+ }
133
+ });
134
+
135
+ // Pause
136
+ app.post('/api/auto-agents/:id/pause', (req, res) => {
137
+ try {
138
+ const def = daemon.orchestrator.pause(req.params.id);
139
+ res.json(def);
140
+ } catch (err) {
141
+ res.status(400).json({ error: err.message });
142
+ }
143
+ });
144
+
145
+ // Resume
146
+ app.post('/api/auto-agents/:id/resume', (req, res) => {
147
+ try {
148
+ const def = daemon.orchestrator.resume(req.params.id);
149
+ res.json(def);
150
+ } catch (err) {
151
+ res.status(400).json({ error: err.message });
152
+ }
153
+ });
154
+
155
+ // Trigger now (manual iteration)
156
+ app.post('/api/auto-agents/:id/trigger', async (req, res) => {
157
+ try {
158
+ const agent = await daemon.orchestrator.trigger(req.params.id);
159
+ res.json({ ok: true, agentId: agent.id });
160
+ } catch (err) {
161
+ res.status(400).json({ error: err.message });
162
+ }
163
+ });
164
+
165
+ // --- State Layer ---
166
+
167
+ // Get state
168
+ app.get('/api/auto-agents/:id/state', (req, res) => {
169
+ const def = daemon.orchestrator.get(req.params.id);
170
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
171
+ res.json(daemon.autoState.getState(req.params.id));
172
+ });
173
+
174
+ // Update state (agent or human can call this to redirect)
175
+ app.patch('/api/auto-agents/:id/state', (req, res) => {
176
+ const def = daemon.orchestrator.get(req.params.id);
177
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
178
+ try {
179
+ const state = daemon.autoState.setState(req.params.id, req.body);
180
+ daemon.broadcast({ type: 'auto-agent:state-updated', data: { id: req.params.id, state } });
181
+ res.json(state);
182
+ } catch (err) {
183
+ res.status(400).json({ error: err.message });
184
+ }
185
+ });
186
+
187
+ // Get journal
188
+ app.get('/api/auto-agents/:id/journal', (req, res) => {
189
+ const def = daemon.orchestrator.get(req.params.id);
190
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
191
+ const limit = parseInt(req.query.limit) || 50;
192
+ const since = req.query.since || undefined;
193
+ res.json(daemon.autoState.getJournal(req.params.id, { limit, since }));
194
+ });
195
+
196
+ // Append journal entry
197
+ app.post('/api/auto-agents/:id/journal', (req, res) => {
198
+ const def = daemon.orchestrator.get(req.params.id);
199
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
200
+ try {
201
+ const entry = daemon.autoState.appendJournal(req.params.id, req.body);
202
+ daemon.broadcast({ type: 'auto-agent:journal-entry', data: { id: req.params.id, entry } });
203
+ res.status(201).json(entry);
204
+ } catch (err) {
205
+ res.status(400).json({ error: err.message });
206
+ }
207
+ });
208
+
209
+ // Append history entry
210
+ app.post('/api/auto-agents/:id/history', (req, res) => {
211
+ const def = daemon.orchestrator.get(req.params.id);
212
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
213
+ try {
214
+ const history = daemon.autoState.appendHistory(req.params.id, req.body);
215
+ daemon.broadcast({ type: 'auto-agent:history-entry', data: { id: req.params.id } });
216
+ res.json({ ok: true, count: history.length });
217
+ } catch (err) {
218
+ res.status(400).json({ error: err.message });
219
+ }
220
+ });
221
+
222
+ // Get/set roadmap
223
+ app.get('/api/auto-agents/:id/roadmap', (req, res) => {
224
+ const def = daemon.orchestrator.get(req.params.id);
225
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
226
+ res.type('text/markdown').send(daemon.autoState.getRoadmap(req.params.id));
227
+ });
228
+
229
+ app.put('/api/auto-agents/:id/roadmap', (req, res) => {
230
+ const def = daemon.orchestrator.get(req.params.id);
231
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
232
+ const content = typeof req.body === 'string' ? req.body : req.body.content;
233
+ if (!content) return res.status(400).json({ error: 'Content is required' });
234
+ daemon.autoState.setRoadmap(req.params.id, content);
235
+ daemon.broadcast({ type: 'auto-agent:roadmap-updated', data: { id: req.params.id } });
236
+ res.json({ ok: true });
237
+ });
238
+
239
+ // Get/set prompt
240
+ app.get('/api/auto-agents/:id/prompt', (req, res) => {
241
+ const def = daemon.orchestrator.get(req.params.id);
242
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
243
+ res.type('text/markdown').send(daemon.autoState.getPrompt(req.params.id));
244
+ });
245
+
246
+ app.put('/api/auto-agents/:id/prompt', (req, res) => {
247
+ const def = daemon.orchestrator.get(req.params.id);
248
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
249
+ const content = typeof req.body === 'string' ? req.body : req.body.content;
250
+ if (!content) return res.status(400).json({ error: 'Content is required' });
251
+ daemon.autoState.setPrompt(req.params.id, content);
252
+ daemon.broadcast({ type: 'auto-agent:prompt-updated', data: { id: req.params.id } });
253
+ res.json({ ok: true });
254
+ });
255
+
256
+ // Run history
257
+ app.get('/api/auto-agents/:id/runs', (req, res) => {
258
+ const def = daemon.orchestrator.get(req.params.id);
259
+ if (!def) return res.status(404).json({ error: 'Auto agent not found' });
260
+ const limit = parseInt(req.query.limit) || 20;
261
+ res.json(daemon.autoState.listRuns(req.params.id, { limit }));
262
+ });
263
+
264
+ }
@@ -118,6 +118,11 @@ export function validateAgentConfig(config) {
118
118
  const validRouting = ['fixed', 'auto', 'auto-floor'];
119
119
  const routingMode = validRouting.includes(config.routingMode) ? config.routingMode : undefined;
120
120
 
121
+ // Claude Code billing mode: 'subscription' (OAuth login) or 'usage' (API credits).
122
+ // Only meaningful for the claude-code provider; ignored by others.
123
+ const authMode = (config.authMode === 'usage' || config.authMode === 'subscription')
124
+ ? config.authMode : undefined;
125
+
121
126
  // Return sanitized config (only known fields)
122
127
  return {
123
128
  role: config.role,
@@ -139,6 +144,7 @@ export function validateAgentConfig(config) {
139
144
  verbosity,
140
145
  effort,
141
146
  routingMode,
147
+ authMode,
142
148
  fast: config.fast === true ? true : undefined,
143
149
  labPresetId: (typeof config.labPresetId === 'string' && config.labPresetId.length <= 64) ? config.labPresetId : undefined,
144
150
  keeperTags: Array.isArray(config.keeperTags) ? config.keeperTags.filter(t => typeof t === 'string').slice(0, 20) : undefined,