### Install from npm Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md Install the AskUserQuestion tool using npm. ```bash pi install npm:@mazli/pi-ask-user-question ``` -------------------------------- ### Install from GitHub Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md Install the AskUserQuestion tool directly from GitHub. ```bash pi install git:github.com/HamdiMaz/AskUserQuestion ``` -------------------------------- ### Install specific release tag from GitHub Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md Install a specific release tag of the AskUserQuestion tool from GitHub. ```bash pi install git:github.com/HamdiMaz/AskUserQuestion@v1.3.3 ``` -------------------------------- ### Reload pi after installation Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md Reload the pi environment or run a reload command after installing the tool. ```text /reload ``` -------------------------------- ### Install Local Package Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md Install the extension as a local package by providing the absolute path to the extension directory. A restart of 'pi' or a `/reload' command is required afterward. ```bash pi install /absolute/path/to/AskUserQuestion ``` -------------------------------- ### Start Interactive Test Session Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Start the pi interactive testing tool from the package root with the local package enabled. ```bash pi -e . ``` -------------------------------- ### Run without installing (GitHub) Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md Execute the AskUserQuestion tool for a one-off test without installing it from GitHub. ```bash pi -e git:github.com/HamdiMaz/AskUserQuestion ``` -------------------------------- ### Run without installing (npm) Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md Execute the AskUserQuestion tool for a one-off test without installing it via npm. ```bash pi -e npm:@mazli/pi-ask-user-question ``` -------------------------------- ### Example Tool Input for User Questions Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md This JSON structure defines the input for the AskUserQuestion tool, specifying questions, headers, selection modes, and options with descriptions. ```json { "questions": [ { "question": "Which HTTP client should we use?", "header": "HTTP", "multiSelect": false, "options": [ { "label": "fetch (Recommended)", "description": "Built-in and dependency-free." }, { "label": "axios", "description": "Popular ecosystem and interceptor support." }, { "label": "got", "description": "Node-focused with retry support." } ] }, { "question": "Which resilience features do you want?", "header": "Resilience", "multiSelect": true, "options": [ { "label": "Retry", "description": "Retry transient failures." }, { "label": "Timeout", "description": "Apply a per-request timeout cap." }, { "label": "Cache", "description": "Cache responses in memory." } ] } ], "metadata": { "source": "clarify" } } ``` -------------------------------- ### Install Dependencies and Remove Lockfile Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Installs npm packages without generating a `package-lock.json` and then removes any existing lockfile. This ensures local development uses the updated dependencies without committing a lockfile. ```bash npm install --no-package-lock rm -f package-lock.json ``` -------------------------------- ### Merge Release Branch and Verify Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Merge the release branch into the main branch using a fast-forward strategy, install dependencies, clean up lock files, and run verification tests. ```bash cd /home/maz/Projects/AskUserQuestion git pull --ff-only origin main git merge --ff-only release/v1.3.2-new-scope npm install --no-package-lock rm -f package-lock.json npm test npm pack --dry-run git status --short --branch ``` -------------------------------- ### Run Helper Tests Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Executes the tests specifically for the navigation and answer state helper functions using Node.js. This command verifies the correctness of the newly implemented helper functions. ```bash node --test tests/ask-user-question-state.test.ts --test-name-pattern "navigation and answer state helpers" ``` -------------------------------- ### Run Extension Directly Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md To run the extension directly during local development, use this command with the path to your extension's entry point. ```bash pi -e ./extensions/index.ts ``` -------------------------------- ### Run Focused Formatter Tests Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Execute the tests using Node.js to verify that the formatter tests fail as expected before implementation. ```bash node --test tests/ask-user-question-state.test.ts ``` -------------------------------- ### Run Verification Commands Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Execute a series of commands to verify the integrity and correctness of the release. Ensure all tests pass, the package contents are as expected, and no whitespace errors exist. Also, check for specific patterns in relevant files. ```bash npm test npm pack --dry-run git diff --check rg '@mariozechner' package.json extensions/index.ts README.md ``` -------------------------------- ### Verify Working Tree and Fetch Tags Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Check the status of the working tree, fetch tags from the remote, and verify the existence of the specific release tag. ```bash git status --short --branch git fetch --tags origin git ls-remote --tags origin refs/tags/v1.3.2 npm whoami npm view @mazli/pi-ask-user-question version ``` -------------------------------- ### Update Changelog for Navigation Behavior Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Stage the CHANGELOG.md file and commit the documentation updates, reflecting the new navigation behaviors and answered question handling. ```bash git add CHANGELOG.md git commit -m "docs: update changelog for navigation behavior" ``` -------------------------------- ### Tag and Push Release Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Create an annotated tag for the release and push both the main branch and the new tag to the origin remote. ```bash git tag -a v1.3.2 -m "Release v1.3.2" git push origin main git push origin v1.3.2 ``` -------------------------------- ### Implement Formatter Helper and UI Wiring Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Add the `formatOptionLabelLine` helper function and update the `optionLines` function in `extensions/ask-user-question.ts` to use the new formatter. ```typescript type OptionTextStyle = (text: string) => string; export interface OptionLabelLineStyles { accent: OptionTextStyle; text: OptionTextStyle; } export function formatOptionLabelLine(focused: boolean, marker: string, label: string, styles: OptionLabelLineStyles): string { const prefix = focused ? styles.accent("› ") : " "; const markerAndLabel = `${marker} ${label}`; return `${prefix}${focused ? styles.accent(markerAndLabel) : styles.text(markerAndLabel)}`; } ``` ```typescript for (let i = 0; i < options.length; i++) { const option = options[i]; const focused = i === optionIndex; const marker = question.multiSelect ? multiSelection.has(i) ? "[x]" : "[ ]" : focused ? "●" : "○"; lines.push( formatOptionLabelLine(focused, marker, option.label, { accent: (text) => theme.fg("accent", text), text: (text) => theme.fg("text", text), }), ); for (const descriptionLine of wrapTextWithAnsi(option.description, Math.max(1, width - 6))) { lines.push(` ${theme.fg("muted", descriptionLine)}`); } } ``` -------------------------------- ### Update Changelog Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Add a new entry to the Unreleased section of CHANGELOG.md to document the UI change. ```markdown ## Unreleased - Highlight the focused answer marker and label in `AskUserQuestion` dialogs with the accent color. ``` -------------------------------- ### Create GitHub Release Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Create a GitHub release using a temporary file to store changelog notes. This script extracts the relevant changelog section for the specified tag. ```bash notes_file=$(mktemp) python - "v1.3.2" "$notes_file" <<'PY' import sys from pathlib import Path tag = sys.argv[1] output = Path(sys.argv[2]) text = Path("CHANGELOG.md").read_text(encoding="utf-8") section = text.split(f"## {tag}", 1)[1].split("\n## ", 1)[0].strip() output.write_text(section + "\n", encoding="utf-8") PY gh release create v1.3.2 --title "v1.3.2" --notes-file "$notes_file" --verify-tag rm -f "$notes_file" ``` -------------------------------- ### Commit Formatter and UI Wiring Changes Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Stage and commit the modified files that include the new formatter and its UI integration. ```bash git add extensions/ask-user-question.ts tests/ask-user-question-state.test.ts git commit -m "fix: accent focused option labels" ``` -------------------------------- ### Commit Release Documentation Changes Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Stage and commit the updated documentation files for the release. ```bash git add CHANGELOG.md README.md git commit -m "docs: prepare v1.3.2 release" ``` -------------------------------- ### Test Suite for Navigation and Answer State Helpers Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md This block contains various test cases for navigation and multi-select answer state helpers. It covers option wrapping, restoring focus for single and multi-select answers, and updating multi-select answer text. ```typescript describe("AskUserQuestion navigation and answer state helpers", () => { it("wraps option focus at both ends", () => { assert.equal(wrapOptionIndex(2, 1, 3), 0); assert.equal(wrapOptionIndex(0, -1, 3), 2); assert.equal(wrapOptionIndex(1, 1, 3), 2); assert.equal(wrapOptionIndex(1, -1, 3), 0); }); it("restores focus to a selected single-select option", () => { assert.equal( preferredOptionIndexForQuestion({ questionIndex: 0, optionCount: 3, multiSelect: false, selectedSingle: new Map([[0, 1]]), selectedMulti: new Map(), selectedOtherQuestions: new Set(), fallbackIndex: 0, }), 1, ); }); it("restores focus to Other for a custom single-select answer", () => { assert.equal( preferredOptionIndexForQuestion({ questionIndex: 0, optionCount: 3, multiSelect: false, selectedSingle: new Map(), selectedMulti: new Map(), selectedOtherQuestions: new Set([0]), fallbackIndex: 0, }), 2, ); }); it("restores focus to the first selected multi-select option before Other", () => { assert.equal( preferredOptionIndexForQuestion({ questionIndex: 0, optionCount: 4, multiSelect: true, selectedSingle: new Map(), selectedMulti: new Map([[0, new Set([2, 1])]]), selectedOtherQuestions: new Set([0]), fallbackIndex: 0, }), 1, ); }); it("restores focus to Other when it is the only multi-select choice", () => { assert.equal( preferredOptionIndexForQuestion({ questionIndex: 0, optionCount: 4, multiSelect: true, selectedSingle: new Map(), selectedMulti: new Map([[0, new Set()]]), selectedOtherQuestions: new Set([0]), fallbackIndex: 0, }), 3, ); }); it("updates multi-select answer text immediately after Space toggles", () => { const question = { question: "Which layers should we test?", header: "Testing", multiSelect: true, options: [ { label: "Unit", description: "Unit tests." }, { label: "E2E", description: "End-to-end tests." }, ], }; const options = [ ...question.options, { label: "Other...", description: "Type a custom answer.", isOther: true }, ]; const answers: Record = {}; const selection = new Set([1, 0]); updateMultiAnswerRecord(question, 0, selection, options, new Set(), new Map(), answers); assert.equal(answers[question.question], "Unit, E2E"); }); it("includes a custom Other answer in multi-select answer text", () => { const options = [ { label: "Unit", description: "Unit tests." }, { label: "Other...", description: "Type a custom answer.", isOther: true }, ]; assert.equal(multiAnswerTextFromSelection(0, new Set([0]), options, new Set([0]), new Map([[0, "Contract tests"]])), "Unit, Contract tests"); }); it("clears a multi-select answer record when every selected option is deselected", () => { const question = { question: "Which layers should we test?", header: "Testing", multiSelect: true, options: [ { label: "Unit", description: "Unit tests." }, { label: "E2E", description: "End-to-end tests." }, ], }; const answers: Record = { [question.question]: "Unit" }; const options = [ ...question.options, { label: "Other...", description: "Type a custom answer.", isOther: true }, ]; updateMultiAnswerRecord(question, 0, new Set(), options, new Set(), new Map(), answers); assert.equal(Object.hasOwn(answers, question.question), false); }); }); ``` -------------------------------- ### Update Peer Dependencies Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Replaces the deprecated `@mariozechner/*` peer dependencies in `package.json` with their `@earendil-works/*` equivalents. ```json "peerDependencies": { "@earendil-works/pi-coding-agent": "*", "@earendil-works/pi-tui": "*", "typebox": "*" } ``` -------------------------------- ### Run Automated Tests Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Execute the full automated test suite to ensure all tests pass after the UI change. ```bash npm test ``` -------------------------------- ### Verify Publication on npm and GitHub Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Check the published npm package version and peer dependencies, and verify the remote Git references and GitHub release details. ```bash npm view @mazli/pi-ask-user-question@1.3.2 peerDependencies version git ls-remote origin refs/heads/main refs/tags/v1.3.2 'refs/tags/v1.3.2^{}' gh release view v1.3.2 --json tagName,name,url,body ``` -------------------------------- ### Final Verification Commands Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Run the automated tests and check git status to ensure no uncommitted tracked changes remain. ```bash npm test git status --short ``` -------------------------------- ### Tool Name Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md The name of the tool to be used. ```text AskUserQuestion ``` -------------------------------- ### Wrap Up Navigation in Options Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md This code implements wrap-around navigation for general options, allowing users to cycle from the last option to the first using 'up' or 'k'. ```typescript if (matchesKey(data, Key.up) || matchesKey(data, "k")) { optionIndex = wrapOptionIndex(optionIndex, -1, options.length); } ``` -------------------------------- ### Publish npm Package Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Publish the package to the npm registry with public access. ```bash npm publish --access public ``` -------------------------------- ### Stage and Commit Implementation Changes Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Stage the modified TypeScript files and the test file, then commit the implementation with a descriptive message indicating the feature enhancement. ```bash git add extensions/index.ts tests/ask-user-question-state.test.ts git commit -m "feat: improve AskUserQuestion navigation state" ``` -------------------------------- ### Write Failing Formatter Tests Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Append new test cases to `tests/ask-user-question-state.test.ts` to verify the behavior of `formatOptionLabelLine` for focused and unfocused options. ```typescript describe("AskUserQuestion option rendering", () => { const styles = { accent: (text: string) => `${text}`, text: (text: string) => `${text}`, }; it("colors the focused marker and label with the accent style", () => { assert.equal( formatOptionLabelLine(true, "●", "VPN only (Recommended)", styles), "● VPN only (Recommended)", ); }); it("keeps unfocused marker and label in the text style", () => { assert.equal( formatOptionLabelLine(false, "○", "Cloudflare Access", styles), " ○ Cloudflare Access", ); }); }); ``` -------------------------------- ### Run Node Test Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Executes the `package-manifest.test.ts` file using Node's built-in test runner. This is used to verify the test's failure before changes and its success after. ```bash node --test tests/package-manifest.test.ts ``` -------------------------------- ### Commit Changelog Changes Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Stage and commit the modified CHANGELOG.md file with a descriptive message. ```bash git add CHANGELOG.md git commit -m "docs: document focused option highlight" ``` -------------------------------- ### Wrap Up Navigation in Picker Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md This snippet shows how to implement wrap-around navigation for picker options, moving from the last option to the first when 'up' or 'k' is pressed. ```typescript if (matchesKey(data, Key.up) || matchesKey(data, "k")) { submitPickerIndex = wrapOptionIndex(submitPickerIndex, -1, 2); } ``` -------------------------------- ### Pure State Helper Functions Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Provides utility functions for managing option indices and determining preferred answers in a question-answering context. Includes clamping, wrapping indices, and calculating the preferred option based on selection type and history. ```typescript function clampOptionIndex(index: number, optionCount: number): number { if (optionCount <= 0) return 0; return Math.min(optionCount - 1, Math.max(0, index)); } ``` ```typescript export function wrapOptionIndex(currentIndex: number, delta: number, optionCount: number): number { if (optionCount <= 0) return 0; return (((currentIndex + delta) % optionCount) + optionCount) % optionCount; } ``` ```typescript export interface PreferredOptionIndexArgs { questionIndex: number; optionCount: number; multiSelect: boolean; selectedSingle: Map; selectedMulti: Map>; selectedOtherQuestions: Set; fallbackIndex?: number; } ``` ```typescript export function preferredOptionIndexForQuestion({ questionIndex, optionCount, multiSelect, selectedSingle, selectedMulti, selectedOtherQuestions, fallbackIndex = 0, }: PreferredOptionIndexArgs): number { if (optionCount <= 0) return 0; const fallback = clampOptionIndex(fallbackIndex, optionCount); const otherIndex = optionCount - 1; if (multiSelect) { const selection = selectedMulti.get(questionIndex); const firstSelected = selection ? Array.from(selection) .sort((a, b) => a - b) .find((index) => index >= 0 && index < optionCount) : undefined; if (firstSelected !== undefined) return firstSelected; if (selectedOtherQuestions.has(questionIndex)) return otherIndex; return fallback; } const selected = selectedSingle.get(questionIndex); if (selected !== undefined && selected >= 0 && selected < optionCount) return selected; if (selectedOtherQuestions.has(questionIndex)) return otherIndex; return fallback; } ``` -------------------------------- ### Wrap Down Navigation in Picker Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md This snippet demonstrates wrap-around navigation for picker options, moving from the first option to the last when 'down' or 'j' is pressed. ```typescript if (matchesKey(data, Key.down) || matchesKey(data, "j")) { submitPickerIndex = wrapOptionIndex(submitPickerIndex, 1, 2); } ``` -------------------------------- ### Helper Functions for Navigation and Answering Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md These helper functions manage preferred option selection, focus management, and updating multi-select answers. ```typescript function preferredCurrentOptionIndex(fallbackIndex = optionIndex): number { return preferredOptionIndexForQuestion({ questionIndex: currentQuestionIndex(), optionCount: currentOptions().length, multiSelect: currentQuestion().multiSelect, selectedSingle, selectedMulti, selectedOtherQuestions, fallbackIndex, }); } function focusCurrentTab(fallbackIndex = optionIndex) { optionIndex = onSubmitTab() ? 0 : preferredCurrentOptionIndex(fallbackIndex); } function updateCurrentMultiAnswer() { const question = currentQuestion(); const questionIndex = currentQuestionIndex(); updateMultiAnswerRecord(question, questionIndex, currentMultiSelection(), currentOptions(), selectedOtherQuestions, customOtherAnswers, answers); } ``` -------------------------------- ### Earendil Package Peer Dependencies Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/specs/2026-05-09-earendil-package-scope-release-design.md Specifies the peer dependencies for Earendil's pi core packages. Ensure these are set to wildcard ranges as per pi package documentation. ```json { "@earendil-works/pi-coding-agent": "*", "@earendil-works/pi-tui": "*", "typebox": "*" } ``` -------------------------------- ### Update CHANGELOG.md Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Modify the top of the CHANGELOG.md file to reflect the unreleased version and its changes. ```markdown ## Unreleased ## v1.3.2 - Replace deprecated pi peer dependencies and imports with `@earendil-works/*` package names. ``` -------------------------------- ### Multi-Answer Formatting Helper Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Formats the text representation of a multi-select answer. It concatenates the labels of selected options and includes custom 'other' answers if applicable. This function is used to generate the display string for multi-select questions. ```typescript export function multiAnswerTextFromSelection( questionIndex: number, selection: Set, options: DisplayOption[], selectedOtherQuestions: Set, customOtherAnswers: Map, ): string { const labels = Array.from(selection) .sort((a, b) => a - b) .map((index) => options[index]) .filter((option): option is DisplayOption => option !== undefined && option.isOther !== true) .map((option) => option.label); if (selectedOtherQuestions.has(questionIndex)) { const customAnswer = customOtherAnswers.get(questionIndex); if (customAnswer !== undefined) labels.push(customAnswer); } return labels.join(", "); } ``` -------------------------------- ### Wrap Down Navigation in Options Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md This code handles wrap-around navigation for options, enabling users to move from the first option to the last using 'down' or 'j'. ```typescript if (matchesKey(data, Key.down) || matchesKey(data, "j")) { optionIndex = wrapOptionIndex(optionIndex, 1, options.length); } ``` -------------------------------- ### Update Package Version Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Changes the `version` field in `package.json` from `1.3.1` to `1.3.2` to reflect the new release. ```json "version": "1.3.2" ``` -------------------------------- ### Update Imports in Test File Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-07-focused-option-accent.md Update the import statement in the test file to include the new `formatOptionLabelLine` function. ```typescript import { answerDisplayText, formatOptionLabelLine, hasSubmitTab, isSubmitTab, missingQuestionHeaders, nextQuestionOrSubmitTab, submitTabIndex, validateParams, } from "../extensions/ask-user-question.ts"; ``` -------------------------------- ### Extend Helper Imports in Test File Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Update the import statement in the test file to include new helper functions. This is a prerequisite for testing the new navigation and multi-select answer logic. ```typescript import askUserQuestion, answerDisplayText, formatOptionDescriptionText, formatOptionLabelLine, hasSubmitTab, isSubmitTab, missingQuestionHeaders, multiAnswerTextFromSelection, nextQuestionOrSubmitTab, optionMarker, preferredOptionIndexForQuestion, promptGuidance, promptSnippet, submitTabIndex, updateMultiAnswerRecord, validateParams, wrapInlineItems, wrapOptionIndex, } from "../extensions/index.ts"; ``` -------------------------------- ### Update Extension Imports Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Modifies the import statements in `extensions/index.ts` to use the new `@earendil-works/*` package scope for `pi-coding-agent` and `pi-tui`. ```typescript import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { Editor, type EditorTheme, Key, matchesKey, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui"; ``` -------------------------------- ### Stage and Commit Scope Fix Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Stages the modified `package.json`, `extensions/index.ts`, and `tests/package-manifest.test.ts` files and commits them with a descriptive message indicating the scope fix. ```bash git add package.json extensions/index.ts tests/package-manifest.test.ts git commit -m "fix: use current pi package scope" ``` -------------------------------- ### Immediate Multi-Select Answer Updates for Custom Other Input Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Ensures that multi-select answers are updated immediately when the input mode is 'other'. ```typescript if (question.multiSelect) { updateCurrentMultiAnswer(); } else { selectedSingle.set(questionIndex, options.length - 1); answers[question.question] = text; } ``` -------------------------------- ### Cancelled or dismissed result format Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md The expected JSON structure when the user cancels or dismisses the dialog. ```json { "cancelled": true } ``` -------------------------------- ### Export DisplayOption Type Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Exports the `DisplayOption` type for use in other modules. This type extends `AskUserQuestionOption` and includes an optional `isOther` boolean. ```typescript export type DisplayOption = AskUserQuestionOption & { isOther?: boolean }; ``` -------------------------------- ### Normal result format Source: https://github.com/hamdimaz/askuserquestion/blob/main/README.md The expected JSON structure for a normal, non-cancelled result from AskUserQuestion. ```json { "cancelled": false, "answers": { "Which HTTP client should we use?": "fetch (Recommended)", "Which resilience features do you want?": "Retry, Timeout" } } ``` -------------------------------- ### Restore Focus on Tab Navigation Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Replaces the optionIndex reset with a call to focusCurrentTab for restoring focus during tab navigation. ```typescript if (matchesKey(data, Key.tab) || matchesKey(data, Key.right)) { currentTabIndex = (currentTabIndex + 1) % totalTabs; focusCurrentTab(); submitPickerIndex = 0; statusMessage = ""; refresh(); return; } ``` ```typescript if (matchesKey(data, Key.shift("tab")) || matchesKey(data, Key.left)) { currentTabIndex = (currentTabIndex - 1 + totalTabs) % totalTabs; focusCurrentTab(); submitPickerIndex = 0; statusMessage = ""; refresh(); return; } ``` -------------------------------- ### Replace Local Multi-Answer Formatter Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Replaces the existing local `multiAnswerText` function within the `execute` function with a version that utilizes the globally defined `multiAnswerTextFromSelection` helper. ```typescript function multiAnswerText(questionIndex: number, selection: Set, options: DisplayOption[]): string { return multiAnswerTextFromSelection(questionIndex, selection, options, selectedOtherQuestions, customOtherAnswers); } ``` -------------------------------- ### Preserve Focus in moveToNextQuestionOrReview Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Replaces the hardcoded optionIndex reset with a call to focusCurrentTab to preserve user focus. ```typescript currentTabIndex = next === "submit" ? reviewTabIndex : next; focusCurrentTab(0); submitPickerIndex = 0; ``` -------------------------------- ### Update Multi-Answer Record Helper Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Updates the answers record with the formatted multi-answer text. If there is no selection or 'other' question selected, the answer for the question is removed from the record. ```typescript export function updateMultiAnswerRecord( question: AskUserQuestionQuestion, questionIndex: number, selection: Set, options: DisplayOption[], selectedOtherQuestions: Set, customOtherAnswers: Map, answers: Record, ): void { const hasSelection = selection.size > 0 || selectedOtherQuestions.has(questionIndex); if (!hasSelection) { delete answers[question.question]; return; } answers[question.question] = multiAnswerTextFromSelection(questionIndex, selection, options, selectedOtherQuestions, customOtherAnswers); } ``` -------------------------------- ### Update Multi-Select Answer on Toggle Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Calls updateCurrentMultiAnswer after changing the selection in a multi-select question. ```typescript function toggleFocusedMultiOption() { const question = currentQuestion(); const options = currentOptions(); const option = options[optionIndex]; if (!option) return; if (option.isOther) { startInput("other"); return; } const selection = currentMultiSelection(); if (selection.has(optionIndex)) { selection.delete(optionIndex); } else { selection.add(optionIndex); } updateCurrentMultiAnswer(); emptySelectionWarnings.delete(currentQuestionIndex()); statusMessage = question.multiSelect && Object.hasOwn(answers, question.question) ? "Answer updated." : ""; refresh(); } ``` -------------------------------- ### Add Deprecated Scope Regression Test Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-09-earendil-package-scope-release.md Appends a test to `tests/package-manifest.test.ts` to verify that deprecated `@mariozechner/*` package references are not present in `package.json` or `extensions/index.ts`, and that the new `@earendil-works/*` references are used. ```typescript it("uses current @earendil-works pi package names", () => { const packageJsonText = readFileSync(packageJsonUrl, "utf8"); const packageJson = JSON.parse(packageJsonText) as { peerDependencies?: Record; }; const extensionSource = readFileSync(new URL("extensions/index.ts", packageRootUrl), "utf8"); assert.equal(packageJson.peerDependencies?.["@earendil-works/pi-coding-agent"], "*"); assert.equal(packageJson.peerDependencies?.["@earendil-works/pi-tui"], "*"); assert.equal(packageJson.peerDependencies?.["@mariozechner/pi-coding-agent"], undefined); assert.equal(packageJson.peerDependencies?.["@mariozechner/pi-tui"], undefined); assert.doesNotMatch(packageJsonText, /@mariozechner\//); assert.doesNotMatch(extensionSource, /@mariozechner\//); assert.match(extensionSource, /@earendil-works\/pi-coding-agent/); assert.match(extensionSource, /@earendil-works\/pi-tui/); }); ``` -------------------------------- ### Conditional Multi-Select Answer Update in saveMultiAnswer Source: https://github.com/hamdimaz/askuserquestion/blob/main/docs/superpowers/plans/2026-05-18-navigation-and-multiselect-answering.md Updates the multi-select answer only if there is a selection, otherwise clears it. ```typescript if (hasSelection) { updateCurrentMultiAnswer(); } else { answers[question.question] = ""; } moveToNextQuestionOrReview(); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.