diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 34f0103c..5e266ad6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,9 @@ on: pull_request: types: - ready_for_review + - reopened + - synchronize + workflow_dispatch: jobs: validate: diff --git a/.gitignore b/.gitignore index 584c0313..59fd5465 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,14 @@ node_modules/ .turbo/ +**/.turbo/ +.cache/ +**/.cache/ +provision/.cache/ .DS_Store coverage/ *.tsbuildinfo -packages/artefacts/.cache/ packages/artefacts/.logs/ packages/artefacts/dist/ packages/tui/dist/ +packages/docs/src/.vitepress/ +packages/docs/src/api/ diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..94c622a1 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +store-dir=provision/.cache/pnpm/store diff --git a/Makefile b/Makefile index 556706e9..87959dc6 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ FMT_RUN := docker run --rm \ -e HOST_PROJECT_PATH=$(ROOT_PATH) \ $(FMT_IMAGE) -TS_GLOBS := '*.ts' '*.tsx' '*.mts' '*.cts' +TS_GLOBS := '*.ts' '*.tsx' '*.vue' '*.mts' '*.cts' .DEFAULT_GOAL := help @@ -18,10 +18,14 @@ define step endef define run_oxfmt -@cd "$(ROOT_PATH)" && tmp=$$(mktemp); git ls-files -z $(1) --exclude-standard -- $(TS_GLOBS) | while IFS= read -r -d '' f; do [ -f "$$f" ] && printf '%s\0' "$$f"; done > "$$tmp"; if [ ! -s "$$tmp" ]; then echo "No TS files to format."; rm -f "$$tmp"; else xargs -0 $(FMT_RUN) format < "$$tmp"; rc=$$?; rm -f "$$tmp"; exit $$rc; fi +@cd "$(ROOT_PATH)" && tmp=$$(mktemp); git ls-files -z $(1) --exclude-standard -- $(TS_GLOBS) | while IFS= read -r -d '' f; do [ -f "$$f" ] && printf '%s\0' "$$f"; done > "$$tmp"; if [ ! -s "$$tmp" ]; then echo "No TS/Vue files to format."; rm -f "$$tmp"; else xargs -0 $(FMT_RUN) format < "$$tmp"; rc=$$?; rm -f "$$tmp"; exit $$rc; fi endef -.PHONY: help format format-all fresh +define run_in + @cd "$(1)" && $(2) +endef + +.PHONY: help dev format format-all fresh help: @awk 'BEGIN {FS = ":.*?## "; printf "\nUsage: \033[36mmake \033[0m\n"} \ @@ -29,21 +33,38 @@ help: /^[a-zA-Z0-9_.-]+:.*?##/ { printf " \033[36m%-28s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) @echo "" +##@ Development +dev: ## Run the docs dev server + $(call run_in,$(ROOT_PATH),pnpm --filter docs dev) + ##@ Formatting -format: ## Format untracked + modified TS files via oxfmt/oxlint +format: ## Format + lint untracked + modified TS/Vue files via oxfmt/oxlint $(call run_oxfmt,--others --modified) -format-all: ## Format every non-ignored TS file in the repo via oxfmt/oxlint - @cd "$(ROOT_PATH)" && tmp=$$(mktemp); git ls-files -z --cached --others --exclude-standard -- $(TS_GLOBS) | while IFS= read -r -d '' f; do [ -f "$$f" ] && printf '%s\0' "$$f"; done > "$$tmp"; if [ ! -s "$$tmp" ]; then echo "No TS files to format."; rm -f "$$tmp"; else xargs -0 $(FMT_RUN) format < "$$tmp"; rc=$$?; rm -f "$$tmp"; exit $$rc; fi +format-all: ## Format + lint every non-ignored TS/Vue file in the repo via oxfmt/oxlint + @cd "$(ROOT_PATH)" && tmp=$$(mktemp); git ls-files -z --cached --others --exclude-standard -- $(TS_GLOBS) | while IFS= read -r -d '' f; do [ -f "$$f" ] && printf '%s\0' "$$f"; done > "$$tmp"; if [ ! -s "$$tmp" ]; then echo "No TS/Vue files to format."; rm -f "$$tmp"; else xargs -0 $(FMT_RUN) format < "$$tmp"; rc=$$?; rm -f "$$tmp"; exit $$rc; fi ##@ Maintenance -fresh: ## Clean generated state, reinstall dependencies, then run local gates +fresh: ## Clean generated state, reinstall dependencies, then build $(call step,Removing generated dependency/cache/build state) @test -n "$(ROOT_PATH)" && test "$(ROOT_PATH)" != "/" || { echo "Refusing to clean unsafe ROOT_PATH='$(ROOT_PATH)'"; exit 1; } - rm -rf "$(ROOT_PATH)/node_modules" "$(ROOT_PATH)"/packages/*/node_modules "$(ROOT_PATH)/.turbo" "$(ROOT_PATH)/packages/artefacts/.cache" "$(ROOT_PATH)/packages/artefacts/.logs" "$(ROOT_PATH)/packages/artefacts/dist" "$(ROOT_PATH)/packages/tui/dist" + rm -rf \ + "$(ROOT_PATH)/node_modules" \ + "$(ROOT_PATH)"/packages/*/node_modules \ + "$(ROOT_PATH)"/provision/*/node_modules \ + "$(ROOT_PATH)/provision/.cache" \ + "$(ROOT_PATH)/packages/artefacts/.logs" \ + "$(ROOT_PATH)/packages/artefacts/dist" \ + "$(ROOT_PATH)/packages/docs/src/.vitepress/cache" \ + "$(ROOT_PATH)/packages/docs/src/.vitepress/dist" \ + "$(ROOT_PATH)/packages/docs/src/api" \ + "$(ROOT_PATH)/packages/tui/dist" + $(call step,Removing generated workspace caches) + find "$(ROOT_PATH)" -path "$(ROOT_PATH)/.git" -prune -o -type d -name '.turbo' -prune -exec rm -rf {} + + find "$(ROOT_PATH)" -path "$(ROOT_PATH)/.git" -prune -o -path "$(ROOT_PATH)/provision/.cache" -prune -o -type d -name '.cache' -prune -exec rm -rf {} + $(call step,Removing TypeScript build info files) find "$(ROOT_PATH)" -name '*.tsbuildinfo' -type f -delete $(call step,Installing dependencies) - cd "$(ROOT_PATH)" && pnpm install - $(call step,Running local gates) - cd "$(ROOT_PATH)" && pnpm build && pnpm typecheck && pnpm test + $(call run_in,$(ROOT_PATH),pnpm install) + $(call step,Building from scratch) + $(call run_in,$(ROOT_PATH),pnpm build) diff --git a/README.md b/README.md index 9b55ab51..5e0fa2ae 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,16 @@ This repository targets behavioral parity with reference prompt toolkit release ## Status -The port is being delivered phase by phase on one draft PR. Current code includes -working key-driven text and choice prompts, output helpers, terminal utilities, -OpenTUI adapter wiring, and local parity tests. Full reference feature-test parity -is tracked in `UPSTREAM.md`. +The current codebase is a TypeScript ESM package with the public `@ollin/tui` +entrypoint exporting prompts, form composition, output helpers, status +indicators, terminal utilities, OpenTUI adapter wiring, and deterministic prompt +environment helpers. + +Local test suites cover prompt behavior, form flows, output and status helpers, +terminal and string utilities, key handling, typed-value editing, and package +consumption through `packages/acceptance`. The docs package builds a VitePress +guide plus generated API reference. Reference parity and the completion audit are +tracked in `UPSTREAM.md`. ## Development diff --git a/UPSTREAM.md b/UPSTREAM.md index 450495e7..bf3e2130 100644 --- a/UPSTREAM.md +++ b/UPSTREAM.md @@ -13,154 +13,222 @@ TypeScript and OpenTUI internals. | --- | --- | | Helper functions | `packages/tui/src/index.ts` | | Prompt lifecycle and fallback behavior | `packages/tui/src/prompt.ts`, `packages/tui/src/environment.ts`, `packages/tui/src/environment/*` | -| Prompt cancellation callback lifecycle | `packages/tui/src/prompt/cancel.ts`, `packages/tui/tests/prompt.test.ts` | +| Prompt fallback reset, predicate condition validation, scoped lifecycle, and predicate condition lifecycle | `packages/tui/src/prompt/fallback.ts`, `packages/tui/src/prompt/validators/fallback.ts`, `packages/tui/src/environment/scope.ts`, `packages/tui/src/prompt.ts`, `packages/tui/src/index.ts` | +| Prompt cancellation callback scoped lifecycle | `packages/tui/src/prompt/cancel.ts`, `packages/tui/src/environment/scope.ts`, `packages/tui/tests/prompt.test.ts` | | Prompt revert rejection lifecycle | `packages/tui/src/prompt/revert.ts`, `packages/tui/src/form/builder/revert.ts`, `packages/tui/src/prompts/select/read-confirm.ts`, `packages/tui/tests/form.test.ts` | -| Prompt validation retry default lifecycle | `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/tests/text.test.ts` | -| Prompt post-validation submitted-frame lifecycle | `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/prompts/text.ts`, `packages/tui/src/prompts/number.ts`, `packages/tui/tests/text.test.ts`, `packages/tui/tests/number.test.ts` | -| Prompt non-interactive transform lifecycle before validation | `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/tests/text.test.ts`, `packages/tui/tests/number.test.ts`, `packages/tui/tests/choices.test.ts`, `packages/tui/tests/search.test.ts` | +| Prompt validation retry default lifecycle and parser-error submitted-value preservation | `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/prompt/lifecycle/*`, `packages/tui/src/prompt/error.ts`, `packages/tui/tests/text.test.ts` | +| Prompt post-validation submitted-frame lifecycle | `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/prompt/lifecycle/*`, `packages/tui/src/prompts/text.ts`, `packages/tui/src/prompts/text/*`, `packages/tui/src/prompts/number.ts`, `packages/tui/tests/text.test.ts`, `packages/tui/tests/number.test.ts` | +| Prompt invalid-attempt active-frame cleanup lifecycle | `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/prompt/lifecycle/*`, `packages/tui/src/prompt/active-frame.ts`, `packages/tui/src/prompts/*`, `packages/tui/src/output/data-table.ts` | +| Prompt non-interactive raw-default validation lifecycle | `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/prompt/lifecycle/*` | | Prompt validation error styling | `packages/tui/src/theme.ts`, `packages/tui/tests/prompt.test.ts` | -| Key constants and event mapping | `packages/tui/src/key.ts`, `packages/tui/src/key/*` | +| Prompt validation warning line styling | `packages/tui/src/theme.ts`, `packages/tui/src/prompt/lifecycle.ts` | +| Prompt local and scoped global validation composition | `packages/tui/src/prompt/validation.ts`, `packages/tui/src/prompt/validate-using.ts`, `packages/tui/src/environment/scope.ts` | +| Key constants, value validation, and event mapping | `packages/tui/src/key.ts`, `packages/tui/src/key/*` | | Terminal helpers | `packages/tui/src/terminal.ts` | | Text input | `packages/tui/src/prompts/text.ts`, `packages/tui/src/typed-value.ts` | -| Text input defaults, transforms, validation, editing keys, non-interactive behavior, and failed reads | `packages/tui/src/prompts/text.ts`, `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/typed-value.ts`, `packages/tui/tests/text.test.ts` | -| Text active, submitted, cancelled, placeholder, and validation-safe rendering | `packages/tui/src/prompts/text.ts`, `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/render.ts`, `packages/tui/tests/text.test.ts` | +| Text input defaults, transforms, validation, editing keys, non-interactive behavior, and failed reads | `packages/tui/src/prompts/text.ts`, `packages/tui/src/prompts/text/*`, `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/read/*`, `packages/tui/tests/text.test.ts` | +| Text active, submitted, cancelled, placeholder, and validation-safe rendering | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/text.ts`, `packages/tui/src/prompts/text/*`, `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/read/*`, `packages/tui/src/typed-value/render.ts`, `packages/tui/tests/text.test.ts` | +| Text active-frame redraw and submitted-frame replacement | `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/render.ts`, `packages/tui/src/prompts/text.ts`, `packages/tui/src/prompts/text/*` | +| Text transformed fallback value, invalid retry default preservation, overload validation, and plain placeholder rendering | `packages/tui/src/prompts/text.ts`, `packages/tui/src/prompts/text/*`, `packages/tui/src/prompts/text-default.ts`, `packages/tui/src/concerns/validators/text-options.ts`, `packages/tui/src/typed-value/render.ts` | | Textarea input | `packages/tui/src/prompts/textarea.ts`, `packages/tui/src/typed-value.ts` | -| Textarea defaults, transforms, validation, editing keys, line navigation, and non-interactive behavior | `packages/tui/src/prompts/textarea.ts`, `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/typed-value.ts`, `packages/tui/tests/textarea.test.ts` | -| Textarea active, submitted, cancelled, scrollbar, placeholder, and validation-safe rendering | `packages/tui/src/prompts/textarea.ts`, `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/tests/textarea.test.ts` | +| Textarea defaults, transforms, validation, editing keys, line navigation, and non-interactive behavior | `packages/tui/src/prompts/textarea.ts`, `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/read/*`, `packages/tui/tests/textarea.test.ts` | +| Textarea active, submitted, cancelled, scrollbar, placeholder, and validation-safe rendering | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/textarea.ts`, `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/read/*`, `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/tests/textarea.test.ts` | +| Textarea active-frame redraw and cursor-aware visible window rendering | `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/lines.ts`, `packages/tui/src/typed-value/lines/*`, `packages/tui/src/typed-value/line-ranges.ts`, `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/src/prompts/textarea.ts` | +| Textarea transformed fallback value, invalid retry default preservation, overload validation, and plain placeholder rendering | `packages/tui/src/prompts/textarea.ts`, `packages/tui/src/prompts/text-default.ts`, `packages/tui/src/concerns/validators/text-options.ts`, `packages/tui/src/typed-value/textarea-frame.ts` | | Textarea control-key line navigation and empty-line movement | `packages/tui/src/typed-value/edit/navigation.ts`, `packages/tui/tests/textarea.test.ts` | | Textarea boxed renderer and placeholder styling | `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/tests/textarea.test.ts` | -| Textarea scrollbar rendering | `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/src/typed-value/lines.ts`, `packages/tui/tests/textarea.test.ts` | -| Textarea wrapped frame line windows | `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/src/typed-value/lines.ts`, `packages/tui/tests/textarea.test.ts`, `packages/tui/tests/typed-value.test.ts` | -| Textarea wrapped-line cursor navigation | `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/edit.ts`, `packages/tui/src/typed-value/edit/navigation.ts`, `packages/tui/src/typed-value/lines.ts`, `packages/tui/tests/textarea.test.ts`, `packages/tui/tests/typed-value.test.ts` | +| Textarea scrollbar rendering | `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/src/typed-value/lines.ts`, `packages/tui/src/typed-value/lines/*`, `packages/tui/src/typed-value/line-ranges.ts`, `packages/tui/tests/textarea.test.ts` | +| Textarea wrapped frame line windows | `packages/tui/src/typed-value/textarea-frame.ts`, `packages/tui/src/typed-value/lines.ts`, `packages/tui/src/typed-value/lines/*`, `packages/tui/src/typed-value/line-ranges.ts`, `packages/tui/tests/textarea.test.ts`, `packages/tui/tests/typed-value.test.ts` | +| Textarea wrapped-line cursor navigation | `packages/tui/src/typed-value.ts`, `packages/tui/src/typed-value/edit.ts`, `packages/tui/src/typed-value/edit/navigation.ts`, `packages/tui/src/typed-value/lines.ts`, `packages/tui/src/typed-value/lines/*`, `packages/tui/src/typed-value/line-ranges.ts`, `packages/tui/tests/textarea.test.ts`, `packages/tui/tests/typed-value.test.ts` | | Password input | `packages/tui/src/prompts/password.ts`, `packages/tui/src/typed-value.ts` | -| Password input transforms, validation retry, editing keys, cancellation, masking, and non-interactive behavior | `packages/tui/src/prompts/password.ts`, `packages/tui/src/prompts/password/input.ts`, `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/tests/password.test.ts` | -| Password active, submitted, cancelled, placeholder, masked, and validation-safe rendering | `packages/tui/src/prompts/password.ts`, `packages/tui/src/prompts/password/input.ts`, `packages/tui/src/prompts/password/render.ts`, `packages/tui/tests/password.test.ts` | +| Password input transforms, validation retry, editing keys, cancellation, masking, and non-interactive behavior | `packages/tui/src/prompts/password.ts`, `packages/tui/src/prompts/password/options.ts`, `packages/tui/src/prompts/password/run.ts`, `packages/tui/src/prompts/password/input.ts`, `packages/tui/src/prompts/password/fallback.ts`, `packages/tui/src/prompts/password/session.ts`, `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/tests/password.test.ts` | +| Password active, submitted, cancelled, placeholder, masked, and validation-safe rendering | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/password.ts`, `packages/tui/src/prompts/password/run.ts`, `packages/tui/src/prompts/password/input.ts`, `packages/tui/src/prompts/password/session.ts`, `packages/tui/src/prompts/password/render.ts`, `packages/tui/tests/password.test.ts` | +| Password active-frame redraw and masked cursor rendering | `packages/tui/src/prompts/password.ts`, `packages/tui/src/prompts/password/run.ts`, `packages/tui/src/prompts/password/input.ts`, `packages/tui/src/prompts/password/session.ts`, `packages/tui/src/prompts/password/render.ts` | +| Password transformed fallback value, invalid retry default preservation, overload validation, and plain placeholder rendering | `packages/tui/src/prompts/password.ts`, `packages/tui/src/prompts/password/options.ts`, `packages/tui/src/prompts/password/run.ts`, `packages/tui/src/prompts/text-default.ts`, `packages/tui/src/concerns/validators/text-options.ts`, `packages/tui/src/prompts/password/render.ts` | | Number input | `packages/tui/src/prompts/number.ts`, `packages/tui/src/typed-value.ts` | -| Number active, submitted, cancelled, arrow, placeholder, default, and validation-safe rendering | `packages/tui/src/prompts/number.ts`, `packages/tui/src/prompts/number/input.ts`, `packages/tui/src/prompts/number/render.ts`, `packages/tui/tests/number.test.ts` | +| Number active, submitted, cancelled, arrow, placeholder, default, and validation-safe rendering | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/number.ts`, `packages/tui/src/prompts/number/input.ts`, `packages/tui/src/prompts/number/interactive.ts`, `packages/tui/src/prompts/number/session.ts`, `packages/tui/src/prompts/number/session/*`, `packages/tui/src/prompts/number/render.ts`, `packages/tui/tests/number.test.ts` | +| Number default renderer inline arrow controls | `packages/tui/src/prompts/number/render.ts` | +| Number active-frame redraw and cursor rendering | `packages/tui/src/prompts/number.ts`, `packages/tui/src/prompts/number/input.ts`, `packages/tui/src/prompts/number/interactive.ts`, `packages/tui/src/prompts/number/session.ts`, `packages/tui/src/prompts/number/session/*`, `packages/tui/src/prompts/number/render.ts` | +| Number explicit-default lifecycle, invalid retry default preservation, parser-error retry preservation, overload validation, and transformed fallback value | `packages/tui/src/prompts/number.ts`, `packages/tui/src/prompts/number/defaults.ts`, `packages/tui/src/prompts/number/input.ts`, `packages/tui/src/prompts/number/fallback.ts`, `packages/tui/src/prompts/number/validators/overload.ts`, `packages/tui/src/validators/default.ts` | | Confirm, select, multiselect | `packages/tui/src/prompts/select/*` | -| Confirm active, submitted, cancelled, custom-label, fallback, and non-interactive behavior | `packages/tui/src/prompts/select/read-confirm.ts`, `packages/tui/src/prompts/select/render-confirm.ts`, `packages/tui/tests/choices.test.ts` | -| Confirm submitted frame renders only after validation passes | `packages/tui/src/prompts/select/confirm.ts`, `packages/tui/src/prompts/select/read-confirm.ts`, `packages/tui/tests/choices.test.ts` | -| Select active boxed layout and row styling | `packages/tui/src/prompts/select/render.ts`, `packages/tui/tests/choices.test.ts` | +| Confirm active, submitted, cancelled, custom-label, fallback, and non-interactive behavior | `packages/tui/src/prompts/select/read-confirm.ts`, `packages/tui/src/prompts/select/read-confirm/*`, `packages/tui/src/prompts/select/render-confirm.ts`, `packages/tui/tests/choices.test.ts` | +| Confirm submitted frame renders only after validation passes | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/select/confirm.ts`, `packages/tui/src/prompts/select/confirm-run.ts`, `packages/tui/src/prompts/select/read-confirm.ts`, `packages/tui/src/prompts/select/read-confirm/*`, `packages/tui/tests/choices.test.ts` | +| Confirm explicit-default lifecycle, invalid retry default preservation, overload validation, and transformed fallback value | `packages/tui/src/prompts/select/confirm.ts`, `packages/tui/src/prompts/select/confirm-options.ts`, `packages/tui/src/prompts/select/confirm-run.ts`, `packages/tui/src/prompts/select/read-confirm.ts`, `packages/tui/src/prompts/select/read-confirm/*`, `packages/tui/src/prompts/select/validators/overload.ts`, `packages/tui/src/validators/default.ts` | +| Confirm active-frame redraw and submitted-frame replacement | `packages/tui/src/prompts/select/confirm.ts`, `packages/tui/src/prompts/select/confirm-run.ts`, `packages/tui/src/prompts/select/read-confirm.ts`, `packages/tui/src/prompts/select/read-confirm/*`, `packages/tui/src/prompts/select/render-confirm.ts` | +| Confirm active and cancelled body styling | `packages/tui/src/prompts/select/render-confirm.ts` | +| Select active boxed layout and row styling | `packages/tui/src/concerns/choice-label.ts`, `packages/tui/src/theme/choice-disabled.ts`, `packages/tui/src/theme/validators/disabled.ts`, `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/render-rows.ts`, `packages/tui/src/prompts/select/render-rows/*`, `packages/tui/tests/choices.test.ts` | | Select and multi-select label-first helper argument surface with info | `packages/tui/src/prompts/select/index.ts`, `packages/tui/tests/choices.test.ts` | -| Select required-option validation | `packages/tui/src/prompts/select/validators/options.ts`, `packages/tui/src/prompts/select/index.ts`, `packages/tui/tests/choices.test.ts` | -| Select non-interactive default validation | `packages/tui/src/prompts/select/index.ts`, `packages/tui/tests/choices.test.ts` | -| Select line-mode and exhausted-input default fallback with validation retry | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/tests/choices.test.ts` | -| Select submitted final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/tests/choices.test.ts` | -| Select submitted frame renders only after validation passes | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/tests/choices.test.ts` | -| Select cancel final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/tests/choices.test.ts` | -| Multi-select active boxed layout and row styling | `packages/tui/src/prompts/select/render.ts`, `packages/tui/tests/choices.test.ts` | -| Multi-select submitted final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-multiple.ts`, `packages/tui/tests/choices.test.ts` | -| Multi-select submitted frame renders only after validation passes | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/read-multiple.ts`, `packages/tui/tests/choices.test.ts` | -| Multi-select cancel final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-multiple.ts`, `packages/tui/tests/choices.test.ts` | +| Select required-option validation | `packages/tui/src/prompts/select/validators/options.ts`, `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/select.ts`, `packages/tui/src/prompts/select/options.ts`, `packages/tui/src/prompts/select/run.ts`, `packages/tui/tests/choices.test.ts` | +| Select non-interactive default validation | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/select.ts`, `packages/tui/src/prompts/select/options.ts`, `packages/tui/src/prompts/select/run.ts`, `packages/tui/tests/choices.test.ts` | +| Select explicit-default lifecycle, invalid retry default preservation, overload validation, and transformed fallback value | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/select.ts`, `packages/tui/src/prompts/select/defaults.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/src/prompts/select/read-selected/interactive.ts`, `packages/tui/src/prompts/select/read-selected/result.ts`, `packages/tui/src/prompts/select/validators/overload.ts`, `packages/tui/src/concerns/choices.ts`, `packages/tui/src/concerns/choice-match.ts`, `packages/tui/src/validators/default.ts` | +| Select line-mode and exhausted-input default fallback with validation retry | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/select.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/src/prompts/select/read-selected/interactive.ts`, `packages/tui/src/prompts/select/read-selected/result.ts`, `packages/tui/tests/choices.test.ts` | +| Select submitted final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/src/prompts/select/read-selected/interactive.ts`, `packages/tui/src/prompts/select/read-selected/interactive/*`, `packages/tui/tests/choices.test.ts` | +| Select submitted frame renders only after validation passes | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/select.ts`, `packages/tui/src/prompts/select/run.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/src/prompts/select/read-selected/interactive.ts`, `packages/tui/src/prompts/select/read-selected/interactive/*`, `packages/tui/src/prompts/select/read-selected/result.ts`, `packages/tui/tests/choices.test.ts` | +| Select active-frame redraw and submitted-frame replacement | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/select.ts`, `packages/tui/src/prompts/select/run.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/src/prompts/select/read-selected/interactive.ts`, `packages/tui/src/prompts/select/read-selected/interactive/*`, `packages/tui/src/prompts/select/render.ts` | +| Select cancel final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-selected.ts`, `packages/tui/src/prompts/select/read-selected/interactive.ts`, `packages/tui/src/prompts/select/read-selected/interactive/*`, `packages/tui/tests/choices.test.ts` | +| Select cancelled frame row styling | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/render-rows.ts`, `packages/tui/src/prompts/select/render-rows/*` | +| Multi-select active boxed layout and row styling | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/render-rows.ts`, `packages/tui/src/prompts/select/render-rows/*`, `packages/tui/tests/choices.test.ts` | +| Multi-select transformed fallback value and invalid retry default preservation | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/multiselect.ts`, `packages/tui/src/prompts/select/multiselect/*`, `packages/tui/src/prompts/select/defaults.ts`, `packages/tui/src/prompts/select/validators/overload.ts` | +| Multi-select submitted final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-multiple.ts`, `packages/tui/src/prompts/select/read-multiple/*`, `packages/tui/src/prompts/select/read-multiple/session/*`, `packages/tui/src/prompts/select/read-multiple/result.ts`, `packages/tui/tests/choices.test.ts` | +| Multi-select empty submitted final frame | `packages/tui/src/prompts/select/render.ts` | +| Multi-select submitted frame renders only after validation passes | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/multiselect.ts`, `packages/tui/src/prompts/select/multiselect/*`, `packages/tui/src/prompts/select/read-multiple.ts`, `packages/tui/src/prompts/select/read-multiple/*`, `packages/tui/src/prompts/select/read-multiple/session/*`, `packages/tui/src/prompts/select/read-multiple/result.ts`, `packages/tui/tests/choices.test.ts` | +| Multi-select active-frame redraw and submitted-frame replacement | `packages/tui/src/prompts/select/index.ts`, `packages/tui/src/prompts/select/multiselect.ts`, `packages/tui/src/prompts/select/multiselect/*`, `packages/tui/src/prompts/select/read-multiple.ts`, `packages/tui/src/prompts/select/read-multiple/*`, `packages/tui/src/prompts/select/read-multiple/session/*`, `packages/tui/src/prompts/select/render.ts` | +| Multi-select cancel final frame | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/read-multiple.ts`, `packages/tui/src/prompts/select/read-multiple/*`, `packages/tui/src/prompts/select/read-multiple/session/*`, `packages/tui/src/prompts/select/read-multiple/result.ts`, `packages/tui/tests/choices.test.ts` | +| Multi-select cancelled frame row styling | `packages/tui/src/prompts/select/render.ts`, `packages/tui/src/prompts/select/render-rows.ts`, `packages/tui/src/prompts/select/render-rows/*` | | Suggest, autocomplete | `packages/tui/src/prompts/suggest/*` | -| Suggest active, submitted, cancelled, placeholder, info, scrolling, and validation-safe rendering | `packages/tui/src/prompts/suggest/index.ts`, `packages/tui/src/prompts/suggest/read.ts`, `packages/tui/src/prompts/suggest/render.ts`, `packages/tui/tests/suggest.test.ts` | -| Suggest and autocomplete label-first info rendering | `packages/tui/src/prompts/suggest/index.ts`, `packages/tui/src/prompts/suggest/options.ts`, `packages/tui/src/prompts/suggest/read-autocomplete.ts`, `packages/tui/src/prompts/suggest/render-autocomplete.ts`, `packages/tui/tests/suggest.test.ts` | +| Suggest active, submitted, cancelled, placeholder, info, scrolling, and validation-safe rendering | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/suggest/suggest.ts`, `packages/tui/src/prompts/suggest/lifecycle.ts`, `packages/tui/src/prompts/suggest/read.ts`, `packages/tui/src/prompts/suggest/read/*`, `packages/tui/src/prompts/suggest/read/state/*`, `packages/tui/src/prompts/suggest/state/*`, `packages/tui/src/prompts/suggest/read-result.ts`, `packages/tui/src/prompts/suggest/render.ts`, `packages/tui/src/prompts/suggest/render/*`, `packages/tui/tests/suggest.test.ts` | +| Suggest active-frame redraw and cursor rendering | `packages/tui/src/prompts/suggest/suggest.ts`, `packages/tui/src/prompts/suggest/read.ts`, `packages/tui/src/prompts/suggest/read/*`, `packages/tui/src/prompts/suggest/read/state/*`, `packages/tui/src/prompts/suggest/state/*`, `packages/tui/src/prompts/suggest/read-result.ts`, `packages/tui/src/prompts/suggest/render.ts`, `packages/tui/src/prompts/suggest/render/*` | +| Suggest empty-result rendering for empty and typed queries | `packages/tui/src/prompts/suggest/render.ts`, `packages/tui/src/prompts/suggest/render/*` | +| Suggest and autocomplete transformed fallback value, invalid retry default preservation, source validation, and overload validation | `packages/tui/src/prompts/suggest/suggest.ts`, `packages/tui/src/prompts/suggest/autocomplete-prompt.ts`, `packages/tui/src/prompts/suggest/lifecycle.ts`, `packages/tui/src/prompts/suggest/validators/overload.ts`, `packages/tui/src/prompts/suggest/validators/source.ts`, `packages/tui/src/prompts/text-default.ts` | +| Suggest and autocomplete plain placeholder rendering | `packages/tui/src/prompts/suggest/render.ts`, `packages/tui/src/prompts/suggest/render-autocomplete.ts` | +| Suggest and autocomplete label-first info rendering | `packages/tui/src/prompts/suggest/suggest.ts`, `packages/tui/src/prompts/suggest/autocomplete-prompt.ts`, `packages/tui/src/prompts/suggest/options.ts`, `packages/tui/src/prompts/suggest/read-autocomplete.ts`, `packages/tui/src/prompts/suggest/read-result.ts`, `packages/tui/src/prompts/suggest/render-autocomplete.ts`, `packages/tui/tests/suggest.test.ts` | | Autocomplete styled cursor-aware ghost text and Unicode-safe completion acceptance | `packages/tui/src/prompts/suggest/ghost-text.ts`, `packages/tui/src/prompts/suggest/autocomplete.ts`, `packages/tui/src/theme/styles.ts`, `packages/tui/tests/suggest.test.ts` | -| Autocomplete active, submitted, cancelled, placeholder, ghost-text, and validation-safe rendering | `packages/tui/src/prompts/suggest/index.ts`, `packages/tui/src/prompts/suggest/read-autocomplete.ts`, `packages/tui/src/prompts/suggest/render-autocomplete.ts`, `packages/tui/tests/suggest.test.ts` | +| Autocomplete active, submitted, cancelled, placeholder, ghost-text, and validation-safe rendering | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/suggest/autocomplete-prompt.ts`, `packages/tui/src/prompts/suggest/lifecycle.ts`, `packages/tui/src/prompts/suggest/read-autocomplete.ts`, `packages/tui/src/prompts/suggest/read-autocomplete/*`, `packages/tui/src/prompts/suggest/read-autocomplete/state/*`, `packages/tui/src/prompts/suggest/state/*`, `packages/tui/src/prompts/suggest/read-result.ts`, `packages/tui/src/prompts/suggest/render-autocomplete.ts`, `packages/tui/tests/suggest.test.ts` | +| Autocomplete active-frame redraw and cursor fallback rendering | `packages/tui/src/prompts/suggest/autocomplete-prompt.ts`, `packages/tui/src/prompts/suggest/read-autocomplete.ts`, `packages/tui/src/prompts/suggest/read-autocomplete/*`, `packages/tui/src/prompts/suggest/read-autocomplete/state/*`, `packages/tui/src/prompts/suggest/state/*`, `packages/tui/src/prompts/suggest/read-result.ts`, `packages/tui/src/prompts/suggest/render-autocomplete.ts`, `packages/tui/src/prompts/suggest/ghost-text.ts` | | Search, multisearch | `packages/tui/src/prompts/search/*` | | Search and multi-search label-first helper argument surface with info | `packages/tui/src/prompts/search/index.ts`, `packages/tui/tests/search.test.ts` | -| Search active boxed layout and row styling | `packages/tui/src/prompts/search/render.ts`, `packages/tui/tests/search.test.ts` | -| Search and multisearch empty-result rendering | `packages/tui/src/prompts/search/render.ts`, `packages/tui/tests/search.test.ts` | -| Search highlighted-result row styling | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/theme/styles.ts`, `packages/tui/tests/search.test.ts` | -| Search submitted final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/tests/search.test.ts` | -| Search submitted frame renders only after validation passes | `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/result.ts`, `packages/tui/tests/search.test.ts` | -| Search cancel final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/tests/search.test.ts` | -| Multi-search active boxed layout and selected-count footer | `packages/tui/src/prompts/search/render.ts`, `packages/tui/tests/search.test.ts` | -| Multi-search submitted final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/read-multi.ts`, `packages/tui/tests/search.test.ts` | -| Multi-search submitted frame renders only after validation passes | `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/read-multi.ts`, `packages/tui/src/prompts/search/read-multi/result.ts`, `packages/tui/tests/search.test.ts` | -| Multi-search cancel final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/read-multi.ts`, `packages/tui/tests/search.test.ts` | -| Pause | `packages/tui/src/prompts/pause.ts` | -| Pause themed key-driven frame | `packages/tui/src/prompts/pause.ts`, `packages/tui/src/prompts/pause/render.ts`, `packages/tui/tests/pause.test.ts` | -| Pause non-interactive no-render behavior | `packages/tui/src/prompts/pause.ts`, `packages/tui/tests/pause.test.ts` | -| Choice normalization, matching, navigation, and list rendering concerns | `packages/tui/src/concerns/choices.ts` | -| Choice and search scrollbar rendering | `packages/tui/src/concerns/scrollbar.ts`, `packages/tui/src/concerns/choices.ts`, `packages/tui/src/prompts/search/render.ts` | -| Form builder | `packages/tui/src/form.ts`, `packages/tui/src/form/builder/*` | +| Search active boxed layout and row styling | `packages/tui/src/concerns/choice-label.ts`, `packages/tui/src/theme/choice-disabled.ts`, `packages/tui/src/theme/validators/disabled.ts`, `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/render-body.ts`, `packages/tui/src/prompts/search/body/*`, `packages/tui/tests/search.test.ts` | +| Search active-frame redraw and cursor rendering | `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/search.ts`, `packages/tui/src/prompts/search/run.ts`, `packages/tui/src/prompts/search/keys.ts`, `packages/tui/src/prompts/search/keys/*`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/*`, `packages/tui/src/prompts/search/read-single/interactive/*`, `packages/tui/src/prompts/search/read-single/session/*`, `packages/tui/src/prompts/search/render.ts` | +| Search retry initial highlight lifecycle | `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/*`, `packages/tui/src/prompts/search/read-single/state/*`, `packages/tui/src/prompts/search/navigation.ts` | +| Search and multisearch empty-result rendering | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/render-body.ts`, `packages/tui/src/prompts/search/body/*`, `packages/tui/tests/search.test.ts` | +| Search highlighted-result row styling | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/render-body.ts`, `packages/tui/src/prompts/search/body/*`, `packages/tui/src/theme/styles.ts`, `packages/tui/tests/search.test.ts` | +| Search explicit-default lifecycle, invalid retry default preservation, source validation, overload validation, and transformed fallback value | `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/search.ts`, `packages/tui/src/prompts/search/options.ts`, `packages/tui/src/prompts/search/run.ts`, `packages/tui/src/prompts/search/defaults.ts`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/*`, `packages/tui/src/prompts/search/read-single/state/*`, `packages/tui/src/prompts/search/read-single/result.ts`, `packages/tui/src/prompts/search/line-mode.ts`, `packages/tui/src/prompts/search/validators/overload.ts`, `packages/tui/src/prompts/search/validators/source.ts`, `packages/tui/src/concerns/choices.ts`, `packages/tui/src/concerns/choice-match.ts`, `packages/tui/src/validators/default.ts` | +| Search submitted final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/*`, `packages/tui/src/prompts/search/read-single/interactive/*`, `packages/tui/tests/search.test.ts` | +| Search submitted frame renders only after validation passes | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/search.ts`, `packages/tui/src/prompts/search/run.ts`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/*`, `packages/tui/src/prompts/search/read-single/interactive/*`, `packages/tui/src/prompts/search/read-single/result.ts`, `packages/tui/tests/search.test.ts` | +| Search cancel final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/interactive/*`, `packages/tui/tests/search.test.ts` | +| Multi-search active boxed layout and selected-count footer | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/render-body.ts`, `packages/tui/src/prompts/search/body/*`, `packages/tui/src/prompts/search/read-multi/state/*`, `packages/tui/tests/search.test.ts` | +| Multi-search transformed fallback value and invalid retry default preservation | `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/multisearch.ts`, `packages/tui/src/prompts/search/multi-options.ts`, `packages/tui/src/prompts/search/multi-run.ts`, `packages/tui/src/prompts/search/defaults.ts`, `packages/tui/src/prompts/search/validators/overload.ts` | +| Multi-search submitted final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/multi-run.ts`, `packages/tui/src/prompts/search/read-multi.ts`, `packages/tui/src/prompts/search/read-multi/*`, `packages/tui/src/prompts/search/read-multi/state/*`, `packages/tui/tests/search.test.ts` | +| Multi-search empty submitted final frame | `packages/tui/src/prompts/search/render.ts` | +| Multi-search submitted frame renders only after validation passes | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/multisearch.ts`, `packages/tui/src/prompts/search/multi-run.ts`, `packages/tui/src/prompts/search/read-multi.ts`, `packages/tui/src/prompts/search/read-multi/*`, `packages/tui/src/prompts/search/read-multi/state/*`, `packages/tui/src/prompts/search/read-multi/result.ts`, `packages/tui/tests/search.test.ts` | +| Multi-search active-frame redraw and cursor rendering | `packages/tui/src/prompts/search/index.ts`, `packages/tui/src/prompts/search/multisearch.ts`, `packages/tui/src/prompts/search/multi-run.ts`, `packages/tui/src/prompts/search/keys.ts`, `packages/tui/src/prompts/search/keys/*`, `packages/tui/src/prompts/search/read-multi.ts`, `packages/tui/src/prompts/search/read-multi/*`, `packages/tui/src/prompts/search/read-multi/state/*`, `packages/tui/src/prompts/search/render.ts` | +| Multi-search cancel final frame | `packages/tui/src/prompts/search/render.ts`, `packages/tui/src/prompts/search/read-multi.ts`, `packages/tui/src/prompts/search/read-multi/*`, `packages/tui/src/prompts/search/read-multi/state/*`, `packages/tui/tests/search.test.ts` | +| Pause | `packages/tui/src/prompts/pause.ts`, `packages/tui/src/prompts/pause/*` | +| Pause themed key-driven frame | `packages/tui/src/prompts/pause.ts`, `packages/tui/src/prompts/pause/read.ts`, `packages/tui/src/prompts/pause/render.ts`, `packages/tui/tests/pause.test.ts` | +| Pause non-interactive no-render behavior | `packages/tui/src/prompts/pause.ts`, `packages/tui/src/prompts/pause/read.ts`, `packages/tui/tests/pause.test.ts` | +| Choice normalization, matching, navigation, and list rendering concerns | `packages/tui/src/concerns/choices.ts`, `packages/tui/src/concerns/choice-normalize.ts`, `packages/tui/src/concerns/choice-match.ts`, `packages/tui/src/concerns/choice-navigation.ts`, `packages/tui/src/concerns/choice-render.ts` | +| Choice and search scrollbar rendering | `packages/tui/src/concerns/scrollbar.ts`, `packages/tui/src/concerns/choice-navigation.ts`, `packages/tui/src/concerns/choice-render.ts`, `packages/tui/src/prompts/search/render.ts` | +| Form builder | `packages/tui/src/form.ts`, `packages/tui/src/form/builder/*`, `packages/tui/src/form/builder/responses.ts` | | Form builder nested prompt revert short-circuiting | `packages/tui/src/form/builder/revert.ts`, `packages/tui/src/form/builder/submit.ts`, `packages/tui/tests/form.test.ts` | | Form builder first-step and conditional revert feature coverage | `packages/tui/src/form/builder/conditions.ts`, `packages/tui/src/form/builder/submit.ts`, `packages/tui/tests/form.test.ts` | | Form builder asynchronous condition lifecycle | `packages/tui/src/form/builder/conditions.ts`, `packages/tui/src/form/builder/submit.ts`, `packages/tui/src/form/types.ts`, `packages/tui/tests/form.test.ts` | -| Notes and alert-style output | `packages/tui/src/output/notes.ts` | -| Note multiline and typed theme rendering | `packages/tui/src/output/notes.ts`, `packages/tui/src/theme/styles.ts`, `packages/tui/tests/output.test.ts` | -| Note intro/outro visible-width padding | `packages/tui/src/output/notes.ts`, `packages/tui/tests/output.test.ts` | +| Form builder side-effect step surface and revert skipping | `packages/tui/src/form/builder/index.ts`, `packages/tui/src/form/builder/methods.ts`, `packages/tui/src/form/builder/step.ts`, `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/status.ts` | +| Notes and alert-style output | `packages/tui/src/output/notes.ts`, `packages/tui/src/output/notes/*` | +| Note multiline and typed theme rendering | `packages/tui/src/output/notes.ts`, `packages/tui/src/output/notes/render.ts`, `packages/tui/src/theme/styles.ts`, `packages/tui/tests/output.test.ts` | +| Note intro/outro visible-width padding | `packages/tui/src/output/notes.ts`, `packages/tui/src/output/notes/render.ts`, `packages/tui/tests/output.test.ts` | | Native notifications | `packages/tui/src/output/notify.ts` | | Notification command construction, executable discovery, and process result reporting | `packages/tui/src/output/notify.ts`, `packages/tui/src/output/notify/*` | -| Tables, data tables, and grids | `packages/tui/src/output/table.ts`, `packages/tui/src/output/data-table.ts` | +| Tables, data tables, and grids | `packages/tui/src/output/table.ts`, `packages/tui/src/output/table-output.ts`, `packages/tui/src/output/grid-output.ts`, `packages/tui/src/output/data-table.ts` | | Data table label-first helper argument surface | `packages/tui/src/output/data-table.ts`, `packages/tui/tests/table.test.ts` | -| Data table transform callback lifecycle | `packages/tui/src/contracts/output.ts`, `packages/tui/src/output/data-table.ts`, `packages/tui/tests/table.test.ts` | -| Data table interactive default selection | `packages/tui/src/output/data-table/read.ts`, `packages/tui/tests/table.test.ts` | -| Data table exhausted-input default selection | `packages/tui/src/output/data-table/read.ts`, `packages/tui/tests/table.test.ts` | -| Data table no-results search rendering | `packages/tui/src/output/data-table/render.ts`, `packages/tui/tests/table.test.ts` | -| Data table viewing-info rendering | `packages/tui/src/output/data-table/render.ts`, `packages/tui/tests/table.test.ts` | -| Data table submitted and cancelled final frames | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/read.ts`, `packages/tui/tests/table.test.ts` | -| Data table submitted frame renders only after validation passes | `packages/tui/src/output/data-table.ts`, `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/types.ts`, `packages/tui/tests/table.test.ts` | -| Data table themed cancellation warning | `packages/tui/src/output/data-table/render.ts`, `packages/tui/tests/table.test.ts` | -| Data table multiline cell rendering | `packages/tui/src/output/data-table/multiline.ts`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/tests/table.test.ts` | -| Data table scrollbar rendering | `packages/tui/src/output/data-table/scrollbar.ts`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/tests/table.test.ts` | -| Data table no-header and blank-cell rendering | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/rows.ts`, `packages/tui/tests/table.test.ts` | -| Data table row-shape validation and normalization | `packages/tui/src/output/validators/data-table.ts`, `packages/tui/src/output/data-table/rows.ts`, `packages/tui/tests/table.test.ts` | -| Static table row-shape validation and header inference | `packages/tui/src/output/validators/table.ts`, `packages/tui/tests/table.test.ts` | -| Data table fixed visual height | `packages/tui/src/output/data-table/visual-window.ts`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/tests/table.test.ts` | -| Data table comfortable width and outlier truncation | `packages/tui/src/output/data-table/widths.ts`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/tests/table.test.ts` | -| Boxed balanced grid rendering | `packages/tui/src/output/grid.ts`, `packages/tui/tests/output.test.ts` | +| Data table transform callback lifecycle | `packages/tui/src/contracts/output.ts`, `packages/tui/src/output/data-table.ts`, `packages/tui/src/output/data-table/run.ts`, `packages/tui/src/output/data-table/options.ts`, `packages/tui/tests/table.test.ts` | +| Data table interactive default selection | `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/reader/result.ts`, `packages/tui/tests/table.test.ts` | +| Data table exhausted-input default selection | `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/reader/result.ts`, `packages/tui/tests/table.test.ts` | +| Data table line-input fallback filtering | `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/reader/fallback.ts`, `packages/tui/src/prompt/ask.ts` | +| Data table no-results search rendering | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/tests/table.test.ts` | +| Data table viewing-info rendering | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/tests/table.test.ts` | +| Data table submitted and cancelled final frames | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/reader/interactive.ts`, `packages/tui/src/output/data-table/reader/cancel.ts`, `packages/tui/tests/table.test.ts` | +| Data table submitted frame renders only after validation passes | `packages/tui/src/prompt/submission.ts`, `packages/tui/src/output/data-table.ts`, `packages/tui/src/output/data-table/run.ts`, `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/reader/interactive.ts`, `packages/tui/src/output/data-table/reader/result.ts`, `packages/tui/src/output/data-table/types.ts`, `packages/tui/tests/table.test.ts` | +| Data table active-frame redraw and cursor-aware search rendering | `packages/tui/src/output/data-table.ts`, `packages/tui/src/output/data-table/run.ts`, `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/reader/interactive.ts`, `packages/tui/src/output/data-table/reader/session.ts`, `packages/tui/src/output/data-table/reader/session/*`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/types.ts` | +| Data table explicit-default lifecycle, invalid retry default preservation, and transformed fallback value | `packages/tui/src/output/data-table.ts`, `packages/tui/src/output/data-table/options.ts`, `packages/tui/src/output/data-table/read.ts`, `packages/tui/src/output/data-table/reader/result.ts`, `packages/tui/src/validators/default.ts` | +| Data table themed cancellation warning | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/src/output/data-table/reader/cancel.ts`, `packages/tui/tests/table.test.ts` | +| Data table multiline cell rendering | `packages/tui/src/output/data-table/multiline.ts`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/tests/table.test.ts` | +| Data table scrollbar rendering | `packages/tui/src/output/data-table/scrollbar.ts`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/tests/table.test.ts` | +| Data table no-header and blank-cell rendering | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/src/output/data-table/rows.ts`, `packages/tui/src/output/data-table/rows/*`, `packages/tui/tests/table.test.ts` | +| Data table row-shape validation and normalization | `packages/tui/src/output/validators/cells.ts`, `packages/tui/src/output/validators/data-table.ts`, `packages/tui/src/output/data-table/rows.ts`, `packages/tui/src/output/data-table/rows/*`, `packages/tui/tests/table.test.ts` | +| Static table row-shape validation and header inference | `packages/tui/src/output/validators/cells.ts`, `packages/tui/src/output/validators/table.ts`, `packages/tui/src/output/validators/table/*`, `packages/tui/tests/table.test.ts` | +| Data table fixed visual height | `packages/tui/src/output/data-table/visual-window.ts`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/tests/table.test.ts` | +| Data table comfortable width and outlier truncation | `packages/tui/src/output/data-table/widths.ts`, `packages/tui/src/output/data-table/widths/*`, `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/render-body.ts`, `packages/tui/src/output/data-table/body/*`, `packages/tui/tests/table.test.ts` | +| Boxed balanced grid rendering | `packages/tui/src/output/grid.ts`, `packages/tui/src/output/grid/*`, `packages/tui/tests/output.test.ts` | | Terminal title and clear output | `packages/tui/src/output/terminal.ts` | | Spinner, progress, task, stream | `packages/tui/src/status/*`, `packages/tui/src/status.ts` | -| Form builder label-first search and multisearch methods | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/tests/form.test.ts` | -| Form builder label-first choice and search info rendering | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/tests/form.test.ts` | +| Form builder label-first search and multisearch methods | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/tests/form.test.ts` | +| Form builder label-first choice and search info rendering | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/tests/form.test.ts` | | Form builder previous-response defaults | `packages/tui/src/form/builder/previous.ts`, `packages/tui/src/form/builder/validators/previous.ts`, `packages/tui/tests/form.test.ts` | -| Form builder basic prompt object-option method surface | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/src/form/builder/prompts/contracts/basic.ts`, `packages/tui/src/form/builder/prompts/validators/basic.ts`, `packages/tui/tests/form.test.ts` | -| Form builder choice prompt object-option method surface | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/src/form/builder/prompts/validators/select.ts`, `packages/tui/tests/form.test.ts` | -| Form builder suggest and autocomplete placeholder/default arguments | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/tests/form.test.ts` | -| Form builder suggest and autocomplete object-option method surface | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/src/form/builder/prompts/validators/suggest.ts`, `packages/tui/tests/form.test.ts` | -| Form builder suggest and autocomplete label-first info rendering | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/tests/form.test.ts` | -| Form builder number transform argument surface | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/src/form/builder/prompts/contracts/basic.ts`, `packages/tui/src/prompts/number.ts`, `packages/tui/tests/form.test.ts`, `packages/tui/tests/number.test.ts` | -| Form builder password previous-response defaults | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/tests/form.test.ts` | -| Form builder search and multisearch previous-response defaults | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/tests/form.test.ts` | -| Form builder named prompt defaults after skipped conditional responses | `packages/tui/src/form/builder/previous.ts`, `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/validators/previous.ts`, `packages/tui/tests/form.test.ts` | -| Form builder label-first data table method surface | `packages/tui/src/form/builder/output.ts`, `packages/tui/tests/form.test.ts` | -| Form builder label-first data table previous-response defaults | `packages/tui/src/form/builder/output.ts`, `packages/tui/tests/form.test.ts` | -| Form builder interactive data table object-option method surface | `packages/tui/src/form/builder/output.ts`, `packages/tui/src/output/validators/data-table.ts`, `packages/tui/tests/form.test.ts` | -| Form builder object-option table output method surface | `packages/tui/src/form/builder/output.ts`, `packages/tui/src/output/validators/table.ts`, `packages/tui/tests/form.test.ts` | -| Form builder output method surface for grid, display data table, terminal helpers, and notifications | `packages/tui/src/form/builder/index.ts`, `packages/tui/src/form/builder/output.ts`, `packages/tui/tests/form.test.ts` | -| Display-only output helper return values and form responses | `packages/tui/src/output/notes.ts`, `packages/tui/src/output/table.ts`, `packages/tui/src/form/builder/output.ts`, `packages/tui/tests/output.test.ts`, `packages/tui/tests/form.test.ts` | -| Progress boxed frame rendering and formatted fractions | `packages/tui/src/status/progress/render.ts`, `packages/tui/src/theme/box.ts` | -| Spinner static and deterministic animated frame rendering | `packages/tui/src/status/spinner.ts`, `packages/tui/src/status/spinner/render.ts` | -| Spinner empty default message | `packages/tui/src/status/spinner.ts`, `packages/tui/src/form/builder/status.ts`, `packages/tui/tests/spinner.test.ts`, `packages/tui/tests/form.test.ts` | -| Task static and deterministic animated frame rendering, bounded logs, and stable summary symbols | `packages/tui/src/status/task.ts`, `packages/tui/src/status/task/*` | -| Form builder root-aligned spinner and task overloads | `packages/tui/src/form/builder/status.ts`, `packages/tui/tests/form.test.ts` | -| Form builder root-aligned manual progress overload | `packages/tui/src/form/builder/status.ts`, `packages/tui/tests/form.test.ts` | -| Task process output capture | `packages/tui/src/status/task/process-output.ts`, `packages/tui/tests/task.test.ts` | -| Stream frame rendering, wrapping, fade styles, and close flushing | `packages/tui/src/status/stream.ts`, `packages/tui/src/status/stream/*` | -| Form builder root-aligned manual stream overload | `packages/tui/src/form/builder/status.ts`, `packages/tui/tests/form.test.ts` | +| Form builder basic prompt object-option method surface with validator-backed names | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/src/form/builder/prompts/basic/*`, `packages/tui/src/form/builder/prompts/contracts/basic.ts`, `packages/tui/src/form/builder/prompts/validators/basic.ts`, `packages/tui/tests/form.test.ts` | +| Form builder choice prompt object-option method surface with validator-backed overload parsing | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/src/form/builder/prompts/validators/select.ts`, `packages/tui/tests/form.test.ts` | +| Form builder suggest and autocomplete placeholder/default arguments | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/tests/form.test.ts` | +| Form builder suggest and autocomplete object-option method surface with validator-backed overload parsing | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/src/form/builder/prompts/validators/suggest.ts`, `packages/tui/tests/form.test.ts` | +| Form builder suggest and autocomplete label-first info rendering | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/src/form/builder/prompts/contracts/choices.ts`, `packages/tui/tests/form.test.ts` | +| Form builder number transform argument surface | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/src/form/builder/prompts/basic/*`, `packages/tui/src/form/builder/prompts/basic/number/*`, `packages/tui/src/form/builder/prompts/contracts/basic.ts`, `packages/tui/src/prompts/number.ts`, `packages/tui/src/prompts/number/defaults.ts`, `packages/tui/tests/form.test.ts`, `packages/tui/tests/number.test.ts` | +| Form builder password previous-response defaults | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/src/form/builder/prompts/basic/*`, `packages/tui/tests/form.test.ts` | +| Form builder search and multisearch previous-response defaults | `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/tests/form.test.ts` | +| Form builder named prompt defaults after skipped conditional responses | `packages/tui/src/form/builder/previous.ts`, `packages/tui/src/form/builder/prompts/choices.ts`, `packages/tui/src/form/builder/prompts/choice/*`, `packages/tui/src/form/builder/validators/previous.ts`, `packages/tui/tests/form.test.ts` | +| Form builder label-first data table method surface | `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/output/*`, `packages/tui/src/form/builder/output/contracts.ts`, `packages/tui/tests/form.test.ts` | +| Form builder label-first data table previous-response defaults | `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/output/*`, `packages/tui/src/form/builder/output/contracts.ts`, `packages/tui/tests/form.test.ts` | +| Form builder interactive data table object-option method surface | `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/output/*`, `packages/tui/src/form/builder/output/contracts.ts`, `packages/tui/src/output/validators/data-table.ts`, `packages/tui/tests/form.test.ts` | +| Form builder output overload and row validator layer | `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/output/*`, `packages/tui/src/form/builder/output/contracts.ts`, `packages/tui/src/form/builder/validators/output.ts` | +| Form builder object-option table output method surface | `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/output/*`, `packages/tui/src/form/builder/output/contracts.ts`, `packages/tui/src/output/validators/table.ts`, `packages/tui/src/output/validators/table/*`, `packages/tui/tests/form.test.ts` | +| Form builder output method surface for grid, display data table, terminal helpers, and notifications | `packages/tui/src/form/builder/index.ts`, `packages/tui/src/form/builder/methods.ts`, `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/output/*`, `packages/tui/tests/form.test.ts` | +| Display-only output helper return values and form responses | `packages/tui/src/output/notes.ts`, `packages/tui/src/output/table.ts`, `packages/tui/src/form/builder/output.ts`, `packages/tui/src/form/builder/output/*`, `packages/tui/tests/output.test.ts`, `packages/tui/tests/form.test.ts` | +| Progress boxed frame rendering, clamped fill rendering, and formatted fractions | `packages/tui/src/status/progress/render.ts`, `packages/tui/src/status/progress/state/*`, `packages/tui/src/theme/box.ts` | +| Spinner static and deterministic animated frame rendering | `packages/tui/src/status/spinner.ts`, `packages/tui/src/status/spinner/lifecycle.ts`, `packages/tui/src/status/spinner/render.ts` | +| Spinner empty default message | `packages/tui/src/status/spinner.ts`, `packages/tui/src/status/spinner/options.ts`, `packages/tui/src/status/spinner/validators/*`, `packages/tui/src/form/builder/status.ts`, `packages/tui/src/form/builder/status/*`, `packages/tui/tests/spinner.test.ts`, `packages/tui/tests/form.test.ts` | +| Task static and deterministic animated frame rendering, active redraw, bounded logs, and stable summary symbols | `packages/tui/src/status/task.ts`, `packages/tui/src/status/task/definition.ts`, `packages/tui/src/status/task/validators/*`, `packages/tui/src/status/task/lifecycle.ts`, `packages/tui/src/status/task/lifecycle/*`, `packages/tui/src/status/task/frame.ts`, `packages/tui/src/status/task/*` | +| Task non-positive log limit defaulting | `packages/tui/src/status/validators/limit.ts`, `packages/tui/src/status/task/logger.ts`, `packages/tui/src/status/task/logger/*`, `packages/tui/tests/task.test.ts` | +| Form builder root-aligned spinner and task overloads with validator-backed parsing | `packages/tui/src/form/builder/status.ts`, `packages/tui/src/form/builder/status/*`, `packages/tui/src/form/builder/validators/status.ts`, `packages/tui/tests/form.test.ts` | +| Form builder root-aligned manual progress side-effect lifecycle and validator-backed overloads | `packages/tui/src/form/builder/status.ts`, `packages/tui/src/form/builder/status/*`, `packages/tui/src/form/builder/validators/status.ts`, `packages/tui/tests/form.test.ts` | +| Task process output capture, writer validation, and restore-before-flush lifecycle | `packages/tui/src/status/task/process-output.ts`, `packages/tui/src/status/task/process-output/*`, `packages/tui/tests/task.test.ts` | +| Stream frame rendering, active redraw, wrapping, fade styles, chunk validation, lifecycle cleanup, burst coalescing, and close flushing | `packages/tui/src/status/stream.ts`, `packages/tui/src/status/stream/output.ts`, `packages/tui/src/status/stream/output/*`, `packages/tui/src/status/stream/lifecycle.ts`, `packages/tui/src/status/stream/renderer.ts`, `packages/tui/src/status/stream/scheduler.ts`, `packages/tui/src/status/stream/validators/*`, `packages/tui/src/status/stream/*` | +| Form builder root-aligned manual stream named-response overload | `packages/tui/src/form/builder/status.ts`, `packages/tui/src/form/builder/status/*`, `packages/tui/src/form/builder/validators/status.ts`, `packages/tui/src/validators/iterable.ts`, `packages/tui/tests/form.test.ts` | | Status cursor visibility cleanup | `packages/tui/src/status/spinner.ts`, `packages/tui/src/status/stream.ts`, `packages/tui/src/status/task.ts` | +| Status signal cleanup for cursor and rendered-frame restoration | `packages/tui/src/status/signals.ts`, `packages/tui/src/status/spinner.ts`, `packages/tui/src/status/stream.ts`, `packages/tui/src/status/task.ts` | | Status rendered-frame cleanup | `packages/tui/src/status/frame.ts`, `packages/tui/src/status/spinner.ts`, `packages/tui/src/status/task.ts` | -| Progress cursor visibility and rendered-frame redraw cleanup | `packages/tui/src/status/progress.ts`, `packages/tui/src/status/frame.ts` | -| Progress signal cleanup | `packages/tui/src/status/progress.ts`, `packages/tui/tests/progress.test.ts` | -| Terminal clear/title, cursor visibility, true-color detection, default colors, and raw input restoration | `packages/tui/src/terminal.ts`, `packages/tui/src/terminal/*`, `packages/tui/src/environment/raw-key.ts` | +| Progress cursor visibility and rendered-frame redraw cleanup | `packages/tui/src/status/progress/progress.ts`, `packages/tui/src/status/progress/controller.ts`, `packages/tui/src/status/progress/renderer.ts`, `packages/tui/src/status/progress/state.ts`, `packages/tui/src/status/progress/state/*`, `packages/tui/src/status/progress/terminal.ts`, `packages/tui/src/status/frame.ts` | +| Progress signal cleanup | `packages/tui/src/status/progress/progress.ts`, `packages/tui/src/status/progress/terminal.ts`, `packages/tui/src/status/progress/terminal/*`, `packages/tui/tests/progress.test.ts` | +| Progress prompt-disable and manual advance semantics | `packages/tui/src/status/progress.ts`, `packages/tui/src/status/progress/progress.ts`, `packages/tui/src/status/progress/prompt.ts`, `packages/tui/src/status/progress/controller.ts`, `packages/tui/src/status/progress/validators/*`, `packages/tui/src/validators/iterable.ts` | +| Progress integer step parsing and clamped manual advance range | `packages/tui/src/status/progress.ts`, `packages/tui/src/status/progress/progress.ts`, `packages/tui/src/status/progress/state.ts`, `packages/tui/src/status/progress/state/*`, `packages/tui/src/status/progress/validators/*`, `packages/tui/src/status/validators/progress.ts` | +| Terminal clear/title, cursor visibility, true-color detection, default colors, and raw input restoration | `packages/tui/src/terminal.ts`, `packages/tui/src/terminal/*`, `packages/tui/src/environment/raw-key.ts`, `packages/tui/src/environment/raw-key/mode.ts`, `packages/tui/src/environment/raw-key/types.ts` | | Terminal clear/title and notification helper return values | `packages/tui/src/output/terminal.ts`, `packages/tui/src/output/notify.ts`, `packages/tui/tests/terminal.test.ts`, `packages/tui/tests/notify.test.ts` | | Terminal raw key alias normalization | `packages/tui/src/environment/raw-key/normalize.ts`, `packages/tui/tests/environment.test.ts` | -| Terminal split escape-sequence buffering | `packages/tui/src/environment/raw-key.ts`, `packages/tui/src/environment/raw-key/normalize.ts`, `packages/tui/tests/environment.test.ts` | +| Terminal split escape-sequence buffering | `packages/tui/src/environment/raw-key.ts`, `packages/tui/src/environment/raw-key/session.ts`, `packages/tui/src/environment/raw-key/normalize.ts`, `packages/tui/tests/environment.test.ts` | | Red, strikethrough, and border-styled frames | `packages/tui/src/theme/styles.ts`, `packages/tui/src/theme/box.ts` | -| ANSI segment parsing, ANSI-aware wrapping, truncation, Unicode width | `packages/tui/src/strings.ts`, `packages/tui/tests/strings.test.ts` | -| ANSI truncation style cleanup and visible-width markers | `packages/tui/src/strings.ts`, `packages/tui/tests/strings.test.ts` | -| Key-mode search default submission | `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/result.ts`, `packages/tui/tests/search.test.ts` | +| Default box renderer terminal-width cap | `packages/tui/src/theme/box.ts` | +| ANSI segment parsing, ANSI-aware wrapping, truncation, Unicode width | `packages/tui/src/strings.ts`, `packages/tui/src/string-utils/*`, `packages/tui/src/string-utils/ansi/*`, `packages/tui/tests/strings.test.ts` | +| ANSI truncation style cleanup and visible-width markers | `packages/tui/src/string-utils/truncate.ts`, `packages/tui/src/string-utils/width.ts`, `packages/tui/tests/strings.test.ts` | +| Key-mode search default submission | `packages/tui/src/prompts/search/read-single.ts`, `packages/tui/src/prompts/search/read-single/state/*`, `packages/tui/src/prompts/search/read-single/result.ts`, `packages/tui/tests/search.test.ts` | | OpenTUI adapter | `packages/tui/src/opentui.ts` | | Type contracts | `packages/tui/src/types.ts`, `packages/tui/src/contracts/*` | -| Public ESM package runtime and type-consumption surface | `packages/tui/src/index.ts`, `packages/tui/src/form/builder/index.ts`, `packages/tui/src/output/notify.ts`, `packages/tui/src/output/notify/*`, `packages/acceptance/tests/package.test.ts` | -| Data table prompt argument validation layer | `packages/tui/src/output/validators/data-table.ts`, `packages/tui/src/output/data-table.ts`, `packages/tui/tests/table.test.ts` | -| Table row cell normalization validation layer | `packages/tui/src/output/validators/table.ts`, `packages/tui/src/output/table.ts`, `packages/tui/tests/table.test.ts` | -| Choice option shape validation layer | `packages/tui/src/concerns/validators/choice.ts`, `packages/tui/src/concerns/choices.ts`, `packages/tui/tests/choices.test.ts` | -| Required value validation layer | `packages/tui/src/validators/required.ts`, `packages/tui/tests/prompt.test.ts` | +| Public ESM package runtime, type-consumption surface, and domain subpath exports | `packages/tui/package.json`, `packages/tui/src/index.ts`, `packages/tui/src/prompts.ts`, `packages/tui/src/prompts/*`, `packages/tui/src/form/builder/index.ts`, `packages/tui/src/output.ts`, `packages/tui/src/output/*`, `packages/tui/src/status.ts`, `packages/tui/src/status/*`, `packages/tui/src/output/notify.ts`, `packages/tui/src/output/notify/*`, `packages/acceptance/tests/package.test.ts` | +| Provision workspace and tool cache isolation | `provision/go`, `provision/ts`, `provision/.cache`, `package.json`, `pnpm-workspace.yaml`, `turbo.json`, `.npmrc` | +| Data table prompt argument validation layer | `packages/tui/src/output/validators/data-table.ts`, `packages/tui/src/output/data-table.ts`, `packages/tui/src/output/data-table/reader/types.ts`, `packages/tui/tests/table.test.ts` | +| Data table filter callback lifecycle | `packages/tui/src/contracts/output.ts`, `packages/tui/src/output/data-table/rows.ts`, `packages/tui/src/output/data-table/rows/*`, `packages/tui/src/output/data-table/reader/state.ts`, `packages/tui/src/output/data-table/reader/state/*`, `packages/tui/src/output/data-table.ts` | +| Data table search title and non-empty query filter lifecycle | `packages/tui/src/output/data-table/render.ts`, `packages/tui/src/output/data-table/rows.ts`, `packages/tui/src/output/data-table/rows/*`, `packages/tui/src/output/data-table/reader/state.ts`, `packages/tui/src/output/data-table/reader/state/*`, `packages/tui/src/output/data-table/reader/session.ts`, `packages/tui/src/output/data-table/reader/session/*`, `packages/tui/tests/form.test.ts` | +| Table row cell normalization validation layer | `packages/tui/src/output/validators/table.ts`, `packages/tui/src/output/validators/table/*`, `packages/tui/src/output/table.ts`, `packages/tui/tests/table.test.ts` | +| Choice option shape validation layer | `packages/tui/src/concerns/validators/choice.ts`, `packages/tui/src/concerns/choice-normalize.ts`, `packages/tui/src/concerns/choices.ts`, `packages/tui/tests/choices.test.ts` | +| Required value and message validation layer | `packages/tui/src/validators/required.ts`, `packages/tui/tests/prompt.test.ts` | +| Keyboard event normalization and key aliases | `packages/tui/src/key/event.ts`, `packages/tui/src/key/event/*`, `packages/tui/tests/key.test.ts` | | Key match validation layer | `packages/tui/src/key/validators/match.ts`, `packages/tui/src/key/match.ts`, `packages/tui/tests/key.test.ts` | -| Form builder number empty-default lifecycle | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/tests/form.test.ts` | +| Form builder number empty-default lifecycle | `packages/tui/src/form/builder/prompts/basic.ts`, `packages/tui/src/form/builder/prompts/basic/*`, `packages/tui/src/form/builder/prompts/basic/number/*`, `packages/tui/tests/form.test.ts` | +| Prompt fallback and global validation lifecycle hooks | `packages/tui/src/prompt/fallback.ts`, `packages/tui/src/prompt/validate-using.ts`, `packages/tui/src/prompt/lifecycle.ts`, `packages/tui/src/prompts/*`, `packages/tui/src/output/data-table.ts` | +| Pipe-style default table rendering | `packages/tui/src/theme.ts`, `packages/tui/src/theme/*`, `packages/tui/src/output/table.ts`, `packages/tui/src/output/data-table/render.ts` | +| Default theme symbol, prompt, validation, choice, and table rendering concerns | `packages/tui/src/theme.ts`, `packages/tui/src/theme/*` | -## Remaining Exact-Parity Work +## Completion Audit -The following reference areas still need full line-by-line behavioral mapping in -later phases: +Current implementation evidence: -- Form builder remaining method-surface and validation parity -- Prompt lifecycle -- Default theme -- Feature parity tests +- Public runtime helpers are exported from `packages/tui/src/index.ts` and + verified by `packages/acceptance/tests/package.test.ts`. +- Prompt, form, output, status, terminal, string, key, typed-value, and package + consumption behavior is covered by the local test suites under + `packages/tui/tests` and `packages/acceptance/tests`. +- Form builder method-surface and validation concerns are split under + `packages/tui/src/form/builder/*` with validator layers under + `packages/tui/src/form/builder/**/validators/*`. +- Prompt implementations are split by concern under `packages/tui/src/prompts/*` + and shared validation layers live under local `validators/*` directories. +- Source imports use package aliases instead of relative paths. +- The package is ESM-only through `packages/tui/package.json` `type` and + `exports`. +- CI is configured in `.github/workflows/ci.yml` as a manual-only + `workflow_dispatch` workflow while validation is being confirmed locally. + +Latest local verification: + +- `pnpm test` +- `pnpm typecheck` +- `pnpm build` +- `make format-all` ## Documented Deviations diff --git a/package.json b/package.json index 5c4cbe50..b3f39def 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,12 @@ "private": true, "type": "module", "scripts": { - "build": "turbo build", - "test": "turbo test", - "typecheck": "turbo typecheck" + "build": "XDG_CACHE_HOME=provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=provision/.cache/playwright turbo run build --cache-dir provision/.cache/turbo --log-file provision/.cache/turbo/logs/build.json --output-logs=none", + "dev": "make dev", + "format": "make format", + "format-all": "make format-all", + "test": "XDG_CACHE_HOME=provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=provision/.cache/playwright turbo run test --cache-dir provision/.cache/turbo --log-file provision/.cache/turbo/logs/test.json --output-logs=full", + "typecheck": "XDG_CACHE_HOME=provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=provision/.cache/playwright turbo run typecheck --cache-dir provision/.cache/turbo --log-file provision/.cache/turbo/logs/typecheck.json --output-logs=none" }, "devDependencies": { "@ollin/artefacts": "workspace:*", diff --git a/packages/acceptance/package.json b/packages/acceptance/package.json index fe784147..7a184d1f 100644 --- a/packages/acceptance/package.json +++ b/packages/acceptance/package.json @@ -4,8 +4,8 @@ "private": true, "type": "module", "scripts": { - "test": "vitest run --config vitest.config.ts", - "typecheck": "tsc -p tsconfig.json --noEmit" + "test": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright vitest run --config vitest.config.ts", + "typecheck": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { "@ollin/tui": "workspace:*", diff --git a/packages/acceptance/tests/package.test.ts b/packages/acceptance/tests/package.test.ts index acb469f3..53d40884 100644 --- a/packages/acceptance/tests/package.test.ts +++ b/packages/acceptance/tests/package.test.ts @@ -1,12 +1,14 @@ import { execFileSync } from 'node:child_process'; -import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; -import { dirname, resolve } from 'node:path'; +import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; const testPath = dirname(fileURLToPath(import.meta.url)); -const acceptancePath = resolve(testPath, '..'); -const workspacePath = resolve(acceptancePath, '../..'); +const acceptancePath = dirname(testPath); +const packagesPath = dirname(acceptancePath); +const workspacePath = dirname(packagesPath); +const acceptanceCachePath = join(workspacePath, 'provision', '.cache', 'vitest', 'acceptance'); describe('package consumption', () => { it('imports the built public entrypoint through ESM package resolution', () => { @@ -25,7 +27,7 @@ describe('package consumption', () => { ); expect(output.trim()).toBe('function,function,function'); - }); + }, 30_000); it('exports the complete runtime helper surface from the root entrypoint', () => { execFileSync('pnpm', ['--filter', '@ollin/tui', 'build'], { @@ -59,6 +61,8 @@ describe('package consumption', () => { 'erasePreviousLines', 'error', 'executeNotificationCommand', + 'fallbackUsing', + 'fallbackWhen', 'foregroundColor', 'form', 'grid', @@ -99,6 +103,7 @@ describe('package consumption', () => { 'textarea', 'title', 'truncate', + 'validateUsing', 'visibleWidth', 'warning', 'withPromptEnvironment', @@ -124,7 +129,7 @@ describe('package consumption', () => { ); expect(JSON.parse(output) as { missing: string[] }).toEqual({ missing: [], count: expectedExports.length }); - }); + }, 30_000); it('exports public helper types from the built root entrypoint', () => { execFileSync('pnpm', ['--filter', '@ollin/tui', 'build'], { @@ -132,10 +137,17 @@ describe('package consumption', () => { stdio: 'pipe', }); - const consumerDirectory = mkdtempSync(resolve(acceptancePath, '.types-')); - const consumerPath = resolve(consumerDirectory, 'consumer.ts'); + const typecheckCachePath = join(acceptanceCachePath, 'types'); + + mkdirSync(typecheckCachePath, { recursive: true }); + + const consumerDirectory = mkdtempSync(join(typecheckCachePath, 'consumer-')); + const packageScopeDirectory = join(consumerDirectory, 'node_modules', '@ollin'); + const consumerPath = join(consumerDirectory, 'consumer.ts'); try { + mkdirSync(packageScopeDirectory, { recursive: true }); + symlinkSync(join(packagesPath, 'tui'), join(packageScopeDirectory, 'tui'), 'dir'); writeFileSync( consumerPath, ` @@ -215,5 +227,5 @@ describe('package consumption', () => { } finally { rmSync(consumerDirectory, { force: true, recursive: true }); } - }); + }, 30_000); }); diff --git a/packages/acceptance/vitest.config.ts b/packages/acceptance/vitest.config.ts index 19132acd..17427c87 100644 --- a/packages/acceptance/vitest.config.ts +++ b/packages/acceptance/vitest.config.ts @@ -1,10 +1,16 @@ +import { dirname, join } from 'node:path'; import { defineConfig } from 'vitest/config'; import { fileURLToPath } from 'node:url'; -const sourcePath = fileURLToPath(new URL('../tui/src/index.ts', import.meta.url)); -const internalSourcePath = fileURLToPath(new URL('../tui/src/$1', import.meta.url)); +const packagePath = dirname(fileURLToPath(import.meta.url)); +const packagesPath = dirname(packagePath); +const workspacePath = dirname(packagesPath); +const cachePath = join(workspacePath, 'provision', '.cache', 'vitest', 'acceptance'); +const sourcePath = join(packagesPath, 'tui', 'src', 'index.ts'); +const internalSourcePath = join(packagesPath, 'tui', 'src', '$1'); export default defineConfig({ + cacheDir: cachePath, resolve: { alias: [ { diff --git a/packages/artefacts/package.json b/packages/artefacts/package.json index d44bb416..af007a96 100644 --- a/packages/artefacts/package.json +++ b/packages/artefacts/package.json @@ -11,7 +11,7 @@ "./tsconfig/*.json": "./tsconfig/*.json" }, "scripts": { - "typecheck": "tsc -p tsconfig.json --noEmit" + "typecheck": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright tsc -p tsconfig.json --noEmit" }, "devDependencies": { "@ollin/tsconfig": "workspace:*", diff --git a/packages/artefacts/src/index.ts b/packages/artefacts/src/index.ts index 479bc05a..740a539e 100644 --- a/packages/artefacts/src/index.ts +++ b/packages/artefacts/src/index.ts @@ -1,11 +1,33 @@ -import { resolve } from 'node:path'; +import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; -export const artefactsRoot = resolve(fileURLToPath(new URL('..', import.meta.url))); +export const artefactsRoot = dirname(dirname(fileURLToPath(import.meta.url))); + +export const workspaceRoot = dirname(dirname(artefactsRoot)); + +export const provisionRoot = resolve(workspaceRoot, 'provision'); export const artefactsPath = (...segments: string[]): string => resolve(artefactsRoot, ...segments); -export const cacheDir = (...segments: string[]): string => artefactsPath('.cache', ...segments); +export const cacheDir = (...segments: string[]): string => resolve(provisionRoot, '.cache', ...segments); + +export const toolBinCacheDir = (...segments: string[]): string => cacheDir('bin', ...segments); + +export const goBuildCacheDir = (...segments: string[]): string => cacheDir('go-build', ...segments); + +export const goModCacheDir = (...segments: string[]): string => cacheDir('go-mod', ...segments); + +export const goTmpCacheDir = (...segments: string[]): string => cacheDir('go-tmp', ...segments); + +export const playwrightCacheDir = (...segments: string[]): string => cacheDir('playwright', ...segments); + +export const tsBuildCacheDir = (...segments: string[]): string => cacheDir('tsbuild', ...segments); + +export const turboCacheDir = (...segments: string[]): string => cacheDir('turbo', ...segments); + +export const vitestCacheDir = (...segments: string[]): string => cacheDir('vitest', ...segments); + +export const xdgCacheDir = (...segments: string[]): string => cacheDir('xdg', ...segments); export const distDir = (...segments: string[]): string => artefactsPath('dist', ...segments); diff --git a/packages/artefacts/tsconfig.json b/packages/artefacts/tsconfig.json index 1d7ebf18..7519ca98 100644 --- a/packages/artefacts/tsconfig.json +++ b/packages/artefacts/tsconfig.json @@ -2,7 +2,7 @@ "extends": "@ollin/tsconfig/base.json", "compilerOptions": { "baseUrl": ".", - "tsBuildInfoFile": ".cache/tsbuild/artefacts.tsbuildinfo", + "tsBuildInfoFile": "../../provision/.cache/tsbuild/artefacts.tsbuildinfo", "paths": { "#artefacts/*": ["./src/*"] } diff --git a/packages/artefacts/tsconfig/acceptance.json b/packages/artefacts/tsconfig/acceptance.json index fe189ce5..7de753e2 100644 --- a/packages/artefacts/tsconfig/acceptance.json +++ b/packages/artefacts/tsconfig/acceptance.json @@ -1,5 +1,5 @@ { "compilerOptions": { - "tsBuildInfoFile": "../.cache/tsbuild/acceptance.tsbuildinfo" + "tsBuildInfoFile": "../../../provision/.cache/tsbuild/acceptance.tsbuildinfo" } } diff --git a/packages/artefacts/tsconfig/tui.json b/packages/artefacts/tsconfig/tui.json index 70bc18e1..058cde9e 100644 --- a/packages/artefacts/tsconfig/tui.json +++ b/packages/artefacts/tsconfig/tui.json @@ -1,5 +1,5 @@ { "compilerOptions": { - "tsBuildInfoFile": "../.cache/tsbuild/tui.tsbuildinfo" + "tsBuildInfoFile": "../../../provision/.cache/tsbuild/tui.tsbuildinfo" } } diff --git a/packages/docs/components.json b/packages/docs/components.json index 7309152d..acd2bf12 100644 --- a/packages/docs/components.json +++ b/packages/docs/components.json @@ -4,7 +4,7 @@ "typescript": true, "tailwind": { "config": "", - "css": "src/.vitepress/theme/styles.css", + "css": "vitepress/theme/styles.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" diff --git a/packages/docs/package.json b/packages/docs/package.json index db4bd017..5ea6d6c4 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -4,12 +4,12 @@ "private": true, "type": "module", "scripts": { - "api": "typedoc --options typedoc.json && cp src/api/README.md src/api/index.md", - "build": "pnpm api && vitepress build src", - "dev": "pnpm api && vitepress dev src --host 127.0.0.1", - "preview": "vitepress preview src --host 127.0.0.1", - "test": "vitest run --config vitest.config.ts", - "typecheck": "tsc -p tsconfig.json --noEmit" + "api": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright typedoc --options typedoc.json && cp src/api/README.md src/api/index.md", + "build": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright pnpm api && XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright vitepress build src --config vitepress/config.ts", + "dev": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright pnpm api && XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright vitepress dev src --config vitepress/config.ts --host 127.0.0.1", + "preview": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright vitepress preview src --config vitepress/config.ts --host 127.0.0.1", + "test": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright vitest run --config vitest.config.ts", + "typecheck": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { "@fontsource/geist-mono": "^5.2.8", diff --git a/packages/docs/src/guide/introduction.md b/packages/docs/src/guide/introduction.md index 7d3b12f0..61b69e75 100644 --- a/packages/docs/src/guide/introduction.md +++ b/packages/docs/src/guide/introduction.md @@ -12,7 +12,9 @@ It also exports `form`, output helpers such as `info`, `warning`, `table`, and ` ## Package Overview -The documentation follows the public package surface. Use the guide for task-oriented examples and the API reference for generated type and overload details. +The package is implemented as TypeScript-first ESM and exposes its supported runtime surface through the public `@ollin/tui` entrypoint. The current implementation includes prompt helpers, form composition, output and status helpers, terminal controls, string and key utilities, OpenTUI text-frame rendering, and deterministic environments for tests or non-standard runtimes. + +The documentation follows that public package surface. Use the guide for task-oriented examples and the API reference for generated type and overload details. Runtime behavior and package consumption are covered by local tests, with the detailed reference parity map and completion audit tracked in `UPSTREAM.md`. ## Complete CLI Flow diff --git a/packages/docs/src/index.md b/packages/docs/src/index.md index 2c5f555c..d76ef722 100644 --- a/packages/docs/src/index.md +++ b/packages/docs/src/index.md @@ -6,6 +6,12 @@ Start with the [guide](/guide/introduction), or open the generated [API referenc These docs cover the public API and common command-line workflows. +## Current Stage + +`@ollin/tui` is currently implemented as a TypeScript ESM package with a public root entrypoint for prompts, forms, output helpers, status indicators, terminal helpers, string and key utilities, and deterministic prompt environments. + +The guide pages describe the tracked public surface, while the generated API reference is built from the package types. Runtime and type-consumption behavior is covered by the workspace test suites, including the acceptance package. The detailed parity map and completion audit live in `UPSTREAM.md`. + ## Build a Prompted Command ```ts diff --git a/packages/docs/tests/docs.test.ts b/packages/docs/tests/docs.test.ts index e00bcd7b..caa2b7e7 100644 --- a/packages/docs/tests/docs.test.ts +++ b/packages/docs/tests/docs.test.ts @@ -1,12 +1,14 @@ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; -import { extname, join, relative } from 'node:path'; +import { dirname, extname, join, relative } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; import { guideSections } from '@docs-config'; -const packagePath = new URL('..', import.meta.url); -const sourcePath = new URL('../src/', import.meta.url); -const examplesPath = new URL('../examples/', import.meta.url); -const vitepressPath = new URL('../src/.vitepress/', import.meta.url); +const testsPath = dirname(fileURLToPath(import.meta.url)); +const packagePath = dirname(testsPath); +const sourcePath = join(packagePath, 'src'); +const examplesPath = join(packagePath, 'examples'); +const vitepressPath = join(sourcePath, '.vitepress'); const blockedTokens = ['TODO', 'lorem', 'fake', 'mocked', 'stubbed']; const importSpecifierPattern = /\b(?:import|export)\b(?:[\s\S]*?\bfrom\s*)?['"]([^'"]+)['"]|import\(\s*['"]([^'"]+)['"]\s*\)/gu; @@ -39,18 +41,18 @@ const walk = (directory: string): string[] => return statSync(path).isDirectory() ? walk(path) : [path]; }); -const markdownFiles = (): string[] => walk(sourcePath.pathname).filter((path) => extname(path) === '.md'); -const exampleFiles = (): string[] => walk(examplesPath.pathname).filter((path) => extname(path) === '.ts'); +const markdownFiles = (): string[] => walk(sourcePath).filter((path) => extname(path) === '.md'); +const exampleFiles = (): string[] => walk(examplesPath).filter((path) => extname(path) === '.ts'); const docsCodeFiles = (): string[] => - [...walk(vitepressPath.pathname), ...walk(new URL('../tests/', import.meta.url).pathname)] + [...walk(vitepressPath), ...walk(testsPath)] .filter((path) => ['.ts', '.vue'].includes(extname(path))) .filter((path) => !path.includes('/.vitepress/cache/') && !path.includes('/.vitepress/dist/')); describe('docs structure', () => { it('has a markdown page for every guide section', () => { for (const section of guideSections) { - const path = join(sourcePath.pathname, `${section.link.replace(/^\//u, '')}.md`); + const path = join(sourcePath, `${section.link.replace(/^\//u, '')}.md`); expect(existsSync(path), `${section.text} is missing at ${path}`).toBe(true); } @@ -73,7 +75,7 @@ describe('docs structure', () => { const content = readFileSync(path, 'utf8'); for (const token of blockedTokens) { - expect(content, `${relative(packagePath.pathname, path)} contains ${token}`).not.toContain(token); + expect(content, `${relative(packagePath, path)} contains ${token}`).not.toContain(token); } } }); @@ -82,8 +84,8 @@ describe('docs structure', () => { for (const path of markdownFiles().filter((file) => file.includes('/guide/'))) { const content = readFileSync(path, 'utf8'); - expect(content, `${relative(packagePath.pathname, path)} needs inline TypeScript usage`).toContain('```ts'); - expect(content, `${relative(packagePath.pathname, path)} should not send readers to source fixtures`).not.toMatch(/\.\.\/\.\.\/examples\//u); + expect(content, `${relative(packagePath, path)} needs inline TypeScript usage`).toContain('```ts'); + expect(content, `${relative(packagePath, path)} should not send readers to source fixtures`).not.toMatch(/\.\.\/\.\.\/examples\//u); } }); @@ -94,7 +96,7 @@ describe('docs structure', () => { for (const match of content.matchAll(importSpecifierPattern)) { const specifier = match[1] ?? match[2] ?? ''; - expect(specifier, `${relative(packagePath.pathname, path)} imports ${specifier}`).not.toMatch(/^\.\.?(?:\/|$)/u); + expect(specifier, `${relative(packagePath, path)} imports ${specifier}`).not.toMatch(/^\.\.?(?:\/|$)/u); } } }); diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json index 07841806..cc1e8a5b 100644 --- a/packages/docs/tsconfig.json +++ b/packages/docs/tsconfig.json @@ -4,17 +4,17 @@ "baseUrl": ".", "paths": { "@docs/*": ["src/*"], - "@docs-components/*": ["src/.vitepress/theme/components/*"], - "@docs-config": ["src/.vitepress/config.ts"], - "@docs-lib/*": ["src/.vitepress/theme/lib/*"], + "@docs-components/*": ["vitepress/theme/components/*"], + "@docs-config": ["vitepress/config.ts"], + "@docs-lib/*": ["vitepress/theme/lib/*"], "@docs-tests/*": ["tests/*"], - "@docs-theme/*": ["src/.vitepress/theme/*"], - "@docs-ui/*": ["src/.vitepress/theme/components/ui/*"], + "@docs-theme/*": ["vitepress/theme/*"], + "@docs-ui/*": ["vitepress/theme/components/ui/*"], "@ollin/tui": ["../tui/src/index.ts"], "#tui/*": ["../tui/src/*"], "#tui/prompts/*": ["../tui/src/prompts/*"] }, - "tsBuildInfoFile": "../artefacts/.cache/tsbuild/docs.tsbuildinfo" + "tsBuildInfoFile": "../../provision/.cache/tsbuild/docs.tsbuildinfo" }, - "include": ["examples/**/*.ts", "src/.vitepress/**/*.ts", "tests/**/*.ts", "vitest.config.ts", "../tui/src/**/*.ts"] + "include": ["examples/**/*.ts", "tests/**/*.ts", "vitepress/**/*.ts", "vitest.config.ts", "../tui/src/**/*.ts"] } diff --git a/packages/docs/src/.vitepress/config.ts b/packages/docs/vitepress/config.ts similarity index 93% rename from packages/docs/src/.vitepress/config.ts rename to packages/docs/vitepress/config.ts index 11b84a7b..381e78ad 100644 --- a/packages/docs/src/.vitepress/config.ts +++ b/packages/docs/vitepress/config.ts @@ -2,11 +2,12 @@ import { fileURLToPath } from 'node:url'; import tailwindcss from '@tailwindcss/vite'; import { defineConfig } from 'vitepress'; -const sourcePath = fileURLToPath(new URL('..', import.meta.url)); +const sourcePath = fileURLToPath(new URL('../src/', import.meta.url)); const themePath = fileURLToPath(new URL('theme', import.meta.url)); const themeComponentsPath = fileURLToPath(new URL('theme/components', import.meta.url)); const themeLibPath = fileURLToPath(new URL('theme/lib', import.meta.url)); const themeUiPath = fileURLToPath(new URL('theme/components/ui', import.meta.url)); +const viteCachePath = fileURLToPath(new URL('../../../provision/.cache/vitepress/docs', import.meta.url)); const tailwindPlugin = tailwindcss() as never; export const guideSections = [ @@ -46,6 +47,7 @@ export default defineConfig({ cleanUrls: true, lastUpdated: true, vite: { + cacheDir: viteCachePath, plugins: [tailwindPlugin], resolve: { alias: [ diff --git a/packages/docs/src/.vitepress/theme/components/TerminalOutput.vue b/packages/docs/vitepress/theme/components/TerminalOutput.vue similarity index 92% rename from packages/docs/src/.vitepress/theme/components/TerminalOutput.vue rename to packages/docs/vitepress/theme/components/TerminalOutput.vue index ec1558b1..87dc66ef 100644 --- a/packages/docs/src/.vitepress/theme/components/TerminalOutput.vue +++ b/packages/docs/vitepress/theme/components/TerminalOutput.vue @@ -33,6 +33,7 @@ const props = withDefaults( ); const viewport = ref(null); + let terminal: Terminal | null = null; let observer: IntersectionObserver | null = null; let timers: ReturnType[] = []; @@ -230,21 +231,9 @@ watch(output, () => {