groove-dev 0.27.141 → 0.27.143
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/CLAUDE.md +7 -0
- 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 +18 -7
- package/node_modules/@groove-dev/daemon/src/introducer.js +1 -1
- package/node_modules/@groove-dev/daemon/src/journalist.js +3 -2
- package/node_modules/@groove-dev/daemon/src/keeper.js +2 -2
- package/node_modules/@groove-dev/daemon/src/memory.js +8 -5
- package/node_modules/@groove-dev/daemon/src/process.js +5 -16
- package/node_modules/@groove-dev/daemon/src/rotator.js +25 -8
- package/node_modules/@groove-dev/gui/dist/assets/{codemirror-BQqYnZfL.js → codemirror-BYKpdS2W.js} +10 -10
- package/node_modules/@groove-dev/gui/dist/assets/index-CCVvAoQn.css +1 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-DGIv_TRm.js +984 -0
- package/node_modules/@groove-dev/gui/dist/index.html +3 -3
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/app.jsx +0 -2
- package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +73 -17
- package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +8 -2
- package/node_modules/@groove-dev/gui/src/components/agents/agent-file-tree.jsx +5 -6
- package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +79 -5
- package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +2 -53
- package/node_modules/@groove-dev/gui/src/components/dashboard/context-gauges.jsx +111 -0
- package/node_modules/@groove-dev/gui/src/components/dashboard/routing-chart.jsx +70 -33
- package/node_modules/@groove-dev/gui/src/components/editor/code-editor.jsx +2 -68
- package/node_modules/@groove-dev/gui/src/components/editor/selection-menu.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +1 -2
- package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +0 -1
- package/node_modules/@groove-dev/gui/src/stores/groove.js +3 -3
- package/node_modules/@groove-dev/gui/src/views/dashboard.jsx +2 -0
- package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +3 -71
- package/node_modules/@groove-dev/gui/src/views/models.jsx +5 -6
- 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 +18 -7
- package/packages/daemon/src/introducer.js +1 -1
- package/packages/daemon/src/journalist.js +3 -2
- package/packages/daemon/src/keeper.js +2 -2
- package/packages/daemon/src/memory.js +8 -5
- package/packages/daemon/src/process.js +5 -16
- package/packages/daemon/src/rotator.js +25 -8
- package/packages/gui/dist/assets/{codemirror-BQqYnZfL.js → codemirror-BYKpdS2W.js} +10 -10
- package/packages/gui/dist/assets/index-CCVvAoQn.css +1 -0
- package/packages/gui/dist/assets/index-DGIv_TRm.js +984 -0
- package/packages/gui/dist/index.html +3 -3
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/app.jsx +0 -2
- package/packages/gui/src/components/agents/agent-chat.jsx +73 -17
- package/packages/gui/src/components/agents/agent-feed.jsx +8 -2
- package/packages/gui/src/components/agents/agent-file-tree.jsx +5 -6
- package/packages/gui/src/components/agents/agent-panel.jsx +79 -5
- package/packages/gui/src/components/agents/workspace-mode.jsx +2 -53
- package/packages/gui/src/components/dashboard/context-gauges.jsx +111 -0
- package/packages/gui/src/components/dashboard/routing-chart.jsx +70 -33
- package/packages/gui/src/components/editor/code-editor.jsx +2 -68
- package/packages/gui/src/components/editor/selection-menu.jsx +2 -0
- package/packages/gui/src/components/layout/activity-bar.jsx +1 -2
- package/packages/gui/src/components/layout/terminal-panel.jsx +0 -1
- package/packages/gui/src/stores/groove.js +3 -3
- package/packages/gui/src/views/dashboard.jsx +2 -0
- package/packages/gui/src/views/marketplace.jsx +3 -71
- package/packages/gui/src/views/models.jsx +5 -6
- package/node_modules/@groove-dev/gui/dist/assets/index-A4e1gIDh.css +0 -1
- package/node_modules/@groove-dev/gui/dist/assets/index-P1hsM27-.js +0 -8696
- package/node_modules/@groove-dev/gui/src/components/toys/toy-card.jsx +0 -78
- package/node_modules/@groove-dev/gui/src/components/toys/toy-creator.jsx +0 -144
- package/node_modules/@groove-dev/gui/src/components/toys/toy-launcher.jsx +0 -187
- package/node_modules/@groove-dev/gui/src/views/toys.jsx +0 -162
- package/packages/gui/dist/assets/index-A4e1gIDh.css +0 -1
- package/packages/gui/dist/assets/index-P1hsM27-.js +0 -8696
- package/packages/gui/src/components/toys/toy-card.jsx +0 -78
- package/packages/gui/src/components/toys/toy-creator.jsx +0 -144
- package/packages/gui/src/components/toys/toy-launcher.jsx +0 -187
- package/packages/gui/src/views/toys.jsx +0 -162
package/CLAUDE.md
CHANGED
|
@@ -295,3 +295,10 @@ Audit-driven release. Multi-agent orchestration system with 7 coordination layer
|
|
|
295
295
|
- Dashboard: routing donut, cache panel, context health gauges
|
|
296
296
|
- Monitor/QC agent mode (stay active, loop)
|
|
297
297
|
- Distribution: demo video, HN launch, Twitter content
|
|
298
|
+
|
|
299
|
+
<!-- GROOVE:START -->
|
|
300
|
+
## GROOVE Orchestration (auto-injected)
|
|
301
|
+
Active agents: 0
|
|
302
|
+
See AGENTS_REGISTRY.md for full agent state.
|
|
303
|
+
**Memory policy:** GROOVE manages project memory automatically. Do not read or write MEMORY.md or .groove/memory/ files directly.
|
|
304
|
+
<!-- GROOVE:END -->
|
|
@@ -460,13 +460,14 @@ export function createApi(app, daemon) {
|
|
|
460
460
|
// Discoveries (error → fix pairs)
|
|
461
461
|
app.get('/api/memory/discoveries', (req, res) => {
|
|
462
462
|
const role = req.query.role;
|
|
463
|
+
const teamId = req.query.teamId;
|
|
463
464
|
const limit = Math.min(parseInt(req.query.limit) || 100, 500);
|
|
464
|
-
res.json({ discoveries: daemon.memory.listDiscoveries({ role, limit }) });
|
|
465
|
+
res.json({ discoveries: daemon.memory.listDiscoveries({ role, teamId, limit }) });
|
|
465
466
|
});
|
|
466
467
|
|
|
467
468
|
app.post('/api/memory/discoveries', (req, res) => {
|
|
468
|
-
const { agentId, role, trigger, fix, outcome } = req.body || {};
|
|
469
|
-
const result = daemon.memory.addDiscovery({ agentId, role, trigger, fix, outcome });
|
|
469
|
+
const { agentId, role, trigger, fix, outcome, teamId } = req.body || {};
|
|
470
|
+
const result = daemon.memory.addDiscovery({ agentId, role, trigger, fix, outcome, teamId });
|
|
470
471
|
if (!result.added && result.error) {
|
|
471
472
|
return res.status(400).json(result);
|
|
472
473
|
}
|
|
@@ -3171,11 +3172,21 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
3171
3172
|
|
|
3172
3173
|
function validateFilePath(relPath, projectDir) {
|
|
3173
3174
|
if (!relPath || typeof relPath !== 'string') return { error: 'path is required' };
|
|
3174
|
-
if (relPath.
|
|
3175
|
-
|
|
3175
|
+
if (relPath.includes('\0')) return { error: 'Invalid path' };
|
|
3176
|
+
|
|
3177
|
+
let fullPath;
|
|
3178
|
+
if (relPath.startsWith('/')) {
|
|
3179
|
+
if (relPath.includes('..')) return { error: 'Invalid path' };
|
|
3180
|
+
if (!relPath.startsWith(projectDir + '/') && relPath !== projectDir) {
|
|
3181
|
+
return { error: 'Path outside project' };
|
|
3182
|
+
}
|
|
3183
|
+
fullPath = relPath;
|
|
3184
|
+
} else {
|
|
3185
|
+
if (relPath.includes('..')) return { error: 'Invalid path' };
|
|
3186
|
+
fullPath = resolve(projectDir, relPath);
|
|
3187
|
+
if (!fullPath.startsWith(projectDir)) return { error: 'Path outside project' };
|
|
3176
3188
|
}
|
|
3177
|
-
|
|
3178
|
-
if (!fullPath.startsWith(projectDir)) return { error: 'Path outside project' };
|
|
3189
|
+
|
|
3179
3190
|
// Symlink resolution — ensure real path is also within project
|
|
3180
3191
|
try {
|
|
3181
3192
|
const realPath = realpathSync(fullPath);
|
|
@@ -437,7 +437,7 @@ export class Introducer {
|
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
if (!isLightPlanner && (hasTask || isRotation)) {
|
|
440
|
-
const discoveries = this.daemon.memory.getDiscoveriesMarkdown(newAgent.role, 8, 600, newAgent.scope);
|
|
440
|
+
const discoveries = this.daemon.memory.getDiscoveriesMarkdown(newAgent.role, 8, 600, newAgent.scope, newAgent.teamId);
|
|
441
441
|
if (discoveries) {
|
|
442
442
|
parts.push(`### Known Fixes for ${newAgent.role} Role\n${discoveries}`);
|
|
443
443
|
}
|
|
@@ -877,7 +877,7 @@ export class Journalist {
|
|
|
877
877
|
const entries = agentLog?.entries || [];
|
|
878
878
|
|
|
879
879
|
// Layer 7 memory: discoveries (inline, not pointer — agents lose context with pointers), constraints, specializations
|
|
880
|
-
const discoveries = this.daemon.memory?.getDiscoveriesMarkdown(agent.role, 10, 1500) || '';
|
|
880
|
+
const discoveries = this.daemon.memory?.getDiscoveriesMarkdown(agent.role, 10, 1500, agent.scope, agent.teamId) || '';
|
|
881
881
|
const constraints = this.daemon.memory?.getConstraintsMarkdown(2000) || '';
|
|
882
882
|
const specialization = this.daemon.memory?.getSpecialization(agent.id);
|
|
883
883
|
const specLine = specialization?.avgQualityScore != null
|
|
@@ -1106,7 +1106,7 @@ export class Journalist {
|
|
|
1106
1106
|
if (!thread) return null;
|
|
1107
1107
|
|
|
1108
1108
|
const constraints = this.daemon.memory?.getConstraintsMarkdown(2000) || '';
|
|
1109
|
-
const discoveries = this.daemon.memory?.getDiscoveriesMarkdown(agent.role, 5, 1000) || '';
|
|
1109
|
+
const discoveries = this.daemon.memory?.getDiscoveriesMarkdown(agent.role, 5, 1000, agent.scope, agent.teamId) || '';
|
|
1110
1110
|
|
|
1111
1111
|
let prompt = [
|
|
1112
1112
|
`# Session Context Resume`,
|
|
@@ -1352,6 +1352,7 @@ export class Journalist {
|
|
|
1352
1352
|
this.daemon.memory.addDiscovery({
|
|
1353
1353
|
agentId: agent.id,
|
|
1354
1354
|
role: agent.role,
|
|
1355
|
+
teamId: agent.teamId || null,
|
|
1355
1356
|
trigger: trigger.slice(0, 300),
|
|
1356
1357
|
fix: fix.slice(0, 500),
|
|
1357
1358
|
outcome: 'success',
|
|
@@ -254,9 +254,9 @@ export class Keeper {
|
|
|
254
254
|
// ── Command parser ────────────────────────────────────────
|
|
255
255
|
|
|
256
256
|
static parseCommand(text) {
|
|
257
|
-
const cmdMatch = text.match(/\[(save|append|update|delete|view|doc|link|read|instruct)\]
|
|
257
|
+
const cmdMatch = text.match(/\[(save|append|update|delete|view|doc|link|read|instruct)\]/i);
|
|
258
258
|
if (!cmdMatch) return null;
|
|
259
|
-
const command =
|
|
259
|
+
const command = cmdMatch[1].toLowerCase();
|
|
260
260
|
const rest = text.slice(cmdMatch.index + cmdMatch[0].length).trim();
|
|
261
261
|
|
|
262
262
|
if (command === 'instruct') {
|
|
@@ -261,7 +261,7 @@ export class MemoryStore {
|
|
|
261
261
|
|
|
262
262
|
// --- Discoveries (error → fix pairs) ---
|
|
263
263
|
|
|
264
|
-
addDiscovery({ agentId, role, trigger, fix, outcome = 'success' }) {
|
|
264
|
+
addDiscovery({ agentId, role, trigger, fix, outcome = 'success', teamId }) {
|
|
265
265
|
if (!trigger || !fix) return { added: false, error: 'trigger and fix required' };
|
|
266
266
|
if (outcome !== 'success') return { added: false, reason: 'only successes stored' };
|
|
267
267
|
|
|
@@ -277,6 +277,7 @@ export class MemoryStore {
|
|
|
277
277
|
ts: new Date().toISOString(),
|
|
278
278
|
agentId: agentId || null,
|
|
279
279
|
role: role || 'unknown',
|
|
280
|
+
teamId: teamId || null,
|
|
280
281
|
trigger: truncate(String(trigger).trim(), 300),
|
|
281
282
|
fix: truncate(String(fix).trim(), 500),
|
|
282
283
|
outcome,
|
|
@@ -298,7 +299,7 @@ export class MemoryStore {
|
|
|
298
299
|
}
|
|
299
300
|
}
|
|
300
301
|
|
|
301
|
-
listDiscoveries({ role, limit = 100 } = {}) {
|
|
302
|
+
listDiscoveries({ role, teamId, limit = 100 } = {}) {
|
|
302
303
|
if (!existsSync(this.discoveriesPath)) return [];
|
|
303
304
|
try {
|
|
304
305
|
const lines = readFileSync(this.discoveriesPath, 'utf8').split('\n').filter(Boolean);
|
|
@@ -306,7 +307,9 @@ export class MemoryStore {
|
|
|
306
307
|
for (const line of lines) {
|
|
307
308
|
try {
|
|
308
309
|
const e = JSON.parse(line);
|
|
309
|
-
if (
|
|
310
|
+
if (role && e.role !== role) continue;
|
|
311
|
+
if (teamId && e.teamId && e.teamId !== teamId) continue;
|
|
312
|
+
entries.push(e);
|
|
310
313
|
} catch { /* skip malformed */ }
|
|
311
314
|
}
|
|
312
315
|
return entries.slice(-limit).reverse(); // newest first
|
|
@@ -328,8 +331,8 @@ export class MemoryStore {
|
|
|
328
331
|
} catch { /* best-effort */ }
|
|
329
332
|
}
|
|
330
333
|
|
|
331
|
-
getDiscoveriesMarkdown(role, limit = 20, maxChars = 4000, scope) {
|
|
332
|
-
let entries = this.listDiscoveries({ role, limit: limit * 3 });
|
|
334
|
+
getDiscoveriesMarkdown(role, limit = 20, maxChars = 4000, scope, teamId) {
|
|
335
|
+
let entries = this.listDiscoveries({ role, teamId, limit: limit * 3 });
|
|
333
336
|
if (entries.length === 0) return '';
|
|
334
337
|
|
|
335
338
|
if (scope && Array.isArray(scope) && scope.length > 0) {
|
|
@@ -2000,22 +2000,11 @@ For normal file edits within your scope, proceed without review.
|
|
|
2000
2000
|
return this.daemon.rotator.rotate(agentId, { additionalPrompt: message });
|
|
2001
2001
|
}
|
|
2002
2002
|
|
|
2003
|
-
//
|
|
2004
|
-
//
|
|
2005
|
-
//
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
? Date.now() - new Date(agent.lastActivity).getTime()
|
|
2009
|
-
: Infinity;
|
|
2010
|
-
|
|
2011
|
-
if (idleMs > IDLE_CONTEXT_THRESHOLD_MS && this.daemon.journalist) {
|
|
2012
|
-
const resumePrompt = this.daemon.journalist.buildConversationResumePrompt(agent, message);
|
|
2013
|
-
if (resumePrompt) {
|
|
2014
|
-
console.log(`[Groove] Agent ${agent.name} idle ${Math.round(idleMs / 60000)}min — using conversation-thread resume`);
|
|
2015
|
-
// Use rotation machinery but with our richer prompt instead of handoff brief
|
|
2016
|
-
return this._conversationResume(agentId, agent, resumePrompt);
|
|
2017
|
-
}
|
|
2018
|
-
}
|
|
2003
|
+
// Conversation-thread resume: available via explicit API call (conversationResume=true)
|
|
2004
|
+
// but NOT automatic. The old 5-min idle threshold was too aggressive — it replaced
|
|
2005
|
+
// every normal --resume with a full re-spawn, losing the Claude Code session.
|
|
2006
|
+
// Normal --resume preserves the actual CC session; conversation-resume is for when
|
|
2007
|
+
// the user explicitly wants a fresh context with the dialogue replayed.
|
|
2019
2008
|
|
|
2020
2009
|
const provider = getProvider(agent.provider || 'claude-code');
|
|
2021
2010
|
if (!provider?.buildResumeCommand) {
|
|
@@ -346,14 +346,31 @@ export class Rotator extends EventEmitter {
|
|
|
346
346
|
delete this.scoreHistory[agentId];
|
|
347
347
|
this.compactionCounts.delete(agentId);
|
|
348
348
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
if (
|
|
356
|
-
|
|
349
|
+
// Try conversation-thread resume first: replays the actual user↔assistant
|
|
350
|
+
// dialogue from stream-json logs so the new agent picks up with full context
|
|
351
|
+
// instead of a lossy journalist summary. Falls back to the brief if logs are
|
|
352
|
+
// empty or the thread is too short to be useful.
|
|
353
|
+
let brief;
|
|
354
|
+
let usedConversationThread = false;
|
|
355
|
+
if (typeof journalist.buildConversationResumePrompt === 'function') {
|
|
356
|
+
const conversationPrompt = journalist.buildConversationResumePrompt(
|
|
357
|
+
agent,
|
|
358
|
+
options.additionalPrompt || ''
|
|
359
|
+
);
|
|
360
|
+
if (conversationPrompt && conversationPrompt.length > 500) {
|
|
361
|
+
brief = conversationPrompt;
|
|
362
|
+
usedConversationThread = true;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (!usedConversationThread) {
|
|
366
|
+
brief = await journalist.generateHandoffBrief(agent, {
|
|
367
|
+
reason: options.reason,
|
|
368
|
+
qualityScore: options.qualityScore,
|
|
369
|
+
signals: options.signals,
|
|
370
|
+
});
|
|
371
|
+
if (options.additionalPrompt) {
|
|
372
|
+
brief = brief + '\n\n## User Instruction\n\n' + options.additionalPrompt;
|
|
373
|
+
}
|
|
357
374
|
}
|
|
358
375
|
|
|
359
376
|
if (agent.role === 'planner' && !brief.includes('PLANNING ONLY')) {
|