groove-dev 0.26.16 → 0.26.18
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/daemon/src/api.js +11 -1
- package/node_modules/@groove-dev/daemon/src/process.js +68 -1
- package/node_modules/@groove-dev/gui/dist/assets/{index-7eQvV_N9.js → index-aT3nOZj0.js} +21 -21
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/src/stores/groove.js +3 -1
- package/node_modules/@groove-dev/gui/src/views/agents.jsx +7 -3
- package/package.json +1 -1
- package/packages/daemon/src/api.js +11 -1
- package/packages/daemon/src/process.js +68 -1
- package/packages/gui/dist/assets/{index-7eQvV_N9.js → index-aT3nOZj0.js} +21 -21
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/src/stores/groove.js +3 -1
- package/packages/gui/src/views/agents.jsx +7 -3
|
@@ -1768,7 +1768,17 @@ Keep responses concise. Help them think, don't lecture them about the system the
|
|
|
1768
1768
|
}
|
|
1769
1769
|
|
|
1770
1770
|
const baseDir = daemon.config?.defaultWorkingDir || daemon.projectDir;
|
|
1771
|
-
|
|
1771
|
+
|
|
1772
|
+
// Use the planner's teamId so launched agents join the correct team.
|
|
1773
|
+
// Accept explicit teamId from request body, or find the most recent planner agent.
|
|
1774
|
+
let launchTeamId = req.body?.teamId || null;
|
|
1775
|
+
if (!launchTeamId) {
|
|
1776
|
+
const planners = daemon.registry.getAll()
|
|
1777
|
+
.filter((a) => a.role === 'planner')
|
|
1778
|
+
.sort((a, b) => (b.lastActivity || '').localeCompare(a.lastActivity || ''));
|
|
1779
|
+
launchTeamId = planners[0]?.teamId || null;
|
|
1780
|
+
}
|
|
1781
|
+
const defaultTeamId = launchTeamId || daemon.teams.getDefault()?.id || null;
|
|
1772
1782
|
|
|
1773
1783
|
// If planner specified a project directory, create it and use it as workingDir
|
|
1774
1784
|
let projectWorkingDir = baseDir;
|
|
@@ -368,6 +368,12 @@ For normal file edits within your scope, proceed without review.
|
|
|
368
368
|
if (this.daemon.integrations) this.daemon.integrations.refreshMcpJson();
|
|
369
369
|
if (status === 'completed' && this.daemon.journalist) this.daemon.journalist.cycle().catch(() => {});
|
|
370
370
|
this._checkPhase2(agent.id);
|
|
371
|
+
|
|
372
|
+
// Auto-trigger idle QC in the same team
|
|
373
|
+
if (status === 'completed') {
|
|
374
|
+
const files = this.daemon.journalist?.getAgentFiles(agent) || [];
|
|
375
|
+
if (files.length > 0) this._triggerIdleQC(agent);
|
|
376
|
+
}
|
|
371
377
|
});
|
|
372
378
|
|
|
373
379
|
// Wire errors — broadcast to GUI for display
|
|
@@ -561,6 +567,13 @@ For normal file edits within your scope, proceed without review.
|
|
|
561
567
|
|
|
562
568
|
// Phase 2 auto-spawn: check if all phase 1 agents for a team are done
|
|
563
569
|
this._checkPhase2(agent.id);
|
|
570
|
+
|
|
571
|
+
// Auto-trigger idle QC: if this agent modified files and there's an idle QC
|
|
572
|
+
// in the same team, activate it to verify the changes
|
|
573
|
+
if (finalStatus === 'completed') {
|
|
574
|
+
const files = this.daemon.journalist?.getAgentFiles(agent) || [];
|
|
575
|
+
if (files.length > 0) this._triggerIdleQC(agent);
|
|
576
|
+
}
|
|
564
577
|
});
|
|
565
578
|
|
|
566
579
|
proc.on('error', (err) => {
|
|
@@ -660,8 +673,20 @@ For normal file edits within your scope, proceed without review.
|
|
|
660
673
|
// Remove from pending
|
|
661
674
|
pending.splice(i, 1);
|
|
662
675
|
|
|
663
|
-
//
|
|
676
|
+
// Check if phase 1 agents did any real work by looking at file modifications.
|
|
677
|
+
// If no agent modified any files, there's nothing to QC.
|
|
678
|
+
const journalist = this.daemon.journalist;
|
|
679
|
+
const phase1Idle = group.waitFor.every((id) => {
|
|
680
|
+
const a = registry.get(id);
|
|
681
|
+
if (!a) return true;
|
|
682
|
+
const files = journalist?.getAgentFiles(a) || [];
|
|
683
|
+
return files.length === 0;
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// Auto-spawn phase 2 agents — if phase 1 was idle, clear the prompt
|
|
687
|
+
// so QC also waits for instructions instead of auditing nothing
|
|
664
688
|
for (const config of group.agents) {
|
|
689
|
+
if (phase1Idle) config.prompt = '';
|
|
665
690
|
try {
|
|
666
691
|
const validated = validateAgentConfig(config);
|
|
667
692
|
if (!validated.teamId) validated.teamId = this.daemon.teams.getDefault()?.id || null;
|
|
@@ -694,6 +719,48 @@ For normal file edits within your scope, proceed without review.
|
|
|
694
719
|
}
|
|
695
720
|
}
|
|
696
721
|
|
|
722
|
+
/**
|
|
723
|
+
* Auto-trigger an idle QC agent in the same team when a teammate completes real work.
|
|
724
|
+
* "Idle" = running fullstack agent that hasn't modified any files yet.
|
|
725
|
+
*/
|
|
726
|
+
_triggerIdleQC(completedAgent) {
|
|
727
|
+
const registry = this.daemon.registry;
|
|
728
|
+
if (!completedAgent.teamId) return;
|
|
729
|
+
|
|
730
|
+
// Find a running fullstack/QC agent in the same team that's idle (no files modified)
|
|
731
|
+
const journalist = this.daemon.journalist;
|
|
732
|
+
const qc = registry.getAll().find((a) =>
|
|
733
|
+
a.id !== completedAgent.id &&
|
|
734
|
+
a.teamId === completedAgent.teamId &&
|
|
735
|
+
a.role === 'fullstack' &&
|
|
736
|
+
a.status === 'running' &&
|
|
737
|
+
(journalist?.getAgentFiles(a) || []).length === 0
|
|
738
|
+
);
|
|
739
|
+
if (!qc) return;
|
|
740
|
+
|
|
741
|
+
// Gather context about what the completed agent did
|
|
742
|
+
const files = this.daemon.journalist?.getAgentFiles(completedAgent) || [];
|
|
743
|
+
const result = this.daemon.journalist?.getAgentResult(completedAgent) || '';
|
|
744
|
+
const fileList = files.length > 0 ? `\nFiles modified: ${files.slice(0, 20).join(', ')}` : '';
|
|
745
|
+
|
|
746
|
+
const message = `Your teammate ${completedAgent.name} (${completedAgent.role}) just finished their work.${fileList}${result ? `\n\nTheir summary:\n${result.slice(0, 2000)}` : ''}\n\nPlease audit their changes: verify correctness, check for bugs, run tests if available, and report any issues.`;
|
|
747
|
+
|
|
748
|
+
// Send message to the QC agent via the instruct flow
|
|
749
|
+
this.sendMessage(qc.id, message).catch((err) => {
|
|
750
|
+
console.error(`[Groove] QC auto-trigger failed: ${err.message}`);
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
this.daemon.audit.log('qc.autoTrigger', {
|
|
754
|
+
qcId: qc.id, qcName: qc.name,
|
|
755
|
+
triggeredBy: completedAgent.name, role: completedAgent.role,
|
|
756
|
+
});
|
|
757
|
+
this.daemon.broadcast({
|
|
758
|
+
type: 'qc:triggered',
|
|
759
|
+
qcId: qc.id, qcName: qc.name,
|
|
760
|
+
triggeredBy: completedAgent.name,
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
|
|
697
764
|
/**
|
|
698
765
|
* Resume a completed agent's session with a new message.
|
|
699
766
|
* Uses --resume SESSION_ID for zero cold-start continuation.
|