docs(dialogs): specify text input and select composition - #40
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The dialogs spec has a documented TextField.initialValue without corresponding normative behavior, and a new requirement sentence that should be reworded for clarity.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Updates the Dialogs specification and documentation index to define the planned text input dialog and its composition with select via user-provided options, and introduces Change 0017 to track the two-PR implementation plan.
Changes:
- Expanded
docs/specs/dialogs/index.mdto specifyinput, field declarations on select options, composed collection flow, and the newselectresult envelope. - Added
docs/changes/0017-add-dialog-text-input-and-composition.md(draft) describing requirements, design decisions, and task breakdown. - Updated
docs/index.ymlanddocs/index.mdto include Change 0017 and refresh the dialogs spec description.
File summaries
| File | Description |
|---|---|
| docs/specs/dialogs/index.md | Specifies input, field model, user-provided options, composed behavior, and updated cleanup/stream contract. |
| docs/index.yml | Updates dialogs spec description and registers Change 0017 metadata. |
| docs/index.md | Updates dialogs spec description and adds Change 0017 to the changes table. |
| docs/changes/0017-add-dialog-text-input-and-composition.md | New change document defining scope, requirements, design, and tasks for input + composition. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🔵 Needs a closer look
The updated dialogs spec has a few internal ambiguities (notably around user-provided option marking, field initial values, and “printable character” input) that should be clarified to keep the acceptance criteria unambiguous.
Review details
Suppressed comments (3)
Previously missed (2) — in code that hasn't changed since the last review.
docs/specs/dialogs/index.md:5
- The overview says options are "marked as user-provided" but the spec’s contract later defines user-provided options specifically as options that declare fields. Making the mechanism explicit here avoids ambiguity about whether a separate flag/property is required.
`tx` provides a bundled dialogs plugin for terminal interactions shared by its own plugins. The plugin MUST expose dialogs through the generic registry rather than through core vocabulary, and its contract MUST contain only a single-choice `select` dialog and a single-field text `input` dialog, which compose when a select option is marked as user-provided.
docs/specs/dialogs/index.md:148
- The term "printable character" is currently undefined, which makes the acceptance criteria ambiguous (e.g., how to treat multi-codepoint input, Alt-modified keys, or paste events). Tightening the wording here will help ensure consistent implementation and tests.
- Printable character input MUST append to the current value in typed order.
- Backspace MUST remove the last character of the current value and MUST do nothing when the value is empty.
- Input that is none of a printable character, Backspace, Enter, Escape, or Ctrl-C MUST leave the value unchanged.
docs/specs/dialogs/index.md:134
TextFieldincludes an optionalinitialValue, and Change 0017 explicitly calls out an initial value for fields, but the "Field Model" section doesn’t specify howinitialValueaffects collection. Without this, an implementation could ignore field initial values while still satisfying the written bullets.
- A field MUST describe exactly one value the user supplies and MUST carry a type that discriminates it, a name that is unique within the option declaring it, and a message to display while it is collected.
- `text` MUST be the only field type available to callers.
- A field name MUST be an opaque key that identifies the collected value to the caller and MUST NOT be rendered in place of the field's message.
- The fields of an option MUST form an ordered list whose order is the order they are collected in.
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟢 Approval recommended
The changes are documentation-only and appear internally consistent, with indexes updated to include the new change document and no incomplete cross-referenced task completions requiring checkbox updates.
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 0 new
- Review effort level: Lite
Documentation only. No file under
src/,plugins/,test/, orsite/is touched; the behavior described here is planned and implemented by the two PRs enumerated in the change document.What the spec now requires
docs/specs/dialogs/index.mdgrows from aselect-only capability toselectplus a textinputdialog, and the two compose:inputrenders a message and the current value, starts from an optional initial value, appends printable characters, removes the last character on Backspace (a no-op when empty), ignores everything else, and resolves on Enter with the value exactly as entered — including the empty string. Escape and Ctrl-C resolveundefined, so a caller can tell cancellation from an intentional empty value. Whether empty is acceptable is the caller's decision; the dialog does not trim, validate, or transform.selectto any dialog, soinputinherits them rather than restating them.textis the only type available to callers; the type discriminator exists so a later field kind is an addition rather than a redesign.The composition model
An option is marked user-provided by declaring a non-empty ordered list of fields. Choosing it collects those fields one at a time, in declared order, in the same render session — no teardown or re-render between the selection and field stages. After the last field is submitted,
selectresolves.selectnow resolves{ value, values }for every completed selection — the chosen option's exact opaque value, plus a record of collected strings keyed by field name. A plain option carries an empty record; a user-provided option carries exactly the field names it declared, which is how a caller tells them apart. A uniform envelope is used because an opaqueTcannot be safely discriminated against a bare-value/envelope union.undefined, and discards already collected values. There is no return to the option list. Escape keeps one meaning regardless of invisible stage state, Ctrl-C must never mean "go back", and back-navigation would require a stage stack, retained partials, and a re-entry rule with no consumer.Two-PR plan
docs/changes/0017-add-dialog-text-input-and-composition.mddecomposes into exactly two implementation PRs:inputdialog, reusing the existing stream adapters, failure tracking, and render session.selectresult, sequential collection, cancellation, the manual update for composition, and the status flip.Each PR documents in
docs/manual/plugins.mdthe capability it ships, so the manual never describes a surface that does not exist.Deliberate non-goals
CI runs the documentation-only path for this branch, so the quality commands are skipped by design (
docs/specs/architecture/index.md); Biome does not process markdown.