fix: イテレーション入力待ち中のpoll_tickログ連続出力を抑制

入力待ちフラグ(enterInputWait/leaveInputWait)を導入し、
selectOption待ち中はワーカープールのポーリングログをスキップする。
入力完了で自動復活。
This commit is contained in:
nrslib 2026-02-20 23:42:38 +09:00
parent 4823a9cb83
commit 75ce583d0b
3 changed files with 53 additions and 22 deletions

View File

@ -0,0 +1,24 @@
/**
* Shared input-wait state for worker pool log suppression.
*
* When a task is waiting for user input (e.g. iteration limit prompt),
* the worker pool should suppress poll_tick debug logs to avoid
* flooding the log file with identical entries.
*/
let waitCount = 0;
/** Call when entering an input-wait state (e.g. selectOption). */
export function enterInputWait(): void {
waitCount++;
}
/** Call when leaving an input-wait state. */
export function leaveInputWait(): void {
if (waitCount > 0) waitCount--;
}
/** Returns true if any task is currently waiting for user input. */
export function isInputWaiting(): boolean {
return waitCount > 0;
}

View File

@ -18,6 +18,7 @@ import { EXIT_SIGINT } from '../../../shared/exitCodes.js';
import { createLogger } from '../../../shared/utils/index.js';
import { executeAndCompleteTask } from './taskExecution.js';
import { ShutdownManager } from './shutdownManager.js';
import { isInputWaiting } from './inputWait.js';
import type { TaskExecutionOptions } from './types.js';
const log = createLogger('worker-pool');
@ -169,7 +170,7 @@ export async function runWithWorkerPool(
}
}
if (!abortController.signal.aborted) {
if (!abortController.signal.aborted && !isInputWaiting()) {
const freeSlots = concurrency - active.size;
if (freeSlots > 0) {
const newTasks = taskRunner.claimNextTasks(freeSlots);

View File

@ -10,6 +10,7 @@ import type { PieceExecutionResult, PieceExecutionOptions } from './types.js';
import { detectRuleIndex } from '../../../shared/utils/ruleIndex.js';
import { interruptAllQueries } from '../../../infra/claude/query-manager.js';
import { callAiJudge } from '../../../agents/ai-judge.js';
import { enterInputWait, leaveInputWait } from './inputWait.js';
export type { PieceExecutionResult, PieceExecutionOptions };
@ -398,32 +399,37 @@ export async function executePiece(
playWarningSound();
}
const action = await selectOption(getLabel('piece.iterationLimit.continueQuestion'), [
{
label: getLabel('piece.iterationLimit.continueLabel'),
value: 'continue',
description: getLabel('piece.iterationLimit.continueDescription'),
},
{ label: getLabel('piece.iterationLimit.stopLabel'), value: 'stop' },
]);
enterInputWait();
try {
const action = await selectOption(getLabel('piece.iterationLimit.continueQuestion'), [
{
label: getLabel('piece.iterationLimit.continueLabel'),
value: 'continue',
description: getLabel('piece.iterationLimit.continueDescription'),
},
{ label: getLabel('piece.iterationLimit.stopLabel'), value: 'stop' },
]);
if (action !== 'continue') {
return null;
}
while (true) {
const input = await promptInput(getLabel('piece.iterationLimit.inputPrompt'));
if (!input) {
if (action !== 'continue') {
return null;
}
const additionalIterations = Number.parseInt(input, 10);
if (Number.isInteger(additionalIterations) && additionalIterations > 0) {
pieceConfig.maxMovements = request.maxMovements + additionalIterations;
return additionalIterations;
}
while (true) {
const input = await promptInput(getLabel('piece.iterationLimit.inputPrompt'));
if (!input) {
return null;
}
out.warn(getLabel('piece.iterationLimit.invalidInput'));
const additionalIterations = Number.parseInt(input, 10);
if (Number.isInteger(additionalIterations) && additionalIterations > 0) {
pieceConfig.maxMovements = request.maxMovements + additionalIterations;
return additionalIterations;
}
out.warn(getLabel('piece.iterationLimit.invalidInput'));
}
} finally {
leaveInputWait();
}
};