groove-dev 0.26.16 → 0.26.17

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.
@@ -368,6 +368,11 @@ 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' && (agent.tokensUsed || 0) > 2000) {
374
+ this._triggerIdleQC(agent);
375
+ }
371
376
  });
372
377
 
373
378
  // Wire errors — broadcast to GUI for display
@@ -561,6 +566,12 @@ For normal file edits within your scope, proceed without review.
561
566
 
562
567
  // Phase 2 auto-spawn: check if all phase 1 agents for a team are done
563
568
  this._checkPhase2(agent.id);
569
+
570
+ // Auto-trigger idle QC: if this agent did real work and there's an idle QC
571
+ // in the same team, activate it to verify the changes
572
+ if (finalStatus === 'completed' && (agent.tokensUsed || 0) > 2000) {
573
+ this._triggerIdleQC(agent);
574
+ }
564
575
  });
565
576
 
566
577
  proc.on('error', (err) => {
@@ -660,8 +671,17 @@ For normal file edits within your scope, proceed without review.
660
671
  // Remove from pending
661
672
  pending.splice(i, 1);
662
673
 
663
- // Auto-spawn phase 2 agents
674
+ // Check if phase 1 agents did any real work.
675
+ // Low token usage means they just introduced themselves and waited.
676
+ const phase1Idle = group.waitFor.every((id) => {
677
+ const a = registry.get(id);
678
+ return !a || (a.tokensUsed || 0) < 2000;
679
+ });
680
+
681
+ // Auto-spawn phase 2 agents — if phase 1 was idle, clear the prompt
682
+ // so QC also waits for instructions instead of auditing nothing
664
683
  for (const config of group.agents) {
684
+ if (phase1Idle) config.prompt = '';
665
685
  try {
666
686
  const validated = validateAgentConfig(config);
667
687
  if (!validated.teamId) validated.teamId = this.daemon.teams.getDefault()?.id || null;
@@ -694,6 +714,47 @@ For normal file edits within your scope, proceed without review.
694
714
  }
695
715
  }
696
716
 
717
+ /**
718
+ * Auto-trigger an idle QC agent in the same team when a teammate completes real work.
719
+ * "Idle" = running with low token usage (just an intro message, awaiting instructions).
720
+ */
721
+ _triggerIdleQC(completedAgent) {
722
+ const registry = this.daemon.registry;
723
+ if (!completedAgent.teamId) return;
724
+
725
+ // Find a running fullstack/QC agent in the same team that's idle
726
+ const qc = registry.getAll().find((a) =>
727
+ a.id !== completedAgent.id &&
728
+ a.teamId === completedAgent.teamId &&
729
+ a.role === 'fullstack' &&
730
+ a.status === 'running' &&
731
+ (a.tokensUsed || 0) < 2000
732
+ );
733
+ if (!qc) return;
734
+
735
+ // Gather context about what the completed agent did
736
+ const files = this.daemon.journalist?.getAgentFiles(completedAgent) || [];
737
+ const result = this.daemon.journalist?.getAgentResult(completedAgent) || '';
738
+ const fileList = files.length > 0 ? `\nFiles modified: ${files.slice(0, 20).join(', ')}` : '';
739
+
740
+ 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.`;
741
+
742
+ // Send message to the QC agent via the instruct flow
743
+ this.sendMessage(qc.id, message).catch((err) => {
744
+ console.error(`[Groove] QC auto-trigger failed: ${err.message}`);
745
+ });
746
+
747
+ this.daemon.audit.log('qc.autoTrigger', {
748
+ qcId: qc.id, qcName: qc.name,
749
+ triggeredBy: completedAgent.name, role: completedAgent.role,
750
+ });
751
+ this.daemon.broadcast({
752
+ type: 'qc:triggered',
753
+ qcId: qc.id, qcName: qc.name,
754
+ triggeredBy: completedAgent.name,
755
+ });
756
+ }
757
+
697
758
  /**
698
759
  * Resume a completed agent's session with a new message.
699
760
  * Uses --resume SESSION_ID for zero cold-start continuation.