| name | Questionnaire CLI workflow and context |
| description | Understand how questions are loaded, validated, presented in Ink, and written back out as markdown. |
| metadata | [object Object] |
Context
The questions CLI expects a JSON array of question definitions and uses Ink to walk a human operator through them. Users typically pipe JSON or point the CLI at a file (questions sample_questions.json). The entrypoint normalizes argv, reads the question set, validates each prompt, and boots the Ink app. Inside the TUI, the operator navigates with [/h and ]/l, arrow keys or j/k, and Enter/Space depending on the question type. Yes/no prompts always include a third "Other" row that opens a custom input so operators can supply free-form context without toggling configuration. Answers are cached locally until the final submit screen, where the UI is replaced with the generated markdown; the CLI simultaneously writes the same payload to --output when set (and only logs directly to stdout when running non-interactively). The finalOutput state doubles as the "submitted" flag—once it holds a string, prior screens unmount and the only available action is confirming exit.
Relevant Files
src/cli.tsx– parses CLI flags, loads question JSON from stdin/file, validates structure, and renders the Ink app.src/components/App.tsx– orchestrates per-question state, keyboard handling, navigation, and submission lifecycle.src/components/{SingleSelect,MultiSelect,FreeForm,YesNo}.tsx– renderers for each supported question type, including custom-option UX.src/components/Header.tsx– displays global navigation affordances and current progress counter.src/components/SubmitScreen.tsx– review + submit view that surfaces every answer and triggers finalizing logic on Enter.src/utils/markdown.ts– turns(questions, answers)into the markdown payload written to stdout/file.sample_questions.json– reference dataset demonstrating the JSON schema accepted by the CLI.
Relevant Types
Questionunion (src/types.ts) – guarantees each prompt carriesid,question, and type-specific metadata (options, suggestions).Answer(src/types.ts) – union used across the UI to store the current value for each question id.parseQuestions(input)(src/cli.tsx) – runtime guard that enforces the schema before Ink ever mounts.generateMarkdown(questions, answers)(src/utils/markdown.ts) – shared formatter used by the submit handler to keep stdout and file output in sync.
Workflow
- Input resolution –
src/cli.tsxinspectsprocess.argv, supports-f/--fileand positional file args, falls back to piped stdin, or exits with help if no payload exists. - Question validation – raw input is parsed as JSON; every entry must have
id,question, and a supportedtype, plusoptions/suggestedarrays where required. Failures exit early so the Ink UI never loads bad data. - App initialization –
render(<App ... />)seeds per-question UI state (selection indexes, custom strings, multi-select sets) and trackscurrentStepto know which component to show. - Interactive answering –
useInputinsideAppcentralizes keyboard handling ([/hand]/lto move steps, arrows orj/kto change the highlighted option,Spacefor multi-select toggles, Enter/Space to confirm). Components receive state slices to display cursors, custom text fields, and selection markers. - Saving answers –
saveAnswer()maps current UI state into the canonicalAnswerunion per question id; multi-select answers are arrays, custom entries persist when Enter/Space is pressed, yes/no returns booleans for Yes/No or a custom string when "Other" is confirmed, and skipped questions remainnull. - Submission and output – when the operator advances past the last question,
SubmitScreenshows a summary. Pressing Enter/Space once generates the markdown viagenerateMarkdown, stores it infinalOutput, and swaps the UI to a read-only Markdown view;finalOutput !== nullnow indicates the session is locked and no prior step can be revisited. Any subsequent Enter/Space (or key press) triggers the finalonSubmit/exit path, which writes to--output(or stdout) and terminates the Ink app.
Edge Cases
- No input / unreadable file – CLI errors with guidance if stdin/file is empty or cannot be read.
- Schema violations – missing ids, unsupported types, or absent
optionsarrays throw descriptive errors before entering the interactive flow. - Custom option handling – multi-select custom entries are only stored once the user confirms the typed text; hitting Escape clears the draft.
- Empty selections – multi-select answers serialize as
_none selected_/(none selected)in markdown so downstream readers know it was intentional. - Output failures – disk write errors propagate from
Bun.write; the CLI surfaces them after printing to stdout so callers can retry another path.
Questions to Clarify
- Should the CLI ship with additional built-in templates beyond
sample_questions.json, or fetch remote question sets? - Do we need persistence/resume capabilities so partially answered sessions can be reloaded?
- How should automated pipelines (non-interactive environments) provide answers—should we allow defaults or scripted input?
- Is markdown the only required output, or should alternate formats (JSON/HTML) be supported behind additional flags?