From a9a37b2b3f98ae006c79d4ba1d450815b1f4c114 Mon Sep 17 00:00:00 2001 From: Aishanee Shah Date: Fri, 10 Apr 2026 01:33:55 +0000 Subject: [PATCH] fix(watcher): initialize status file and correct turn counting to prevent subagent loops --- packages/core/src/core/client.ts | 19 +++++++++++++++++-- packages/core/src/core/client_watcher.test.ts | 6 +++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/core/src/core/client.ts b/packages/core/src/core/client.ts index 4bccd72818..4edfed3e56 100644 --- a/packages/core/src/core/client.ts +++ b/packages/core/src/core/client.ts @@ -618,8 +618,6 @@ export class GeminiClient { ): AsyncGenerator { let turn = new Turn(this.getChat(), prompt_id); - this.sessionTurnCount++; - const watcherInterval = this.config.getExperimentalWatcherInterval(); if ( this.config.isExperimentalWatcherEnabled() && @@ -928,6 +926,7 @@ export class GeminiClient { ): AsyncGenerator { if (!isInvalidStreamRetry) { this.config.resetTurn(); + this.sessionTurnCount++; } const hooksEnabled = this.config.getEnableHooks(); @@ -1327,6 +1326,22 @@ export class GeminiClient { } const interval = this.config.getExperimentalWatcherInterval(); + + const projectTempDir = this.config.storage.getProjectTempDir(); + const statusFilePath = path.join(projectTempDir, 'watcher_status.md'); + + // Ensure the file exists before the subagent tries to read it + if (!fs.existsSync(statusFilePath)) { + try { + if (!fs.existsSync(projectTempDir)) { + fs.mkdirSync(projectTempDir, { recursive: true }); + } + fs.writeFileSync(statusFilePath, 'EMPTY', 'utf-8'); + } catch (e) { + debugLogger.warn('Failed to initialize watcher status file', e); + } + } + const history = this.getHistory(); // Get last N turns (approx) const recentHistory = history diff --git a/packages/core/src/core/client_watcher.test.ts b/packages/core/src/core/client_watcher.test.ts index 7a546e1604..d22d307925 100644 --- a/packages/core/src/core/client_watcher.test.ts +++ b/packages/core/src/core/client_watcher.test.ts @@ -137,7 +137,7 @@ describe('GeminiClient Watcher Integration', () => { 'gemini-pro', ); - clientAccess.sessionTurnCount = 0; // Will become 1 inside processTurn + clientAccess.sessionTurnCount = 1; const promptId = 'test-prompt'; const signal = new AbortController().signal; @@ -214,7 +214,7 @@ describe('GeminiClient Watcher Integration', () => { 'gemini-pro', ); - clientAccess.sessionTurnCount = 0; // Will become 1 inside processTurn + clientAccess.sessionTurnCount = 1; const promptId = 'test-prompt'; const signal = new AbortController().signal; @@ -323,7 +323,7 @@ describe('GeminiClient Watcher Integration', () => { // Simulate 11 turns for (let i = 1; i <= 11; i++) { - clientAccess.sessionTurnCount = i - 1; // Will become i inside processTurn + clientAccess.sessionTurnCount = i; const generator = clientAccess.processTurn( [{ text: `turn ${i}` }],