From 02d95d76ce8d65182a84cbae721ea3bec89331b2 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Mon, 22 Jun 2026 19:29:18 +0200 Subject: [PATCH 1/2] fix: bump question tool max options from 4 to 10 --- .pi/extensions/ocgs-question/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pi/extensions/ocgs-question/index.ts b/.pi/extensions/ocgs-question/index.ts index 2e4e7d1..a994d00 100644 --- a/.pi/extensions/ocgs-question/index.ts +++ b/.pi/extensions/ocgs-question/index.ts @@ -66,7 +66,7 @@ const OptionSchema = Type.Object({ const QuestionParams = Type.Object({ question: Type.String({ description: "The question to ask the user" }), - options: Type.Array(OptionSchema, { minItems: 2, maxItems: 4 }), + options: Type.Array(OptionSchema, { minItems: 2, maxItems: 10 }), header: Type.Optional( Type.String({ description: "Optional short header (e.g. 'CD-PILLARS')" }), ), From 1e3517617cb6b723916cfca152e275604b512986 Mon Sep 17 00:00:00 2001 From: Jaco du Preez Date: Mon, 22 Jun 2026 20:15:14 +0200 Subject: [PATCH 2/2] fix(question): address PR #69 review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix stale promptGuidelines: '2-4 options' → '2-10 options' - Add scrollable option window (VISIBLE_OPTIONS=6) with '↑ more'/'↓ more' - Add number-key shortcuts: 1-9 selects option, 0 selects 'Type something.' - Pad option numbers so double-digit '10.' keeps indentation aligned - Update footer hint to show the new shortcuts --- .pi/extensions/ocgs-question/index.ts | 58 +++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/.pi/extensions/ocgs-question/index.ts b/.pi/extensions/ocgs-question/index.ts index a994d00..f6ac91d 100644 --- a/.pi/extensions/ocgs-question/index.ts +++ b/.pi/extensions/ocgs-question/index.ts @@ -83,7 +83,7 @@ export default function (pi: ExtensionAPI) { promptSnippet: "Present a strategic decision with options and capture the user's choice", promptGuidelines: [ - "Use the question tool when you need the user to make a strategic choice between 2-4 options.", + "Use the question tool when you need the user to make a strategic choice between 2-10 options.", "ALWAYS write your full reasoning in conversation text BEFORE calling the question tool — explain the trade-offs, your recommendation, and why.", "Add '(Recommended)' to your preferred option's label.", "Labels: 1-5 words. Descriptions: 1 sentence with the key trade-off.", @@ -135,6 +135,8 @@ export default function (pi: ExtensionAPI) { index?: number; } | null>((tui, theme, _kb, done) => { let optionIndex = 0; + let scrollOffset = 0; + const VISIBLE_OPTIONS = 6; let editMode = false; let cachedLines: string[] | undefined; @@ -182,11 +184,14 @@ export default function (pi: ExtensionAPI) { if (matchesKey(data, Key.up)) { optionIndex = Math.max(0, optionIndex - 1); + if (optionIndex < scrollOffset) scrollOffset = optionIndex; refresh(); return; } if (matchesKey(data, Key.down)) { optionIndex = Math.min(allOptions.length - 1, optionIndex + 1); + if (optionIndex >= scrollOffset + VISIBLE_OPTIONS) + scrollOffset = optionIndex - VISIBLE_OPTIONS + 1; refresh(); return; } @@ -206,6 +211,26 @@ export default function (pi: ExtensionAPI) { return; } + // Number shortcuts: 1-9 for options 1-9, 0 for option 10 + const digit = /^[0-9]$/.test(data) ? parseInt(data, 10) : -1; + if (digit >= 0) { + const target = digit === 0 ? 9 : digit - 1; + if (target < allOptions.length) { + const selected = allOptions[target]; + if (selected.isOther) { + optionIndex = target; + editMode = true; + } else { + done({ + answer: selected.label, + wasCustom: false, + index: target + 1, + }); + } + return; + } + } + if (matchesKey(data, Key.escape)) { done(null); } @@ -249,13 +274,28 @@ export default function (pi: ExtensionAPI) { addWrappedWithPrefix(" ", theme.fg("text", params.question)); lines.push(""); - // Options - for (let i = 0; i < allOptions.length; i++) { - const opt = allOptions[i]; - const selected = i === optionIndex; + // Options (scrollable window) + const numPad = String(allOptions.length).length; + const visible = allOptions.slice( + scrollOffset, + scrollOffset + VISIBLE_OPTIONS, + ); + const hasMoreAbove = scrollOffset > 0; + const hasMoreBelow = + scrollOffset + VISIBLE_OPTIONS < allOptions.length; + + if (hasMoreAbove) { + addWrappedWithPrefix(" ", theme.fg("dim", "↑ more")); + } + + for (let i = 0; i < visible.length; i++) { + const realIndex = scrollOffset + i; + const opt = allOptions[realIndex]; + const selected = realIndex === optionIndex; const isOther = opt.isOther === true; const prefix = selected ? theme.fg("accent", "> ") : " "; - const label = `${i + 1}. ${opt.label}${isOther && editMode ? " ✎" : ""}`; + const numStr = String(realIndex + 1).padStart(numPad); + const label = `${numStr}. ${opt.label}${isOther && editMode ? " ✎" : ""}`; const color = selected || (isOther && editMode) ? "accent" : "text"; addWrappedWithPrefix(prefix, theme.fg(color, label)); @@ -266,6 +306,10 @@ export default function (pi: ExtensionAPI) { } } + if (hasMoreBelow) { + addWrappedWithPrefix(" ", theme.fg("dim", "↓ more")); + } + // Edit mode: inline text editor if (editMode) { lines.push(""); @@ -285,7 +329,7 @@ export default function (pi: ExtensionAPI) { } else { addWrappedWithPrefix( " ", - theme.fg("dim", "↑↓ navigate • Enter to select • Esc to cancel"), + theme.fg("dim", "↑↓ navigate • 1-9 choose • 0=Other • Enter to select • Esc to cancel"), ); } lines.push(theme.fg("accent", "─".repeat(renderWidth)));