From e9040f28fe51eeaf889f381f04b847c5c1050387 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 5 Aug 2026 10:21:16 +0000 Subject: [PATCH] fix: keep every manual activity when the lines arrive together promptUser built a new readline interface per line and closed it after each answer, discarding the lines readline had already buffered from the same stdin chunk. A pasted or piped list recorded only its first entry. Closes #34 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01VApAvCjp7qDWftMrdtnzHt --- src/tools/manual-kpi.test.ts | 9 +++++++++ src/tools/manual-kpi.tool.ts | 28 +++++++++++----------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/tools/manual-kpi.test.ts b/src/tools/manual-kpi.test.ts index af0348c..0cecc40 100644 --- a/src/tools/manual-kpi.test.ts +++ b/src/tools/manual-kpi.test.ts @@ -55,3 +55,12 @@ test('still records an activity that arrived before stdin ended', async () => { test('still treats a blank line as the end of input', async () => { assert.deepEqual(activitiesFrom(await collect('Paired on the auth bug\n\n')), ['Paired on the auth bug']) }) + +// Every line lands in one stdin chunk here, which is what a paste looks like. +test('keeps every activity when the lines arrive together rather than one at a time', async () => { + assert.deepEqual(activitiesFrom(await collect('Reviewed 3 PRs\nRan the release\nMentored a junior\ndone\n')), [ + 'Reviewed 3 PRs', + 'Ran the release', + 'Mentored a junior', + ]) +}) diff --git a/src/tools/manual-kpi.tool.ts b/src/tools/manual-kpi.tool.ts index a392945..3c20921 100644 --- a/src/tools/manual-kpi.tool.ts +++ b/src/tools/manual-kpi.tool.ts @@ -3,20 +3,6 @@ import { z } from 'zod' import * as readline from 'readline' import { logger, prompt } from '../utils/logger.js' -function promptUser(question: string): Promise { - const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) - - return new Promise((resolve) => { - rl.on('close', () => resolve('')) - - rl.question(question, (answer) => { - resolve(answer.trim()) - - rl.close() - }) - }) -} - // Read activities from env var (GitHub Actions) or fall back to interactive readline (local terminal) async function collectActivities(): Promise { const now = new Date().toISOString() @@ -38,15 +24,23 @@ async function collectActivities(): Promise { prompt('📝 (Enter each activity on a new line)') prompt('📝 Type "done" when finished.\n') + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) const activities: string[] = [] - while (true) { - const input = await promptUser(' > ') + rl.setPrompt(' > ') + rl.prompt() + + for await (const line of rl) { + const input = line.trim() if (input.toLowerCase() === 'done' || input === '') break - if (input.length > 0) activities.push(input) + + activities.push(input) + rl.prompt() } + rl.close() + prompt('──────────────────────────────────────────\n') return activities