From 02077a33558dac72c7142352dec3c994c8004772 Mon Sep 17 00:00:00 2001 From: Gustavo Ocanto Date: Wed, 17 Jun 2026 15:02:56 +0800 Subject: [PATCH 1/4] chore: remove Go shell bridge and adopt infra/ workspace conventions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the Go shell bridge (provision/go, the @ollin/shell portal and the Go TUI reimplementation) — it was a real-terminal harness, not part of the shipped runtime — and prune its now-dead cache plumbing (bin/go-build/ go-mod/go-tmp). Rename provision/ -> infra/ and adopt the sibling sasu repo's infra conventions by consolidating @ollin/artefacts + @ollin/tsconfig + the old provision-ts helpers into a single @ollin/infra package: - infra/src/index.ts: cache/path helpers (infraRoot, cacheDir, distDir, workspacePath, ...) - infra/tsconfig/{base,tui,acceptance}.json: centralized configs exported via @ollin/infra/tsconfig/*.json - infra/.cache: single tool-cache root; .npmrc store-dir -> infra/.cache/ pnpm-store - infra/make/*.mk: modular Makefile with the root Makefile as a transparent forwarder Rewire all consumers (root, tui, docs, acceptance) onto @ollin/infra, repoint every provision/.cache path to infra/.cache, drop the deleted packages from the workspace, and update UPSTREAM.md. Verified: pnpm install / typecheck / build / test all green (tui 401, docs 5, acceptance 10 incl. the ESM package-consumption test); make help reaches infra/make/* via the forwarder. --- .gitignore | 5 +- .npmrc | 2 +- Makefile | 71 +- UPSTREAM.md | 2 +- {provision => infra}/.gitignore | 0 infra/README.md | 25 + infra/make/Makefile | 15 + infra/make/dev.mk | 5 + infra/make/format.mk | 8 + infra/make/fresh.mk | 24 + infra/make/shared.mk | 29 + infra/make/turbo.mk | 5 + {packages/artefacts => infra}/package.json | 8 +- infra/src/index.ts | 27 + infra/tsconfig.json | 11 + infra/tsconfig/acceptance.json | 5 + {packages => infra}/tsconfig/base.json | 0 infra/tsconfig/tui.json | 5 + package.json | 9 +- packages/acceptance/package.json | 7 +- packages/acceptance/tests/package.test.ts | 2 +- packages/acceptance/tsconfig.json | 2 +- packages/acceptance/vitest.config.ts | 2 +- packages/artefacts/src/index.ts | 34 - packages/artefacts/tsconfig.json | 11 - packages/artefacts/tsconfig/acceptance.json | 5 - packages/artefacts/tsconfig/tui.json | 5 - packages/docs/package.json | 14 +- packages/docs/tsconfig.json | 4 +- packages/docs/vitepress/config.ts | 2 +- packages/docs/vitest.config.ts | 2 +- packages/tsconfig/package.json | 9 - packages/tui/package.json | 9 +- packages/tui/tsconfig.build.json | 2 +- packages/tui/tsconfig.json | 2 +- packages/tui/vitest.config.ts | 2 +- pnpm-lock.yaml | 56 +- pnpm-workspace.yaml | 3 +- provision/README.md | 24 - provision/go/.gitignore | 2 - provision/go/exports.go | 178 ----- provision/go/exports_test.go | 50 -- provision/go/go.mod | 23 - provision/go/go.sum | 33 - .../go/internal/environment/environment.go | 96 --- .../internal/environment/environment_test.go | 121 --- provision/go/internal/environment/errors.go | 29 - .../go/internal/environment/memory_output.go | 33 - provision/go/internal/environment/scope.go | 80 -- .../go/internal/environment/scripted_input.go | 34 - provision/go/internal/environment/stdio.go | 89 --- .../go/internal/environment/stdio_test.go | 43 -- provision/go/internal/form/builder.go | 148 ---- provision/go/internal/form/form_test.go | 214 ----- provision/go/internal/form/output.go | 87 --- provision/go/internal/form/previous.go | 55 -- provision/go/internal/form/prompts.go | 111 --- provision/go/internal/form/responses.go | 70 -- provision/go/internal/form/revert.go | 58 -- provision/go/internal/form/status.go | 30 - provision/go/internal/key/key.go | 175 ----- provision/go/internal/key/key_test.go | 61 -- provision/go/internal/output/datatable.go | 300 -------- provision/go/internal/output/notes.go | 96 --- provision/go/internal/output/notify.go | 90 --- provision/go/internal/output/output_test.go | 178 ----- provision/go/internal/output/table.go | 152 ---- provision/go/internal/output/terminal.go | 14 - provision/go/internal/prompt/lifecycle.go | 71 -- provision/go/internal/prompt/validation.go | 90 --- provision/go/internal/prompts/basic_test.go | 260 ------- provision/go/internal/prompts/choices.go | 689 ----------------- provision/go/internal/prompts/choices_test.go | 249 ------ provision/go/internal/prompts/number.go | 230 ------ provision/go/internal/prompts/render.go | 218 ------ .../go/internal/prompts/search_suggest.go | 728 ------------------ provision/go/internal/prompts/text.go | 252 ------ provision/go/internal/status/frame.go | 21 - provision/go/internal/status/progress.go | 154 ---- provision/go/internal/status/spinner.go | 52 -- provision/go/internal/status/status_test.go | 194 ----- provision/go/internal/status/stream.go | 133 ---- provision/go/internal/status/task.go | 205 ----- provision/go/internal/strings/strings.go | 300 -------- provision/go/internal/strings/strings_test.go | 97 --- provision/go/internal/terminal/terminal.go | 93 --- .../go/internal/terminal/terminal_test.go | 39 - provision/go/internal/theme/box.go | 79 -- provision/go/internal/theme/styles.go | 63 -- provision/go/internal/theme/theme.go | 121 --- provision/go/internal/theme/theme_test.go | 47 -- provision/go/internal/typedvalue/lines.go | 168 ---- .../go/internal/typedvalue/typedvalue.go | 247 ------ .../go/internal/typedvalue/typedvalue_test.go | 139 ---- provision/go/package.json | 10 - provision/go/portal/config.go | 157 ---- provision/go/portal/main.go | 89 --- provision/go/portal/main_test.go | 104 --- provision/ts/package.json | 17 - provision/ts/src/cache.ts | 26 - provision/ts/src/index.ts | 14 - provision/ts/tsconfig.json | 11 - turbo.json | 2 +- 103 files changed, 225 insertions(+), 8247 deletions(-) rename {provision => infra}/.gitignore (100%) create mode 100644 infra/README.md create mode 100644 infra/make/Makefile create mode 100644 infra/make/dev.mk create mode 100644 infra/make/format.mk create mode 100644 infra/make/fresh.mk create mode 100644 infra/make/shared.mk create mode 100644 infra/make/turbo.mk rename {packages/artefacts => infra}/package.json (59%) create mode 100644 infra/src/index.ts create mode 100644 infra/tsconfig.json create mode 100644 infra/tsconfig/acceptance.json rename {packages => infra}/tsconfig/base.json (100%) create mode 100644 infra/tsconfig/tui.json delete mode 100644 packages/artefacts/src/index.ts delete mode 100644 packages/artefacts/tsconfig.json delete mode 100644 packages/artefacts/tsconfig/acceptance.json delete mode 100644 packages/artefacts/tsconfig/tui.json delete mode 100644 packages/tsconfig/package.json delete mode 100644 provision/README.md delete mode 100644 provision/go/.gitignore delete mode 100644 provision/go/exports.go delete mode 100644 provision/go/exports_test.go delete mode 100644 provision/go/go.mod delete mode 100644 provision/go/go.sum delete mode 100644 provision/go/internal/environment/environment.go delete mode 100644 provision/go/internal/environment/environment_test.go delete mode 100644 provision/go/internal/environment/errors.go delete mode 100644 provision/go/internal/environment/memory_output.go delete mode 100644 provision/go/internal/environment/scope.go delete mode 100644 provision/go/internal/environment/scripted_input.go delete mode 100644 provision/go/internal/environment/stdio.go delete mode 100644 provision/go/internal/environment/stdio_test.go delete mode 100644 provision/go/internal/form/builder.go delete mode 100644 provision/go/internal/form/form_test.go delete mode 100644 provision/go/internal/form/output.go delete mode 100644 provision/go/internal/form/previous.go delete mode 100644 provision/go/internal/form/prompts.go delete mode 100644 provision/go/internal/form/responses.go delete mode 100644 provision/go/internal/form/revert.go delete mode 100644 provision/go/internal/form/status.go delete mode 100644 provision/go/internal/key/key.go delete mode 100644 provision/go/internal/key/key_test.go delete mode 100644 provision/go/internal/output/datatable.go delete mode 100644 provision/go/internal/output/notes.go delete mode 100644 provision/go/internal/output/notify.go delete mode 100644 provision/go/internal/output/output_test.go delete mode 100644 provision/go/internal/output/table.go delete mode 100644 provision/go/internal/output/terminal.go delete mode 100644 provision/go/internal/prompt/lifecycle.go delete mode 100644 provision/go/internal/prompt/validation.go delete mode 100644 provision/go/internal/prompts/basic_test.go delete mode 100644 provision/go/internal/prompts/choices.go delete mode 100644 provision/go/internal/prompts/choices_test.go delete mode 100644 provision/go/internal/prompts/number.go delete mode 100644 provision/go/internal/prompts/render.go delete mode 100644 provision/go/internal/prompts/search_suggest.go delete mode 100644 provision/go/internal/prompts/text.go delete mode 100644 provision/go/internal/status/frame.go delete mode 100644 provision/go/internal/status/progress.go delete mode 100644 provision/go/internal/status/spinner.go delete mode 100644 provision/go/internal/status/status_test.go delete mode 100644 provision/go/internal/status/stream.go delete mode 100644 provision/go/internal/status/task.go delete mode 100644 provision/go/internal/strings/strings.go delete mode 100644 provision/go/internal/strings/strings_test.go delete mode 100644 provision/go/internal/terminal/terminal.go delete mode 100644 provision/go/internal/terminal/terminal_test.go delete mode 100644 provision/go/internal/theme/box.go delete mode 100644 provision/go/internal/theme/styles.go delete mode 100644 provision/go/internal/theme/theme.go delete mode 100644 provision/go/internal/theme/theme_test.go delete mode 100644 provision/go/internal/typedvalue/lines.go delete mode 100644 provision/go/internal/typedvalue/typedvalue.go delete mode 100644 provision/go/internal/typedvalue/typedvalue_test.go delete mode 100644 provision/go/package.json delete mode 100644 provision/go/portal/config.go delete mode 100644 provision/go/portal/main.go delete mode 100644 provision/go/portal/main_test.go delete mode 100644 provision/ts/package.json delete mode 100644 provision/ts/src/cache.ts delete mode 100644 provision/ts/src/index.ts delete mode 100644 provision/ts/tsconfig.json diff --git a/.gitignore b/.gitignore index 59fd5465..b9b7998b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,12 +3,11 @@ node_modules/ **/.turbo/ .cache/ **/.cache/ -provision/.cache/ +infra/.cache/ .DS_Store +.idea/ coverage/ *.tsbuildinfo -packages/artefacts/.logs/ -packages/artefacts/dist/ packages/tui/dist/ packages/docs/src/.vitepress/ packages/docs/src/api/ diff --git a/.npmrc b/.npmrc index 94c622a1..d2986d71 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1 @@ -store-dir=provision/.cache/pnpm/store +store-dir=infra/.cache/pnpm-store diff --git a/Makefile b/Makefile index 87959dc6..c6fab2e3 100644 --- a/Makefile +++ b/Makefile @@ -1,70 +1,19 @@ SHELL := /bin/bash -ROOT_PATH := $(CURDIR) -FMT_IMAGE := ghcr.io/oullin/go-fmt:v0.4.0 -FMT_RUN := docker run --rm \ - --user $$(id -u):$$(id -g) \ - -v $(ROOT_PATH):/work \ - -w /work \ - -e HOST_PROJECT_PATH=$(ROOT_PATH) \ - $(FMT_IMAGE) - -TS_GLOBS := '*.ts' '*.tsx' '*.vue' '*.mts' '*.cts' +INFRA_MAKEFILE := infra/make/Makefile .DEFAULT_GOAL := help -define step - @printf "\n\033[1;36m==>\033[0m \033[1m%s\033[0m\n" "$(1)" -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/Vue files to format."; rm -f "$$tmp"; else xargs -0 $(FMT_RUN) format < "$$tmp"; rc=$$?; rm -f "$$tmp"; exit $$rc; fi -endef - -define run_in - @cd "$(1)" && $(2) -endef - -.PHONY: help dev format format-all fresh - +# Every real target lives in infra/make. This root Makefile is a transparent +# forwarder so existing `make ` commands keep working. +.PHONY: help FORCE help: - @awk 'BEGIN {FS = ":.*?## "; printf "\nUsage: \033[36mmake \033[0m\n"} \ - /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5); next } \ - /^[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) + @$(MAKE) --no-print-directory -f $(INFRA_MAKEFILE) help -##@ Formatting -format: ## Format + lint untracked + modified TS/Vue files via oxfmt/oxlint - $(call run_oxfmt,--others --modified) +Makefile: + @: -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 +%: FORCE + @$(MAKE) --no-print-directory -f $(INFRA_MAKEFILE) $@ -##@ Maintenance -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)"/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) - $(call run_in,$(ROOT_PATH),pnpm install) - $(call step,Building from scratch) - $(call run_in,$(ROOT_PATH),pnpm build) +FORCE: diff --git a/UPSTREAM.md b/UPSTREAM.md index bf3e2130..f387620b 100644 --- a/UPSTREAM.md +++ b/UPSTREAM.md @@ -189,7 +189,7 @@ TypeScript and OpenTUI internals. | OpenTUI adapter | `packages/tui/src/opentui.ts` | | Type contracts | `packages/tui/src/types.ts`, `packages/tui/src/contracts/*` | | 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` | +| Infra workspace and tool cache isolation | `infra`, `infra/.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` | diff --git a/provision/.gitignore b/infra/.gitignore similarity index 100% rename from provision/.gitignore rename to infra/.gitignore diff --git a/infra/README.md b/infra/README.md new file mode 100644 index 00000000..027210b3 --- /dev/null +++ b/infra/README.md @@ -0,0 +1,25 @@ +# Infra Workspace + +The `infra` workspace (`@ollin/infra`) owns project tooling that is not part of +the public package runtime: + +- `src` exposes shared TypeScript path helpers (`infraRoot`, `cacheDir`, + `workspacePath`, …) for the tool cache. +- `tsconfig` holds the centralized TypeScript configs every package extends + (`base.json`, `tui.json`, `acceptance.json`), published via the + `@ollin/infra/tsconfig/*.json` exports. +- `make` holds the modular Makefile. The repo-root `Makefile` is a transparent + forwarder into `infra/make/Makefile`. +- `.cache` is the only mutable tool-cache root for workspace commands. + +Cache buckets are named by tool: + +- `.cache/turbo` +- `.cache/vitest` +- `.cache/tsbuild` +- `.cache/playwright` +- `.cache/xdg` +- `.cache/pnpm-store` + +Do not add package-local cache directories for new tools. Add a named helper in +`infra/src/index.ts` and point the tool at `infra/.cache/`. diff --git a/infra/make/Makefile b/infra/make/Makefile new file mode 100644 index 00000000..b208344c --- /dev/null +++ b/infra/make/Makefile @@ -0,0 +1,15 @@ +SHELL := /bin/bash + +INFRA_MAKE_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +ROOT_PATH := $(abspath $(INFRA_MAKE_DIR)/../..) +INFRA_MAKE_DIR := $(ROOT_PATH)/infra/make + +# Shared helpers/vars first (defines run_in, paths, etc.), then each concern. +# All make target definitions live under infra/make so they have one owner. +include $(INFRA_MAKE_DIR)/shared.mk +include $(INFRA_MAKE_DIR)/turbo.mk +include $(INFRA_MAKE_DIR)/format.mk +include $(INFRA_MAKE_DIR)/dev.mk +include $(INFRA_MAKE_DIR)/fresh.mk + +.DEFAULT_GOAL := help diff --git a/infra/make/dev.mk b/infra/make/dev.mk new file mode 100644 index 00000000..84f70da7 --- /dev/null +++ b/infra/make/dev.mk @@ -0,0 +1,5 @@ +.PHONY: dev + +##@ Development +dev: ## Run the docs dev server + $(call run_in,$(ROOT_PATH),pnpm --filter docs dev) diff --git a/infra/make/format.mk b/infra/make/format.mk new file mode 100644 index 00000000..c5238fb9 --- /dev/null +++ b/infra/make/format.mk @@ -0,0 +1,8 @@ +.PHONY: format format-all + +##@ Formatting +format: ## Format + lint untracked + modified TS/Vue files via oxfmt/oxlint + $(call run_oxfmt,--others --modified) + +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 diff --git a/infra/make/fresh.mk b/infra/make/fresh.mk new file mode 100644 index 00000000..86d8aa1c --- /dev/null +++ b/infra/make/fresh.mk @@ -0,0 +1,24 @@ +.PHONY: fresh + +##@ Maintenance +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)/infra/node_modules" \ + "$(ROOT_PATH)/infra/.cache" \ + "$(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)/infra/.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) + $(call run_in,$(ROOT_PATH),pnpm install) + $(call step,Building from scratch) + $(call run_in,$(ROOT_PATH),pnpm build) diff --git a/infra/make/shared.mk b/infra/make/shared.mk new file mode 100644 index 00000000..f4064b59 --- /dev/null +++ b/infra/make/shared.mk @@ -0,0 +1,29 @@ +FMT_IMAGE := ghcr.io/oullin/go-fmt:v0.4.0 +FMT_RUN := docker run --rm \ + --user $$(id -u):$$(id -g) \ + -v $(ROOT_PATH):/work \ + -w /work \ + -e HOST_PROJECT_PATH=$(ROOT_PATH) \ + $(FMT_IMAGE) + +TS_GLOBS := '*.ts' '*.tsx' '*.vue' '*.mts' '*.cts' + +define step + @printf "\n\033[1;36m==>\033[0m \033[1m%s\033[0m\n" "$(1)" +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/Vue files to format."; rm -f "$$tmp"; else xargs -0 $(FMT_RUN) format < "$$tmp"; rc=$$?; rm -f "$$tmp"; exit $$rc; fi +endef + +define run_in + @cd "$(1)" && $(2) +endef + +.PHONY: help + +help: + @awk 'BEGIN {FS = ":.*?## "; printf "\nUsage: \033[36mmake \033[0m\n"} \ + /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5); next } \ + /^[a-zA-Z0-9_.-]+:.*?##/ { printf " \033[36m%-28s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + @echo "" diff --git a/infra/make/turbo.mk b/infra/make/turbo.mk new file mode 100644 index 00000000..46d03728 --- /dev/null +++ b/infra/make/turbo.mk @@ -0,0 +1,5 @@ +.PHONY: test + +##@ Quality +test: ## Run the workspace test suite from the repo root + $(call run_in,$(ROOT_PATH),pnpm run test) diff --git a/packages/artefacts/package.json b/infra/package.json similarity index 59% rename from packages/artefacts/package.json rename to infra/package.json index af007a96..1c0c7714 100644 --- a/packages/artefacts/package.json +++ b/infra/package.json @@ -1,5 +1,5 @@ { - "name": "@ollin/artefacts", + "name": "@ollin/infra", "version": "0.1.0", "private": true, "type": "module", @@ -10,11 +10,13 @@ }, "./tsconfig/*.json": "./tsconfig/*.json" }, + "imports": { + "#infra/*": "./src/*.ts" + }, "scripts": { - "typecheck": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright tsc -p tsconfig.json --noEmit" + "typecheck": "XDG_CACHE_HOME=.cache/xdg PLAYWRIGHT_BROWSERS_PATH=.cache/playwright tsc -p tsconfig.json --noEmit" }, "devDependencies": { - "@ollin/tsconfig": "workspace:*", "@types/node": "^25.6.2", "typescript": "^6.0.3" } diff --git a/infra/src/index.ts b/infra/src/index.ts new file mode 100644 index 00000000..8e4007cf --- /dev/null +++ b/infra/src/index.ts @@ -0,0 +1,27 @@ +import { fileURLToPath } from 'node:url'; +import { resolve } from 'node:path'; + +// infra/ lives at the repo root and owns the single mutable tool-cache root. +export const infraRoot = resolve(fileURLToPath(new URL('..', import.meta.url))); + +export const cacheRoot = resolve(infraRoot, '.cache'); + +export const repoRoot = resolve(infraRoot, '..'); + +export const repoPath = (...segments: string[]): string => resolve(repoRoot, ...segments); + +export const workspacePath = (...segments: string[]): string => repoPath('packages', ...segments); + +export const cacheDir = (...segments: string[]): string => resolve(cacheRoot, ...segments); + +// Named buckets, one per tool. Add new tools here and point them at +// infra/.cache/ rather than introducing package-local cache directories. +export const turboCacheDir = (...segments: string[]): string => cacheDir('turbo', ...segments); + +export const vitestCacheDir = (...segments: string[]): string => cacheDir('vitest', ...segments); + +export const tsBuildCacheDir = (...segments: string[]): string => cacheDir('tsbuild', ...segments); + +export const playwrightCacheDir = (...segments: string[]): string => cacheDir('playwright', ...segments); + +export const xdgCacheDir = (...segments: string[]): string => cacheDir('xdg', ...segments); diff --git a/infra/tsconfig.json b/infra/tsconfig.json new file mode 100644 index 00000000..5ccb2ab4 --- /dev/null +++ b/infra/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig/base.json", + "compilerOptions": { + "baseUrl": ".", + "tsBuildInfoFile": "./.cache/tsbuild/infra.tsbuildinfo", + "paths": { + "#infra/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts"] +} diff --git a/infra/tsconfig/acceptance.json b/infra/tsconfig/acceptance.json new file mode 100644 index 00000000..fe189ce5 --- /dev/null +++ b/infra/tsconfig/acceptance.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "../.cache/tsbuild/acceptance.tsbuildinfo" + } +} diff --git a/packages/tsconfig/base.json b/infra/tsconfig/base.json similarity index 100% rename from packages/tsconfig/base.json rename to infra/tsconfig/base.json diff --git a/infra/tsconfig/tui.json b/infra/tsconfig/tui.json new file mode 100644 index 00000000..70bc18e1 --- /dev/null +++ b/infra/tsconfig/tui.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "../.cache/tsbuild/tui.tsbuildinfo" + } +} diff --git a/package.json b/package.json index b3f39def..f1677855 100644 --- a/package.json +++ b/package.json @@ -4,16 +4,15 @@ "private": true, "type": "module", "scripts": { - "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", + "build": "XDG_CACHE_HOME=infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=infra/.cache/playwright turbo run build --cache-dir infra/.cache/turbo --log-file infra/.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" + "test": "XDG_CACHE_HOME=infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=infra/.cache/playwright turbo run test --cache-dir infra/.cache/turbo --log-file infra/.cache/turbo/logs/test.json --output-logs=full", + "typecheck": "XDG_CACHE_HOME=infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=infra/.cache/playwright turbo run typecheck --cache-dir infra/.cache/turbo --log-file infra/.cache/turbo/logs/typecheck.json --output-logs=none" }, "devDependencies": { - "@ollin/artefacts": "workspace:*", - "@ollin/tsconfig": "workspace:*", + "@ollin/infra": "workspace:*", "@types/node": "^25.6.2", "turbo": "^2.9.12", "typescript": "^6.0.3", diff --git a/packages/acceptance/package.json b/packages/acceptance/package.json index 7a184d1f..03a49b7c 100644 --- a/packages/acceptance/package.json +++ b/packages/acceptance/package.json @@ -4,16 +4,15 @@ "private": true, "type": "module", "scripts": { - "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" + "test": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitest run --config vitest.config.ts", + "typecheck": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { "@ollin/tui": "workspace:*", "@opentui/core": "^0.4.0" }, "devDependencies": { - "@ollin/artefacts": "workspace:*", - "@ollin/tsconfig": "workspace:*", + "@ollin/infra": "workspace:*", "@types/node": "^25.6.2", "typescript": "^6.0.3", "vitest": "^4.1.5" diff --git a/packages/acceptance/tests/package.test.ts b/packages/acceptance/tests/package.test.ts index 53d40884..c1948458 100644 --- a/packages/acceptance/tests/package.test.ts +++ b/packages/acceptance/tests/package.test.ts @@ -8,7 +8,7 @@ const testPath = dirname(fileURLToPath(import.meta.url)); const acceptancePath = dirname(testPath); const packagesPath = dirname(acceptancePath); const workspacePath = dirname(packagesPath); -const acceptanceCachePath = join(workspacePath, 'provision', '.cache', 'vitest', 'acceptance'); +const acceptanceCachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'acceptance'); describe('package consumption', () => { it('imports the built public entrypoint through ESM package resolution', () => { diff --git a/packages/acceptance/tsconfig.json b/packages/acceptance/tsconfig.json index e10cbc7c..af5e9ab8 100644 --- a/packages/acceptance/tsconfig.json +++ b/packages/acceptance/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": ["@ollin/tsconfig/base.json", "@ollin/artefacts/tsconfig/acceptance.json"], + "extends": ["@ollin/infra/tsconfig/base.json", "@ollin/infra/tsconfig/acceptance.json"], "compilerOptions": { "baseUrl": "..", "paths": { diff --git a/packages/acceptance/vitest.config.ts b/packages/acceptance/vitest.config.ts index 17427c87..68b5f430 100644 --- a/packages/acceptance/vitest.config.ts +++ b/packages/acceptance/vitest.config.ts @@ -5,7 +5,7 @@ import { fileURLToPath } from 'node: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 cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'acceptance'); const sourcePath = join(packagesPath, 'tui', 'src', 'index.ts'); const internalSourcePath = join(packagesPath, 'tui', 'src', '$1'); diff --git a/packages/artefacts/src/index.ts b/packages/artefacts/src/index.ts deleted file mode 100644 index 740a539e..00000000 --- a/packages/artefacts/src/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node: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 => 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); - -export const logDir = (...segments: string[]): string => artefactsPath('.logs', ...segments); diff --git a/packages/artefacts/tsconfig.json b/packages/artefacts/tsconfig.json deleted file mode 100644 index 7519ca98..00000000 --- a/packages/artefacts/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "@ollin/tsconfig/base.json", - "compilerOptions": { - "baseUrl": ".", - "tsBuildInfoFile": "../../provision/.cache/tsbuild/artefacts.tsbuildinfo", - "paths": { - "#artefacts/*": ["./src/*"] - } - }, - "include": ["src/**/*.ts"] -} diff --git a/packages/artefacts/tsconfig/acceptance.json b/packages/artefacts/tsconfig/acceptance.json deleted file mode 100644 index 7de753e2..00000000 --- a/packages/artefacts/tsconfig/acceptance.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "../../../provision/.cache/tsbuild/acceptance.tsbuildinfo" - } -} diff --git a/packages/artefacts/tsconfig/tui.json b/packages/artefacts/tsconfig/tui.json deleted file mode 100644 index 058cde9e..00000000 --- a/packages/artefacts/tsconfig/tui.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "../../../provision/.cache/tsbuild/tui.tsbuildinfo" - } -} diff --git a/packages/docs/package.json b/packages/docs/package.json index 5ea6d6c4..b449467d 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -4,12 +4,12 @@ "private": true, "type": "module", "scripts": { - "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" + "api": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright typedoc --options typedoc.json && cp src/api/README.md src/api/index.md", + "build": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress build src --config vitepress/config.ts", + "dev": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress dev src --config vitepress/config.ts --host 127.0.0.1", + "preview": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress preview src --config vitepress/config.ts --host 127.0.0.1", + "test": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitest run --config vitest.config.ts", + "typecheck": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { "@fontsource/geist-mono": "^5.2.8", @@ -20,7 +20,7 @@ "reka-ui": "^2.9.10" }, "devDependencies": { - "@ollin/tsconfig": "workspace:*", + "@ollin/infra": "workspace:*", "@tailwindcss/vite": "^4.3.0", "@types/node": "^25.6.2", "class-variance-authority": "^0.7.1", diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json index cc1e8a5b..c03fb7e2 100644 --- a/packages/docs/tsconfig.json +++ b/packages/docs/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@ollin/tsconfig/base.json", + "extends": "@ollin/infra/tsconfig/base.json", "compilerOptions": { "baseUrl": ".", "paths": { @@ -14,7 +14,7 @@ "#tui/*": ["../tui/src/*"], "#tui/prompts/*": ["../tui/src/prompts/*"] }, - "tsBuildInfoFile": "../../provision/.cache/tsbuild/docs.tsbuildinfo" + "tsBuildInfoFile": "../../infra/.cache/tsbuild/docs.tsbuildinfo" }, "include": ["examples/**/*.ts", "tests/**/*.ts", "vitepress/**/*.ts", "vitest.config.ts", "../tui/src/**/*.ts"] } diff --git a/packages/docs/vitepress/config.ts b/packages/docs/vitepress/config.ts index 381e78ad..e7885be8 100644 --- a/packages/docs/vitepress/config.ts +++ b/packages/docs/vitepress/config.ts @@ -7,7 +7,7 @@ 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 viteCachePath = fileURLToPath(new URL('../../../infra/.cache/vitepress/docs', import.meta.url)); const tailwindPlugin = tailwindcss() as never; export const guideSections = [ diff --git a/packages/docs/vitest.config.ts b/packages/docs/vitest.config.ts index a6c77d2f..8fc6fa91 100644 --- a/packages/docs/vitest.config.ts +++ b/packages/docs/vitest.config.ts @@ -9,7 +9,7 @@ const docsSourcePath = join(packagePath, 'src'); const docsVitepressPath = join(packagePath, 'vitepress'); const docsThemePath = join(docsVitepressPath, 'theme'); const docsComponentsPath = join(docsThemePath, 'components'); -const cachePath = join(workspacePath, 'provision', '.cache', 'vitest', 'docs'); +const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'docs'); const tuiSourcePath = join(packagesPath, 'tui', 'src', 'index.ts'); const internalSourcePath = join(packagesPath, 'tui', 'src', '$1'); const docsConfigPath = join(docsVitepressPath, 'config.ts'); diff --git a/packages/tsconfig/package.json b/packages/tsconfig/package.json deleted file mode 100644 index d224a6e4..00000000 --- a/packages/tsconfig/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "@ollin/tsconfig", - "version": "0.1.0", - "private": true, - "type": "module", - "exports": { - "./base.json": "./base.json" - } -} diff --git a/packages/tui/package.json b/packages/tui/package.json index c85e8c6a..8e705191 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -188,10 +188,10 @@ } }, "scripts": { - "build": "XDG_CACHE_HOME=../../provision/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../provision/.cache/playwright tsc -p tsconfig.build.json", + "build": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.build.json", "prepack": "pnpm build", - "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" + "test": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitest run --config vitest.config.ts", + "typecheck": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { "@opentui/core": "^0.4.0", @@ -200,8 +200,7 @@ "zod": "^4.4.3" }, "devDependencies": { - "@ollin/artefacts": "workspace:*", - "@ollin/tsconfig": "workspace:*", + "@ollin/infra": "workspace:*", "@types/node": "^25.6.2", "typescript": "^6.0.3", "vitest": "^4.1.5" diff --git a/packages/tui/tsconfig.build.json b/packages/tui/tsconfig.build.json index 4acf1e5e..6b2ea2a1 100644 --- a/packages/tui/tsconfig.build.json +++ b/packages/tui/tsconfig.build.json @@ -8,7 +8,7 @@ "outDir": "dist", "rootDir": "src", "sourceMap": true, - "tsBuildInfoFile": "../../provision/.cache/tsbuild/tui-build.tsbuildinfo" + "tsBuildInfoFile": "../../infra/.cache/tsbuild/tui-build.tsbuildinfo" }, "exclude": ["dist", "tests", "vitest.config.ts"], "include": ["src/**/*.ts"] diff --git a/packages/tui/tsconfig.json b/packages/tui/tsconfig.json index e222b8e8..95773e9b 100644 --- a/packages/tui/tsconfig.json +++ b/packages/tui/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": ["@ollin/tsconfig/base.json", "@ollin/artefacts/tsconfig/tui.json"], + "extends": ["@ollin/infra/tsconfig/base.json", "@ollin/infra/tsconfig/tui.json"], "compilerOptions": { "baseUrl": ".", "paths": { diff --git a/packages/tui/vitest.config.ts b/packages/tui/vitest.config.ts index a5e4b2f4..ca1954b0 100644 --- a/packages/tui/vitest.config.ts +++ b/packages/tui/vitest.config.ts @@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url'; const packagePath = dirname(fileURLToPath(import.meta.url)); const workspacePath = dirname(dirname(packagePath)); -const cachePath = join(workspacePath, 'provision', '.cache', 'vitest', 'tui'); +const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'tui'); const sourcePath = join(packagePath, 'src', '$1'); export default defineConfig({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 93bbd017..da4e5552 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,9 @@ importers: .: devDependencies: - '@ollin/artefacts': + '@ollin/infra': specifier: workspace:* - version: link:packages/artefacts - '@ollin/tsconfig': - specifier: workspace:* - version: link:packages/tsconfig + version: link:infra '@types/node': specifier: ^25.6.2 version: 25.9.2 @@ -27,6 +24,15 @@ importers: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) + infra: + devDependencies: + '@types/node': + specifier: ^25.6.2 + version: 25.9.2 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + packages/acceptance: dependencies: '@ollin/tui': @@ -36,12 +42,9 @@ importers: specifier: ^0.4.0 version: 0.4.0(typescript@6.0.3)(web-tree-sitter@0.25.10) devDependencies: - '@ollin/artefacts': - specifier: workspace:* - version: link:../artefacts - '@ollin/tsconfig': + '@ollin/infra': specifier: workspace:* - version: link:../tsconfig + version: link:../../infra '@types/node': specifier: ^25.6.2 version: 25.9.2 @@ -52,18 +55,6 @@ importers: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) - packages/artefacts: - devDependencies: - '@ollin/tsconfig': - specifier: workspace:* - version: link:../tsconfig - '@types/node': - specifier: ^25.6.2 - version: 25.9.2 - typescript: - specifier: ^6.0.3 - version: 6.0.3 - packages/docs: dependencies: '@fontsource/geist-mono': @@ -85,9 +76,9 @@ importers: specifier: ^2.9.10 version: 2.9.10(vue@3.5.38(typescript@6.0.3)) devDependencies: - '@ollin/tsconfig': + '@ollin/infra': specifier: workspace:* - version: link:../tsconfig + version: link:../../infra '@tailwindcss/vite': specifier: ^4.3.0 version: 4.3.0(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) @@ -128,8 +119,6 @@ importers: specifier: ^3.5.38 version: 3.5.38(typescript@6.0.3) - packages/tsconfig: {} - packages/tui: dependencies: '@opentui/core': @@ -145,12 +134,9 @@ importers: specifier: ^4.4.3 version: 4.4.3 devDependencies: - '@ollin/artefacts': - specifier: workspace:* - version: link:../artefacts - '@ollin/tsconfig': + '@ollin/infra': specifier: workspace:* - version: link:../tsconfig + version: link:../../infra '@types/node': specifier: ^25.6.2 version: 25.9.2 @@ -161,14 +147,6 @@ importers: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) - provision/go: {} - - provision/ts: - devDependencies: - '@ollin/tsconfig': - specifier: workspace:* - version: link:../../packages/tsconfig - packages: '@algolia/abtesting@1.19.0': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a7606e20..cf12e65e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,6 @@ packages: - "packages/*" - - "provision/go" - - "provision/ts" + - "infra" allowBuilds: esbuild: true diff --git a/provision/README.md b/provision/README.md deleted file mode 100644 index 49210c24..00000000 --- a/provision/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Provision Workspace - -The `provision` workspace owns project tooling that is not part of the public -package runtime. - -- `go` contains the local shell bridge package and builds its binary into - `.cache/bin`. -- `ts` contains shared TypeScript helpers for provisioned paths. -- `.cache` is the only mutable tool-cache root for workspace commands. - -Cache buckets are named by tool: - -- `.cache/turbo` -- `.cache/vitest` -- `.cache/tsbuild` -- `.cache/playwright` -- `.cache/xdg` -- `.cache/go-build` -- `.cache/go-mod` -- `.cache/go-tmp` -- `.cache/bin` - -Do not add package-local cache directories for new tools. Add a named helper in -`provision/ts/src/cache.ts` and point the tool at `provision/.cache/`. diff --git a/provision/go/.gitignore b/provision/go/.gitignore deleted file mode 100644 index 3515c4b9..00000000 --- a/provision/go/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.test -coverage.out diff --git a/provision/go/exports.go b/provision/go/exports.go deleted file mode 100644 index 545c15bf..00000000 --- a/provision/go/exports.go +++ /dev/null @@ -1,178 +0,0 @@ -package tui - -import ( - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/form" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/output" - "github.com/oullin/tui/internal/prompt" - "github.com/oullin/tui/internal/prompts" - "github.com/oullin/tui/internal/status" - textutil "github.com/oullin/tui/internal/strings" - "github.com/oullin/tui/internal/terminal" - "github.com/oullin/tui/internal/typedvalue" -) - -type Environment = environment.Environment -type Input = environment.Input -type Output = environment.Output -type Patch = environment.Patch -type MemoryOutput = environment.MemoryOutput -type ScriptedInput = environment.ScriptedInput -type StdioInput = environment.StdioInput -type WriterOutput = environment.WriterOutput - -var CurrentEnvironment = environment.Current -var Configure = environment.Configure -var WithEnvironment = environment.With -var NewMemoryOutput = environment.NewMemoryOutput -var NewScriptedInput = environment.NewScriptedInput -var NewStdioInput = environment.NewStdioInput -var NewWriterOutput = environment.NewWriterOutput -var CancelUsing = environment.CancelUsing -var CancelPrompt = environment.CancelPrompt - -type KeyValue = key.Value -type KeyEvent = key.Event - -var ( - KeyUp = key.Up - KeyDown = key.Down - KeyRight = key.Right - KeyLeft = key.Left - KeyEscape = key.Escape - KeyDelete = key.Delete - KeyBackspace = key.Backspace - KeyEnter = key.Enter - KeySpace = key.Space - KeyTab = key.Tab - KeyShiftTab = key.ShiftTab - KeyCtrlC = key.CtrlC - KeyCtrlA = key.CtrlA - KeyCtrlD = key.CtrlD - KeyCtrlU = key.CtrlU - KeyOptionBackspace = key.OptionBackspace -) - -var KeyFirst = key.First -var KeyFromEvent = key.FromEvent -var KeyOneOf = key.OneOf - -type Required = prompt.Required -type Validator[T any] = prompt.Validator[T] -type PromptValidationError = environment.PromptValidationError - -var ValidationError = prompt.ValidationError -var EnsureValid = prompt.EnsureValid[any] - -type TextOptions = prompts.TextOptions -type NumberOptions = prompts.NumberOptions -type Choice = prompts.Choice -type ChoiceOptions = prompts.ChoiceOptions -type MultiChoiceOptions = prompts.MultiChoiceOptions -type ConfirmOptions = prompts.ConfirmOptions -type SearchSource = prompts.SearchSource -type SearchOptions = prompts.SearchOptions -type MultiSearchOptions = prompts.MultiSearchOptions -type SuggestSource = prompts.SuggestSource -type SuggestOptions = prompts.SuggestOptions - -var Text = prompts.Text -var Textarea = prompts.Textarea -var Password = prompts.Password -var Number = prompts.Number -var Pause = prompts.Pause -var NewStringChoices = prompts.NewStringChoices -var Select = prompts.Select -var Multiselect = prompts.Multiselect -var Confirm = prompts.Confirm -var Search = prompts.Search -var Multisearch = prompts.MultiSearch -var Suggest = prompts.Suggest -var Autocomplete = prompts.Autocomplete - -type FormBuilder = form.Builder -type FormResponses = form.Responses -type FormStep = form.Step -type FormStepFunc = form.StepFunc -type FormConditionFunc = form.ConditionFunc - -var Form = form.New -var FormBool = form.Bool -var ErrFormReverted = form.ErrReverted - -type NoteType = output.NoteType -type TableRow = output.TableRow -type DataTableRow = output.DataTableRow -type DataTableOptions = output.DataTableOptions -type NotificationCommand = output.NotificationCommand -type NotificationRuntime = output.NotificationRuntime - -const ( - NoteAlert = output.NoteAlert - NoteError = output.NoteError - NoteInfo = output.NoteInfo - NoteIntro = output.NoteIntro - NoteOutro = output.NoteOutro - NoteWarning = output.NoteWarning -) - -var Alert = output.Alert -var Clear = output.Clear -var DataTable = output.DataTable -var Error = output.Error -var Grid = output.Grid -var Info = output.Info -var Intro = output.Intro -var Note = output.Note -var NotifyForPlatform = output.NotifyForPlatform -var NotificationCommandFor = output.NotificationCommandFor -var NotificationCommands = output.NotificationCommands -var Outro = output.Outro -var Table = output.Table -var TableObjects = output.TableObjects -var Title = output.Title -var Warning = output.Warning - -type Progress = status.Progress -type Stream = status.Stream -type Logger = status.Logger - -var NewProgress = status.NewProgress -var RunProgress = status.RunProgress[string, string] -var Spin = status.Spin[any] -var NewStream = status.NewStream -var Task = status.Task[any] - -type AnsiSegment = textutil.AnsiSegment - -var VisibleWidth = textutil.VisibleWidth -var Truncate = textutil.Truncate -var ParseAnsiSegments = textutil.ParseAnsiSegments -var ParseAnsiText = textutil.ParseAnsiText -var Wrap = textutil.Wrap - -type TerminalSize = terminal.Size -type TerminalColor = terminal.Color - -var DefaultTerminalSize = terminal.DefaultSize -var ClearTerminalSequence = terminal.ClearSequence -var TerminalTitleSequence = terminal.TitleSequence -var EraseLineSequence = terminal.EraseLineSequence -var ErasePreviousLinesSequence = terminal.ErasePreviousLinesSequence -var CursorToStartSequence = terminal.CursorToStartSequence -var HideCursorSequence = terminal.HideCursorSequence -var ShowCursorSequence = terminal.ShowCursorSequence -var SupportsTrueColor = terminal.SupportsTrueColor -var DefaultForegroundColor = terminal.DefaultForegroundColor -var DefaultBackgroundColor = terminal.DefaultBackgroundColor -var ParseTerminalColor = terminal.ParseColor - -type TypedValueState = typedvalue.State -type AppliedKey = typedvalue.AppliedKey - -var InitialTypedValueState = typedvalue.InitialState -var ApplyTypedKey = typedvalue.ApplyKey -var TypedValueCharacters = typedvalue.Characters -var TypedValueFromCharacters = typedvalue.FromCharacters -var TypedValueCharacterLength = typedvalue.CharacterLength diff --git a/provision/go/exports_test.go b/provision/go/exports_test.go deleted file mode 100644 index 6ade9760..00000000 --- a/provision/go/exports_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package tui_test - -import ( - "strings" - "testing" - - tui "github.com/oullin/tui" -) - -func TestPublicAPIConsumesFormAndOutput(t *testing.T) { - memoryOutput := tui.NewMemoryOutput() - interactive := true - err := tui.WithEnvironment(tui.Patch{ - Input: tui.NewScriptedInput([]string{"A", "d", "a", tui.KeyFirst(tui.KeyEnter)}), - Output: memoryOutput, - ErrorOutput: memoryOutput, - Interactive: &interactive, - }, func() error { - responses, err := tui.Form(). - Text(tui.TextOptions{Message: "Name"}). - Info("Saved", "note"). - Submit() - if err != nil { - return err - } - if responses.At(0) != "Ada" || responses.Named("note") != nil { - t.Fatalf("responses positional=%#v named=%#v", responses.Values(), responses.Names()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - if !strings.Contains(memoryOutput.Text(), "Saved") { - t.Fatalf("output missing note: %q", memoryOutput.Text()) - } -} - -func TestPublicAPIExportsCoreHelpers(t *testing.T) { - if tui.KeyFromEvent(tui.KeyEvent{Name: "u", Ctrl: true}) != tui.KeyFirst(tui.KeyCtrlU) { - t.Fatalf("ctrl-u key mapping mismatch") - } - if tui.VisibleWidth("\x1b[31mTokyo\x1b[39m") != 5 { - t.Fatalf("visible width mismatch") - } - if tui.ClearTerminalSequence() == "" || tui.HideCursorSequence() == "" { - t.Fatalf("terminal sequences should be exported") - } -} diff --git a/provision/go/go.mod b/provision/go/go.mod deleted file mode 100644 index 40c58976..00000000 --- a/provision/go/go.mod +++ /dev/null @@ -1,23 +0,0 @@ -module github.com/oullin/tui - -go 1.26.3 - -require github.com/mattn/go-runewidth v0.0.24 - -require ( - github.com/clipperhouse/uax29/v2 v2.2.0 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect - github.com/sagikazarmark/locafero v0.11.0 // indirect - github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect - github.com/spf13/afero v1.15.0 // indirect - github.com/spf13/cast v1.10.0 // indirect - github.com/spf13/pflag v1.0.10 // indirect - github.com/spf13/viper v1.21.0 // indirect - github.com/subosito/gotenv v1.6.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/term v0.44.0 // indirect - golang.org/x/text v0.28.0 // indirect -) diff --git a/provision/go/go.sum b/provision/go/go.sum deleted file mode 100644 index 47f62dab..00000000 --- a/provision/go/go.sum +++ /dev/null @@ -1,33 +0,0 @@ -github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY= -github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU= -github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= -github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= -github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= -github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= -github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= -github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= -github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/provision/go/internal/environment/environment.go b/provision/go/internal/environment/environment.go deleted file mode 100644 index 195fadb7..00000000 --- a/provision/go/internal/environment/environment.go +++ /dev/null @@ -1,96 +0,0 @@ -package environment - -import "sync" - -type Output interface { - Write(content string) -} - -type Input interface { - ReadKey() (string, bool, error) - ReadLine(message string) (string, error) -} - -type Environment struct { - Input Input - Output Output - ErrorOutput Output - Interactive bool -} - -type Patch struct { - Input Input - Output Output - ErrorOutput Output - Interactive *bool -} - -var ( - current = Environment{ - Input: NewScriptedInput(nil), - Output: NewMemoryOutput(), - ErrorOutput: NewMemoryOutput(), - Interactive: false, - } - currentMu sync.Mutex - scopes = map[uint64][]Environment{} -) - -func Current() Environment { - currentMu.Lock() - defer currentMu.Unlock() - - if scoped, ok := currentScope(); ok { - return scoped - } - - return current -} - -func Configure(patch Patch) { - currentMu.Lock() - defer currentMu.Unlock() - - if scoped, ok := currentScope(); ok { - updateCurrentScope(merge(scoped, patch)) - - return - } - - current = merge(current, patch) -} - -func With(patch Patch, callback func() error) error { - currentMu.Lock() - base := current - if scoped, ok := currentScope(); ok { - base = scoped - } - pushScope(merge(base, patch)) - currentMu.Unlock() - - defer func() { - currentMu.Lock() - popScope() - currentMu.Unlock() - }() - - return callback() -} - -func merge(environment Environment, patch Patch) Environment { - if patch.Input != nil { - environment.Input = patch.Input - } - if patch.Output != nil { - environment.Output = patch.Output - } - if patch.ErrorOutput != nil { - environment.ErrorOutput = patch.ErrorOutput - } - if patch.Interactive != nil { - environment.Interactive = *patch.Interactive - } - - return environment -} diff --git a/provision/go/internal/environment/environment_test.go b/provision/go/internal/environment/environment_test.go deleted file mode 100644 index ea30ef9f..00000000 --- a/provision/go/internal/environment/environment_test.go +++ /dev/null @@ -1,121 +0,0 @@ -package environment - -import ( - "errors" - "testing" -) - -func TestWithRestoresPreviousEnvironmentWhenCallbackFails(t *testing.T) { - output := NewMemoryOutput() - errorOutput := NewMemoryOutput() - previous := Current() - interactive := false - - Configure(Patch{Output: output, ErrorOutput: errorOutput, Interactive: &interactive}) - - scopedOutput := NewMemoryOutput() - scopedInteractive := true - err := With(Patch{Output: scopedOutput, Interactive: &scopedInteractive}, func() error { - current := Current() - if current.Output != scopedOutput { - t.Fatalf("Current().Output was not scoped output") - } - if current.ErrorOutput != errorOutput { - t.Fatalf("Current().ErrorOutput was not preserved") - } - if !current.Interactive { - t.Fatalf("Current().Interactive = false, want true") - } - - return errors.New("failed") - }) - - if err == nil || err.Error() != "failed" { - t.Fatalf("With() error = %v", err) - } - - current := Current() - if current.Output != output { - t.Fatalf("Current().Output was not restored") - } - if current.ErrorOutput != errorOutput { - t.Fatalf("Current().ErrorOutput was not restored") - } - if current.Interactive { - t.Fatalf("Current().Interactive = true, want false") - } - - Configure(Patch{ - Input: previous.Input, - Output: previous.Output, - ErrorOutput: previous.ErrorOutput, - Interactive: &previous.Interactive, - }) -} - -func TestConfigureMergesPartialPromptConfiguration(t *testing.T) { - previous := Current() - output := NewMemoryOutput() - errorOutput := NewMemoryOutput() - interactive := false - - Configure(Patch{Output: output, ErrorOutput: errorOutput, Interactive: &interactive}) - - nextOutput := NewMemoryOutput() - Configure(Patch{Output: nextOutput}) - - current := Current() - if current.Output != nextOutput { - t.Fatalf("Current().Output was not updated") - } - if current.ErrorOutput != errorOutput { - t.Fatalf("Current().ErrorOutput was not preserved") - } - if current.Interactive { - t.Fatalf("Current().Interactive = true, want false") - } - - Configure(Patch{ - Input: previous.Input, - Output: previous.Output, - ErrorOutput: previous.ErrorOutput, - Interactive: &previous.Interactive, - }) -} - -func TestMemoryOutputCapturesAndClears(t *testing.T) { - output := NewMemoryOutput() - - output.Write("first") - output.Write(" second") - - if got := output.Text(); got != "first second" { - t.Fatalf("Text() = %q", got) - } - - output.Clear() - - if got := output.Text(); got != "" { - t.Fatalf("Text() after Clear() = %q", got) - } -} - -func TestScriptedInputDrainsForKeysAndLines(t *testing.T) { - input := NewScriptedInput([]string{"a", "line"}) - - if got, ok, err := input.ReadKey(); err != nil || !ok || got != "a" { - t.Fatalf("ReadKey() = %q, %v, %v", got, ok, err) - } - - if got, err := input.ReadLine("Question"); err != nil || got != "line" { - t.Fatalf("ReadLine() = %q, %v", got, err) - } - - if got, ok, err := input.ReadKey(); err != nil || ok || got != "" { - t.Fatalf("ReadKey(empty) = %q, %v, %v", got, ok, err) - } - - if got, err := input.ReadLine("Question"); err != nil || got != "" { - t.Fatalf("ReadLine(empty) = %q, %v", got, err) - } -} diff --git a/provision/go/internal/environment/errors.go b/provision/go/internal/environment/errors.go deleted file mode 100644 index c0312899..00000000 --- a/provision/go/internal/environment/errors.go +++ /dev/null @@ -1,29 +0,0 @@ -package environment - -import "errors" - -var ErrKeyInputUnsupported = errors.New("key input is unsupported") - -type PromptValidationError struct { - Message string -} - -func (err PromptValidationError) Error() string { - return err.Message -} - -type CancelHandler func(fallback string) (string, error) - -var cancelHandler CancelHandler - -func CancelUsing(handler CancelHandler) { - cancelHandler = handler -} - -func CancelPrompt(fallback string) (string, error) { - if cancelHandler == nil { - return fallback, nil - } - - return cancelHandler(fallback) -} diff --git a/provision/go/internal/environment/memory_output.go b/provision/go/internal/environment/memory_output.go deleted file mode 100644 index f12a2c89..00000000 --- a/provision/go/internal/environment/memory_output.go +++ /dev/null @@ -1,33 +0,0 @@ -package environment - -import "sync" - -type MemoryOutput struct { - mu sync.Mutex - buffer string -} - -func NewMemoryOutput() *MemoryOutput { - return &MemoryOutput{} -} - -func (output *MemoryOutput) Write(content string) { - output.mu.Lock() - defer output.mu.Unlock() - - output.buffer += content -} - -func (output *MemoryOutput) Clear() { - output.mu.Lock() - defer output.mu.Unlock() - - output.buffer = "" -} - -func (output *MemoryOutput) Text() string { - output.mu.Lock() - defer output.mu.Unlock() - - return output.buffer -} diff --git a/provision/go/internal/environment/scope.go b/provision/go/internal/environment/scope.go deleted file mode 100644 index 0451faed..00000000 --- a/provision/go/internal/environment/scope.go +++ /dev/null @@ -1,80 +0,0 @@ -package environment - -import ( - "runtime" - "strconv" - "strings" -) - -func currentScope() (Environment, bool) { - id, ok := currentScopeID() - if !ok { - return Environment{}, false - } - - stack := scopes[id] - if len(stack) == 0 { - return Environment{}, false - } - - return stack[len(stack)-1], true -} - -func updateCurrentScope(environment Environment) { - id, ok := currentScopeID() - if !ok { - return - } - - stack := scopes[id] - if len(stack) == 0 { - return - } - - stack[len(stack)-1] = environment - scopes[id] = stack -} - -func pushScope(environment Environment) { - id, ok := currentScopeID() - if !ok { - current = environment - - return - } - - scopes[id] = append(scopes[id], environment) -} - -func popScope() { - id, ok := currentScopeID() - if !ok { - return - } - - stack := scopes[id] - if len(stack) <= 1 { - delete(scopes, id) - - return - } - - scopes[id] = stack[:len(stack)-1] -} - -func currentScopeID() (uint64, bool) { - var buffer [64]byte - size := runtime.Stack(buffer[:], false) - line := string(buffer[:size]) - id, _, ok := strings.Cut(strings.TrimPrefix(line, "goroutine "), " ") - if !ok { - return 0, false - } - - parsed, err := strconv.ParseUint(id, 10, 64) - if err != nil { - return 0, false - } - - return parsed, true -} diff --git a/provision/go/internal/environment/scripted_input.go b/provision/go/internal/environment/scripted_input.go deleted file mode 100644 index 76a2b37a..00000000 --- a/provision/go/internal/environment/scripted_input.go +++ /dev/null @@ -1,34 +0,0 @@ -package environment - -type ScriptedInput struct { - queued []string -} - -func NewScriptedInput(lines []string) *ScriptedInput { - queued := make([]string, len(lines)) - copy(queued, lines) - - return &ScriptedInput{queued: queued} -} - -func (input *ScriptedInput) ReadKey() (string, bool, error) { - if len(input.queued) == 0 { - return "", false, nil - } - - value := input.queued[0] - input.queued = input.queued[1:] - - return value, true, nil -} - -func (input *ScriptedInput) ReadLine(_ string) (string, error) { - if len(input.queued) == 0 { - return "", nil - } - - value := input.queued[0] - input.queued = input.queued[1:] - - return value, nil -} diff --git a/provision/go/internal/environment/stdio.go b/provision/go/internal/environment/stdio.go deleted file mode 100644 index bc23b4c6..00000000 --- a/provision/go/internal/environment/stdio.go +++ /dev/null @@ -1,89 +0,0 @@ -package environment - -import ( - "bufio" - "errors" - "io" - stdstrings "strings" -) - -type StdioInput struct { - prompt io.Writer - reader *bufio.Reader -} - -type WriterOutput struct { - writer io.Writer -} - -func NewStdioInput(reader io.Reader, prompt io.Writer) *StdioInput { - return &StdioInput{prompt: prompt, reader: bufio.NewReader(reader)} -} - -func NewWriterOutput(writer io.Writer) WriterOutput { - return WriterOutput{writer: writer} -} - -func (input *StdioInput) ReadKey() (string, bool, error) { - value, err := input.reader.ReadByte() - if errors.Is(err, io.EOF) { - return "", false, nil - } - if err != nil { - return "", false, err - } - - if value == '\r' { - return "\n", true, nil - } - - if value == '\x1b' { - return input.readEscapeSequence(value), true, nil - } - - return string(value), true, nil -} - -func (input *StdioInput) ReadLine(message string) (string, error) { - if input.prompt != nil && message != "" { - if _, err := io.WriteString(input.prompt, message); err != nil { - return "", err - } - } - - value, err := input.reader.ReadString('\n') - if err != nil && !errors.Is(err, io.EOF) { - return "", err - } - - return stdstrings.TrimRight(value, "\r\n"), nil -} - -func (input *StdioInput) readEscapeSequence(first byte) string { - sequence := []byte{first} - - for input.reader.Buffered() > 0 { - next, err := input.reader.ReadByte() - if err != nil { - break - } - sequence = append(sequence, next) - if isEscapeSequenceFinal(next) { - break - } - } - - return string(sequence) -} - -func isEscapeSequenceFinal(value byte) bool { - return (value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z') || value == '~' -} - -func (output WriterOutput) Write(content string) { - if output.writer == nil || content == "" { - return - } - - _, _ = io.WriteString(output.writer, content) -} diff --git a/provision/go/internal/environment/stdio_test.go b/provision/go/internal/environment/stdio_test.go deleted file mode 100644 index 15a007b4..00000000 --- a/provision/go/internal/environment/stdio_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package environment - -import ( - "bytes" - "testing" -) - -func TestStdioInputReadsKeysLinesAndEscapeSequences(t *testing.T) { - var prompt bytes.Buffer - input := NewStdioInput(bytes.NewBufferString("A\r\x1b[Ahello\n"), &prompt) - - pressed, ok, err := input.ReadKey() - if err != nil || !ok || pressed != "A" { - t.Fatalf("first key = %q ok=%v err=%v", pressed, ok, err) - } - - pressed, ok, err = input.ReadKey() - if err != nil || !ok || pressed != "\n" { - t.Fatalf("enter key = %q ok=%v err=%v", pressed, ok, err) - } - - pressed, ok, err = input.ReadKey() - if err != nil || !ok || pressed != "\x1b[A" { - t.Fatalf("escape key = %q ok=%v err=%v", pressed, ok, err) - } - - line, err := input.ReadLine("Name: ") - if err != nil || line != "hello" { - t.Fatalf("line = %q err=%v", line, err) - } - if prompt.String() != "Name: " { - t.Fatalf("prompt = %q", prompt.String()) - } -} - -func TestWriterOutputWritesToWriter(t *testing.T) { - var output bytes.Buffer - NewWriterOutput(&output).Write("hello") - - if output.String() != "hello" { - t.Fatalf("output = %q", output.String()) - } -} diff --git a/provision/go/internal/form/builder.go b/provision/go/internal/form/builder.go deleted file mode 100644 index a2e58169..00000000 --- a/provision/go/internal/form/builder.go +++ /dev/null @@ -1,148 +0,0 @@ -package form - -import "errors" - -type StepFunc func(responses *Responses, previous any, name string) (any, error) -type ConditionFunc func(responses *Responses) (bool, error) - -type Step struct { - Condition ConditionFunc - IgnoreWhenReverting bool - Name string - Run StepFunc -} - -type Builder struct { - responses *Responses - steps []Step -} - -func New() *Builder { - return &Builder{responses: NewResponses()} -} - -func (builder *Builder) Add(run StepFunc, name ...string) *Builder { - return builder.addStep(trueCondition, run, firstName(name), false) -} - -func (builder *Builder) AddSideEffect(run func() error, name ...string) *Builder { - return builder.addStep(trueCondition, SideEffect(run), firstName(name), true) -} - -func (builder *Builder) AddIf(condition ConditionFunc, run StepFunc, name ...string) *Builder { - return builder.addStep(condition, run, firstName(name), false) -} - -func (builder *Builder) AddSideEffectIf(condition ConditionFunc, run func() error, name ...string) *Builder { - return builder.addStep(condition, SideEffect(run), firstName(name), true) -} - -func (builder *Builder) Submit() (*Responses, error) { - index := 0 - wasReverted := false - - for index < len(builder.steps) { - step := builder.steps[index] - - if wasReverted && index > 0 { - ignore, err := shouldIgnoreWhenReverting(step, builder.responses) - if err != nil { - return nil, err - } - if ignore { - index-- - continue - } - } - - wasReverted = false - shouldRun, err := shouldRun(step, builder.responses) - if err != nil { - return nil, err - } - if !shouldRun { - builder.responses.set(index, step.Name, nil) - index++ - continue - } - - previous := builder.responses.previous(index, step.Name) - value, err := runWithRevert(index > 0, func() (any, error) { - return step.Run(builder.responses, previous, step.Name) - }) - if err != nil { - if !errors.Is(err, ErrReverted) { - return nil, err - } - wasReverted = true - } else { - builder.responses.set(index, step.Name, value) - } - - if wasReverted { - index-- - } else { - index++ - } - } - - return builder.responses, nil -} - -func (builder *Builder) addStep(condition ConditionFunc, run StepFunc, name string, ignoreWhenReverting bool) *Builder { - if condition == nil { - condition = trueCondition - } - builder.steps = append(builder.steps, Step{ - Condition: condition, - IgnoreWhenReverting: ignoreWhenReverting, - Name: name, - Run: run, - }) - return builder -} - -func SideEffect(callback func() error) StepFunc { - return func(*Responses, any, string) (any, error) { - if callback == nil { - return nil, nil - } - - return nil, callback() - } -} - -func Bool(condition bool) ConditionFunc { - return func(*Responses) (bool, error) { - return condition, nil - } -} - -func trueCondition(*Responses) (bool, error) { - return true, nil -} - -func shouldRun(step Step, responses *Responses) (bool, error) { - if step.Condition == nil { - return true, nil - } - - return step.Condition(responses) -} - -func shouldIgnoreWhenReverting(step Step, responses *Responses) (bool, error) { - run, err := shouldRun(step, responses) - if err != nil || !run { - return true, err - } - - return step.IgnoreWhenReverting, nil -} - -func firstName(values []string) string { - if len(values) == 0 { - return "" - } - - return values[0] -} diff --git a/provision/go/internal/form/form_test.go b/provision/go/internal/form/form_test.go deleted file mode 100644 index 2fa96e86..00000000 --- a/provision/go/internal/form/form_test.go +++ /dev/null @@ -1,214 +0,0 @@ -package form - -import ( - "reflect" - "strings" - "testing" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/output" - "github.com/oullin/tui/internal/prompts" -) - -func withFormEnvironment(keys []string, callback func(*environment.MemoryOutput) error) error { - memoryOutput := environment.NewMemoryOutput() - interactive := true - return environment.With( - environment.Patch{ - Input: environment.NewScriptedInput(keys), - Output: memoryOutput, - ErrorOutput: memoryOutput, - Interactive: &interactive, - }, - func() error { - return callback(memoryOutput) - }, - ) -} - -func TestBuilderRunsChainedStepsAndReturnsPositionalResponses(t *testing.T) { - err := withFormEnvironment([]string{"A", "d", "a", key.First(key.Enter), key.First(key.Enter), key.First(key.Enter)}, func(*environment.MemoryOutput) error { - responses, err := New(). - Text(prompts.TextOptions{Message: "Name"}). - Select(prompts.ChoiceOptions{Message: "Runtime", Choices: prompts.NewStringChoices("TS", "JS")}). - Confirm(prompts.ConfirmOptions{Message: "Active"}). - Submit() - if err != nil { - return err - } - - if responses.At(0) != "Ada" || responses.At(1) != "TS" || responses.At(2) != true { - t.Fatalf("responses = %#v", responses.Values()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestBuilderKeysNamedResponsesAndPassesPreviousAndName(t *testing.T) { - err := withFormEnvironment([]string{"A", "d", "a", key.First(key.Enter)}, func(*environment.MemoryOutput) error { - responses, err := New(). - Text(prompts.TextOptions{Message: "Name"}, "name"). - Add(func(values *Responses, previous any, name string) (any, error) { - if previous == nil { - previous = "new" - } - return name + ":" + previous.(string) + ":Hello " + values.Named("name").(string), nil - }, "greeting"). - Submit() - if err != nil { - return err - } - - if responses.Named("name") != "Ada" || responses.Named("greeting") != "greeting:new:Hello Ada" { - t.Fatalf("named responses = %#v", responses.Names()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestBuilderStoresNilForSkippedConditionalSteps(t *testing.T) { - err := withFormEnvironment([]string{"n"}, func(*environment.MemoryOutput) error { - responses, err := New(). - Confirm(prompts.ConfirmOptions{Message: "Include details?", Default: false, HasDefault: true}, "include"). - AddIf(func(values *Responses) (bool, error) { - return values.Named("include") == true, nil - }, func(*Responses, any, string) (any, error) { - return "details", nil - }, "details"). - Submit() - if err != nil { - return err - } - - if responses.Named("include") != false || responses.Named("details") != nil { - t.Fatalf("named responses = %#v", responses.Names()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestBuilderRevertsToPreviousStepAndReusesPriorResponse(t *testing.T) { - err := withFormEnvironment([]string{ - "A", key.First(key.Enter), - "B", key.First(key.CtrlU), - key.First(key.Backspace), "C", key.First(key.Enter), - "D", key.First(key.Enter), - }, func(*environment.MemoryOutput) error { - responses, err := New(). - Text(prompts.TextOptions{Message: "First"}). - Text(prompts.TextOptions{Message: "Second"}). - Submit() - if err != nil { - return err - } - - if responses.At(0) != "C" || responses.At(1) != "D" { - t.Fatalf("responses = %#v", responses.Values()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestBuilderReusesPreviousPromptDefaultsByType(t *testing.T) { - err := withFormEnvironment([]string{ - "4", key.First(key.Enter), - key.First(key.Space), key.First(key.Enter), - key.First(key.CtrlU), - key.First(key.Enter), - "D", key.First(key.Enter), - }, func(*environment.MemoryOutput) error { - responses, err := New(). - Number(prompts.NumberOptions{Message: "Count"}). - Multiselect(prompts.MultiChoiceOptions{Message: "Flags", Choices: prompts.NewStringChoices("alpha", "beta")}). - Text(prompts.TextOptions{Message: "Done"}). - Submit() - if err != nil { - return err - } - - if responses.At(0) != 4 || !reflect.DeepEqual(responses.At(1), []any{"alpha"}) || responses.At(2) != "D" { - t.Fatalf("responses = %#v", responses.Values()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestBuilderRevertsPastIgnoredSideEffectSteps(t *testing.T) { - err := withFormEnvironment([]string{ - "A", key.First(key.Enter), - "B", key.First(key.CtrlU), - key.First(key.Backspace), "C", key.First(key.Enter), - "D", key.First(key.Enter), - }, func(*environment.MemoryOutput) error { - responses, err := New(). - Text(prompts.TextOptions{Message: "First"}). - Note("Skipping back over this", output.NoteType(""), "note"). - Text(prompts.TextOptions{Message: "Second"}). - Submit() - if err != nil { - return err - } - - if responses.At(0) != "C" || responses.Named("note") != nil || responses.At(2) != "D" { - t.Fatalf("positional=%#v named=%#v", responses.Values(), responses.Names()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestBuilderDoesNotRevertTheFirstStep(t *testing.T) { - err := withFormEnvironment([]string{key.First(key.CtrlU), "A", key.First(key.Enter)}, func(output *environment.MemoryOutput) error { - responses, err := New().Text(prompts.TextOptions{Message: "First"}).Submit() - if err != nil { - return err - } - - if responses.At(0) != "A" || !strings.Contains(output.Text(), "This cannot be reverted.") { - t.Fatalf("response=%#v output=%q", responses.Values(), output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestBuilderRunsOutputAndStatusAdapters(t *testing.T) { - err := withFormEnvironment(nil, func(memoryOutput *environment.MemoryOutput) error { - responses, err := New(). - Info("Preparing", "info"). - Spin("Working", func() (any, error) { return "done", nil }, "spin"). - Submit() - if err != nil { - return err - } - - rendered := memoryOutput.Text() - if responses.Named("info") != nil || responses.Named("spin") != "done" || !strings.Contains(rendered, "Preparing") || !strings.Contains(rendered, "Working") { - t.Fatalf("named=%#v output=%q", responses.Names(), rendered) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} diff --git a/provision/go/internal/form/output.go b/provision/go/internal/form/output.go deleted file mode 100644 index d3cf86b5..00000000 --- a/provision/go/internal/form/output.go +++ /dev/null @@ -1,87 +0,0 @@ -package form - -import "github.com/oullin/tui/internal/output" - -func (builder *Builder) Alert(message string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Alert(message) - return nil - }, name...) -} - -func (builder *Builder) Clear(name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Clear() - return nil - }, name...) -} - -func (builder *Builder) Error(message string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Error(message) - return nil - }, name...) -} - -func (builder *Builder) Grid(items []any, maxWidth int, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Grid(items, maxWidth) - return nil - }, name...) -} - -func (builder *Builder) Info(message string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Info(message) - return nil - }, name...) -} - -func (builder *Builder) Intro(message string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Intro(message) - return nil - }, name...) -} - -func (builder *Builder) Note(message string, noteType output.NoteType, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Note(message, noteType) - return nil - }, name...) -} - -func (builder *Builder) Outro(message string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Outro(message) - return nil - }, name...) -} - -func (builder *Builder) Table(headers []string, rows [][]any, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Table(headers, rows) - return nil - }, name...) -} - -func (builder *Builder) TableObjects(headers []string, rows []output.TableRow, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.TableObjects(headers, rows) - return nil - }, name...) -} - -func (builder *Builder) Title(value string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Title(value) - return nil - }, name...) -} - -func (builder *Builder) Warning(message string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - output.Warning(message) - return nil - }, name...) -} diff --git a/provision/go/internal/form/previous.go b/provision/go/internal/form/previous.go deleted file mode 100644 index a448fea0..00000000 --- a/provision/go/internal/form/previous.go +++ /dev/null @@ -1,55 +0,0 @@ -package form - -import "fmt" - -func PreviousString(previous any, defaultValue string) string { - value, ok := previous.(string) - if !ok { - return defaultValue - } - - return value -} - -func PreviousNumber(previous any, defaultValue string) string { - switch value := previous.(type) { - case nil: - return defaultValue - case string: - return value - case int: - return fmt.Sprint(value) - case int64: - return fmt.Sprint(value) - case float64: - return fmt.Sprint(value) - default: - return defaultValue - } -} - -func PreviousBool(previous any, defaultValue bool) bool { - value, ok := previous.(bool) - if !ok { - return defaultValue - } - - return value -} - -func PreviousSlice(previous any, defaultValue []any) []any { - value, ok := previous.([]any) - if !ok { - return append([]any{}, defaultValue...) - } - - return append([]any{}, value...) -} - -func PreviousValue(previous any, defaultValue any) any { - if previous == nil { - return defaultValue - } - - return previous -} diff --git a/provision/go/internal/form/prompts.go b/provision/go/internal/form/prompts.go deleted file mode 100644 index 3dfc719e..00000000 --- a/provision/go/internal/form/prompts.go +++ /dev/null @@ -1,111 +0,0 @@ -package form - -import ( - "github.com/oullin/tui/internal/output" - "github.com/oullin/tui/internal/prompt" - "github.com/oullin/tui/internal/prompts" -) - -func (builder *Builder) Text(options prompts.TextOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousString(previous, options.Default) - return prompts.Text(options) - }, name...) -} - -func (builder *Builder) Textarea(options prompts.TextOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousString(previous, options.Default) - return prompts.Textarea(options) - }, name...) -} - -func (builder *Builder) Password(options prompts.TextOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousString(previous, options.Default) - return prompts.Password(options) - }, name...) -} - -func (builder *Builder) Number(options prompts.NumberOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - previousValue := PreviousNumber(previous, options.Default) - options.Default = previousValue - options.HasDefault = options.HasDefault || previousValue != "" - return prompts.Number(options) - }, name...) -} - -func (builder *Builder) Pause(message string, name ...string) *Builder { - return builder.Add(func(*Responses, any, string) (any, error) { - return prompts.Pause(message) - }, name...) -} - -func (builder *Builder) Confirm(options prompts.ConfirmOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - if previous != nil { - options.Default = PreviousBool(previous, options.Default) - } else if !options.HasDefault { - options.Default = true - } - options.HasDefault = true - return prompts.Confirm(options) - }, name...) -} - -func (builder *Builder) Select(options prompts.ChoiceOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousValue(previous, options.Default) - options.HasDefault = options.HasDefault || previous != nil - return prompts.Select(options) - }, name...) -} - -func (builder *Builder) Multiselect(options prompts.MultiChoiceOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Defaults = PreviousSlice(previous, options.Defaults) - return prompts.Multiselect(options) - }, name...) -} - -func (builder *Builder) Search(options prompts.SearchOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousValue(previous, options.Default) - options.HasDefault = options.HasDefault || previous != nil - return prompts.Search(options) - }, name...) -} - -func (builder *Builder) Multisearch(options prompts.MultiSearchOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Defaults = PreviousSlice(previous, options.Defaults) - return prompts.MultiSearch(options) - }, name...) -} - -func (builder *Builder) Suggest(options prompts.SuggestOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousString(previous, options.Default) - return prompts.Suggest(options) - }, name...) -} - -func (builder *Builder) Autocomplete(options prompts.SuggestOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousString(previous, options.Default) - return prompts.Autocomplete(options) - }, name...) -} - -func (builder *Builder) DataTable(options output.DataTableOptions, name ...string) *Builder { - return builder.Add(func(_ *Responses, previous any, _ string) (any, error) { - options.Default = PreviousValue(previous, options.Default) - options.HasDefault = options.HasDefault || previous != nil - return output.DataTable(options) - }, name...) -} - -func Required(value bool) prompt.Required { - return prompt.Required{Enabled: value} -} diff --git a/provision/go/internal/form/responses.go b/provision/go/internal/form/responses.go deleted file mode 100644 index dbb4c73f..00000000 --- a/provision/go/internal/form/responses.go +++ /dev/null @@ -1,70 +0,0 @@ -package form - -type Responses struct { - named map[string]any - positional []any -} - -func NewResponses() *Responses { - return &Responses{named: map[string]any{}} -} - -func (responses *Responses) At(index int) any { - if responses == nil || index < 0 || index >= len(responses.positional) { - return nil - } - - return responses.positional[index] -} - -func (responses *Responses) Named(name string) any { - if responses == nil || name == "" { - return nil - } - - return responses.named[name] -} - -func (responses *Responses) Values() []any { - if responses == nil { - return nil - } - - values := make([]any, len(responses.positional)) - copy(values, responses.positional) - - return values -} - -func (responses *Responses) Names() map[string]any { - if responses == nil { - return nil - } - - values := make(map[string]any, len(responses.named)) - for key, value := range responses.named { - values[key] = value - } - - return values -} - -func (responses *Responses) previous(index int, name string) any { - if name != "" { - return responses.Named(name) - } - - return responses.At(index) -} - -func (responses *Responses) set(index int, name string, value any) { - if name != "" { - responses.named[name] = value - return - } - - for len(responses.positional) <= index { - responses.positional = append(responses.positional, nil) - } - responses.positional[index] = value -} diff --git a/provision/go/internal/form/revert.go b/provision/go/internal/form/revert.go deleted file mode 100644 index 7a21ab4c..00000000 --- a/provision/go/internal/form/revert.go +++ /dev/null @@ -1,58 +0,0 @@ -package form - -import ( - "errors" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/theme" -) - -var ErrReverted = errors.New("form reverted") - -type revertInput struct { - canRevert bool - previous environment.Input -} - -func runWithRevert(canRevert bool, callback func() (any, error)) (any, error) { - env := environment.Current() - if env.Input == nil { - return callback() - } - - return callbackWithInput(revertInput{canRevert: canRevert, previous: env.Input}, callback) -} - -func callbackWithInput(input environment.Input, callback func() (any, error)) (any, error) { - returnValue := any(nil) - err := environment.With(environment.Patch{Input: input}, func() error { - value, callbackErr := callback() - returnValue = value - return callbackErr - }) - - return returnValue, err -} - -func (input revertInput) ReadKey() (string, bool, error) { - pressed, ok, err := input.previous.ReadKey() - if err != nil || !ok { - return pressed, ok, err - } - - if pressed != key.First(key.CtrlU) { - return pressed, ok, nil - } - - if input.canRevert { - return "", false, ErrReverted - } - - environment.Current().ErrorOutput.Write(theme.Red(" ⚠ This cannot be reverted.") + "\n") - return input.ReadKey() -} - -func (input revertInput) ReadLine(message string) (string, error) { - return input.previous.ReadLine(message) -} diff --git a/provision/go/internal/form/status.go b/provision/go/internal/form/status.go deleted file mode 100644 index 38c6d7bb..00000000 --- a/provision/go/internal/form/status.go +++ /dev/null @@ -1,30 +0,0 @@ -package form - -import "github.com/oullin/tui/internal/status" - -func (builder *Builder) Progress(total int, message string, name ...string) *Builder { - return builder.AddSideEffect(func() error { - bar := status.NewProgress(total, message, "") - bar.Start() - bar.Finish() - return nil - }, name...) -} - -func (builder *Builder) Spin(message string, callback func() (any, error), name ...string) *Builder { - return builder.Add(func(*Responses, any, string) (any, error) { - return status.Spin(message, callback) - }, name...) -} - -func (builder *Builder) Stream(name ...string) *Builder { - return builder.Add(func(*Responses, any, string) (any, error) { - return status.NewStream(), nil - }, name...) -} - -func (builder *Builder) Task(label string, callback func(*status.Logger) (any, error), limit int, keepSummary bool, subLabel string, name ...string) *Builder { - return builder.Add(func(*Responses, any, string) (any, error) { - return status.Task(label, callback, limit, keepSummary, subLabel) - }, name...) -} diff --git a/provision/go/internal/key/key.go b/provision/go/internal/key/key.go deleted file mode 100644 index 775aca55..00000000 --- a/provision/go/internal/key/key.go +++ /dev/null @@ -1,175 +0,0 @@ -package key - -type Value []string - -type Event struct { - Name string - Sequence string - Ctrl bool - Meta bool - Shift bool -} - -var ( - Up = Value{"\x1b[A"} - ShiftUp = Value{"\x1b[1;2A"} - PageUp = Value{"\x1b[5~"} - Down = Value{"\x1b[B"} - ShiftDown = Value{"\x1b[1;2B"} - PageDown = Value{"\x1b[6~"} - Right = Value{"\x1b[C"} - Left = Value{"\x1b[D"} - UpArrow = Value{"\x1bOA"} - DownArrow = Value{"\x1bOB"} - RightArrow = Value{"\x1bOC"} - LeftArrow = Value{"\x1bOD"} - Escape = Value{"\x1b"} - Delete = Value{"\x1b[3~"} - Backspace = Value{"\x7f"} - Enter = Value{"\n"} - Space = Value{" "} - Tab = Value{"\t"} - ShiftTab = Value{"\x1b[Z"} - Home = Value{"\x1b[1~", "\x1bOH", "\x1b[H", "\x1b[7~"} - End = Value{"\x1b[4~", "\x1bOF", "\x1b[F", "\x1b[8~"} - CtrlC = Value{"\x03"} - CtrlP = Value{"\x10"} - CtrlN = Value{"\x0e"} - CtrlF = Value{"\x06"} - CtrlB = Value{"\x02"} - CtrlH = Value{"\x08"} - CtrlA = Value{"\x01"} - CtrlD = Value{"\x04"} - CtrlE = Value{"\x05"} - CtrlU = Value{"\x15"} - OptionBackspace = Value{"\x1b\x7f"} -) - -var named = map[string]Value{ - "up": Up, - "shiftUp": ShiftUp, - "pageUp": PageUp, - "down": Down, - "shiftDown": ShiftDown, - "pageDown": PageDown, - "right": Right, - "left": Left, - "upArrow": UpArrow, - "downArrow": DownArrow, - "rightArrow": RightArrow, - "leftArrow": LeftArrow, - "escape": Escape, - "delete": Delete, - "backspace": Backspace, - "enter": Enter, - "space": Space, - "tab": Tab, - "shiftTab": ShiftTab, - "home": Home, - "end": End, - "ctrlC": CtrlC, - "ctrlP": CtrlP, - "ctrlN": CtrlN, - "ctrlF": CtrlF, - "ctrlB": CtrlB, - "ctrlH": CtrlH, - "ctrlA": CtrlA, - "ctrlD": CtrlD, - "ctrlE": CtrlE, - "ctrlU": CtrlU, - "optionBackspace": OptionBackspace, -} - -var ctrlKeys = map[string]Value{ - "a": CtrlA, - "b": CtrlB, - "c": CtrlC, - "d": CtrlD, - "e": CtrlE, - "f": CtrlF, - "h": CtrlH, - "n": CtrlN, - "p": CtrlP, - "u": CtrlU, -} - -var aliases = map[string]Value{ - "pagedown": PageDown, - "pageup": PageUp, - "return": Enter, -} - -func First(value Value) string { - if len(value) == 0 { - return "" - } - - return value[0] -} - -func FromEvent(event Event) string { - name := lowerASCII(event.Name) - - if event.Ctrl && name != "" { - if value, ok := ctrlKeys[name]; ok { - return First(value) - } - } - - if event.Meta && event.Name == "backspace" { - return First(OptionBackspace) - } - - if event.Shift && name == "tab" { - return First(ShiftTab) - } - - if name != "" { - if value, ok := aliases[name]; ok { - return First(value) - } - } - - if event.Name != "" { - if value, ok := named[event.Name]; ok { - return First(value) - } - } - - if event.Sequence == " " { - return First(Space) - } - - if event.Sequence == "\r" || event.Sequence == "\n" { - return First(Enter) - } - - if event.Name != "" { - return event.Name - } - - return event.Sequence -} - -func OneOf(keys []Value, match string) (string, bool) { - for _, value := range keys { - for _, candidate := range value { - if candidate == match { - return match, true - } - } - } - - return "", false -} - -func lowerASCII(value string) string { - bytes := []byte(value) - for index, char := range bytes { - if char >= 'A' && char <= 'Z' { - bytes[index] = char + ('a' - 'A') - } - } - - return string(bytes) -} diff --git a/provision/go/internal/key/key_test.go b/provision/go/internal/key/key_test.go deleted file mode 100644 index 713ec8a3..00000000 --- a/provision/go/internal/key/key_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package key - -import "testing" - -func TestFromEventMapsNamedKeys(t *testing.T) { - if got := FromEvent(Event{Name: "enter"}); got != First(Enter) { - t.Fatalf("FromEvent() = %q, want %q", got, First(Enter)) - } -} - -func TestFromEventMapsAliases(t *testing.T) { - tests := []struct { - name string - want string - }{ - {name: "return", want: First(Enter)}, - {name: "pageup", want: First(PageUp)}, - {name: "pagedown", want: First(PageDown)}, - } - - for _, test := range tests { - if got := FromEvent(Event{Name: test.name}); got != test.want { - t.Fatalf("FromEvent(%q) = %q, want %q", test.name, got, test.want) - } - } -} - -func TestFromEventMapsSequencesAndModifiers(t *testing.T) { - tests := []struct { - event Event - want string - }{ - {event: Event{Sequence: " "}, want: First(Space)}, - {event: Event{Sequence: "\n"}, want: First(Enter)}, - {event: Event{Ctrl: true, Name: "c"}, want: First(CtrlC)}, - {event: Event{Ctrl: true, Name: "n"}, want: First(CtrlN)}, - {event: Event{Ctrl: true, Name: "U"}, want: First(CtrlU)}, - {event: Event{Meta: true, Name: "backspace"}, want: First(OptionBackspace)}, - {event: Event{Shift: true, Name: "tab"}, want: First(ShiftTab)}, - } - - for _, test := range tests { - if got := FromEvent(test.event); got != test.want { - t.Fatalf("FromEvent(%+v) = %q, want %q", test.event, got, test.want) - } - } -} - -func TestOneOfMatchesGroupedKeys(t *testing.T) { - if got, ok := OneOf([]Value{Home, End}, Home[2]); !ok || got != Home[2] { - t.Fatalf("OneOf(Home[2]) = %q, %v", got, ok) - } - - if got, ok := OneOf([]Value{Home, End}, End[3]); !ok || got != End[3] { - t.Fatalf("OneOf(End[3]) = %q, %v", got, ok) - } - - if _, ok := OneOf([]Value{Home, End}, First(Enter)); ok { - t.Fatalf("OneOf(Enter) matched unexpectedly") - } -} diff --git a/provision/go/internal/output/datatable.go b/provision/go/internal/output/datatable.go deleted file mode 100644 index 0369d3a4..00000000 --- a/provision/go/internal/output/datatable.go +++ /dev/null @@ -1,300 +0,0 @@ -package output - -import ( - "errors" - "fmt" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/prompt" - "github.com/oullin/tui/internal/theme" - "github.com/oullin/tui/internal/typedvalue" -) - -type DataTableRow struct { - Cells map[string]any - Value any -} - -type DataTableOptions struct { - Message string - Headers []string - Rows []DataTableRow - Default any - HasDefault bool - Required prompt.Required - Validate prompt.Validator[any] - Transform func(any) (any, error) - Filter func(string, DataTableRow) bool - Scroll int -} - -func DataTable(options DataTableOptions) (any, error) { - if options.Scroll == 0 { - options.Scroll = 10 - } - if len(options.Headers) == 0 { - options.Headers = deriveHeaders(options.Rows) - } - defaultValue := options.Default - if options.HasDefault && options.Transform != nil { - transformed, err := options.Transform(defaultValue) - if err == nil { - defaultValue = transformed - } - } - var submitted *dataTableSelection - return prompt.UntilValid( - prompt.Options[any]{Message: options.Message, Default: defaultValue, Required: options.Required, Validate: options.Validate}, - func(_ int) (any, error) { - selection, err := readDataTableSelection(options) - if err != nil { - return nil, err - } - value := selection.Value - if options.Transform != nil { - value, err = options.Transform(value) - if err != nil { - return nil, err - } - } - if selection.Submitted && !selection.Cancelled { - submitted = &selection - } - return value, nil - }, - func(any) error { - if submitted != nil { - renderSubmittedDataTableFrame(options.Message, options.Headers, submitted.Row) - } - return nil - }, - ) -} - -type dataTableSelection struct { - Cancelled bool - Submitted bool - Row DataTableRow - Value any -} - -func readDataTableSelection(options DataTableOptions) (dataTableSelection, error) { - env := environment.Current() - rows := visibleRows(options, "") - selected := defaultDataTableIndex(rows, options.Default, options.HasDefault) - query := "" - mode := "browse" - renderDataTableFrame(options, rows, selected, mode, query) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(options.Message, "")) - if lineErr != nil { - return dataTableSelection{}, lineErr - } - rows = visibleRows(options, answer) - if len(rows) == 0 { - return dataTableSelection{}, prompt.ValidationError("Please select a valid option.") - } - return dataTableSelection{Row: rows[0], Value: dataTableRowValue(rows[0], 0)}, nil - } - return dataTableSelection{}, err - } - if !ok || pressed == key.First(key.Enter) { - if len(rows) == 0 { - return dataTableSelection{}, prompt.ValidationError("Please select a valid option.") - } - row := rows[selected] - return dataTableSelection{Submitted: true, Row: row, Value: dataTableRowValue(row, selected)}, nil - } - if pressed == key.First(key.CtrlC) { - if len(rows) == 0 { - return dataTableSelection{}, prompt.ValidationError("Please select a valid option.") - } - row := rows[selected] - renderCancelledDataTableFrame(options, rows, selected) - return dataTableSelection{Cancelled: true, Row: row, Value: dataTableRowValue(row, selected)}, nil - } - if pressed == "/" { - mode = "search" - query = "" - renderDataTableFrame(options, rows, selected, mode, query) - continue - } - if mode == "search" { - if pressed == key.First(key.Escape) { - mode = "browse" - query = "" - rows = visibleRows(options, query) - selected = clampSelection(selected, rows) - renderDataTableFrame(options, rows, selected, mode, query) - continue - } - next := typedvalue.ApplyKey(typedvalue.State{Cursor: typedvalue.CharacterLength(query), Value: query}, pressed, false) - if !next.Submitted && !next.Cancelled { - query = next.Value - rows = visibleRows(options, query) - selected = clampSelection(0, rows) - renderDataTableFrame(options, rows, selected, mode, query) - continue - } - } - if direction, ok := dataTableNavigation(pressed); ok { - selected = clampSelection(selected+direction, rows) - renderDataTableFrame(options, rows, selected, mode, query) - continue - } - } -} - -func renderDataTableFrame(options DataTableOptions, rows []DataTableRow, selected int, mode string, query string) { - title := options.Message - if mode == "search" || query != "" { - title += " " + query - } - if len(rows) == 0 { - environment.Current().Output.Write(title + "\n" + theme.RenderTable(nil, [][]string{{"No results found."}}) + "\n") - return - } - windowStart := 0 - windowEnd := len(rows) - if options.Scroll > 0 && options.Scroll < len(rows) { - windowStart = selected - (options.Scroll-1)/2 - if windowStart < 0 { - windowStart = 0 - } - if windowStart+options.Scroll > len(rows) { - windowStart = len(rows) - options.Scroll - } - windowEnd = windowStart + options.Scroll - } - rendered := make([][]string, windowEnd-windowStart) - for index := windowStart; index < windowEnd; index++ { - pointer := " " - if index == selected { - pointer = "›" - } - rendered[index-windowStart] = append([]string{pointer}, dataTableRowCells(options.Headers, rows[index])...) - } - headers := append([]string{""}, options.Headers...) - environment.Current().Output.Write(title + "\n" + theme.RenderTable(headers, rendered) + "\n") -} - -func renderSubmittedDataTableFrame(message string, headers []string, row DataTableRow) { - environment.Current().Output.Write(message + "\n" + stdstrings.Join(dataTableRowCells(headers, row), ", ") + "\n") -} - -func renderCancelledDataTableFrame(options DataTableOptions, rows []DataTableRow, selected int) { - rendered := make([][]string, len(rows)) - for index, row := range rows { - pointer := " " - if index == selected { - pointer = "›" - } - cells := dataTableRowCells(options.Headers, row) - for cellIndex, cell := range cells { - cells[cellIndex] = theme.Strikethrough(theme.Dim(cell)) - } - rendered[index] = append([]string{pointer}, cells...) - } - env := environment.Current() - env.Output.Write(options.Message + "\n") - env.Output.Write(theme.Dim("/ Search") + "\n") - env.Output.Write(theme.RenderTable(append([]string{""}, options.Headers...), rendered) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func visibleRows(options DataTableOptions, query string) []DataTableRow { - rows := make([]DataTableRow, 0, len(options.Rows)) - for _, row := range options.Rows { - if query == "" { - rows = append(rows, row) - continue - } - if options.Filter != nil { - if options.Filter(query, row) { - rows = append(rows, row) - } - continue - } - if stdstrings.Contains(stdstrings.ToLower(stdstrings.Join(dataTableRowCells(options.Headers, row), " ")), stdstrings.ToLower(query)) { - rows = append(rows, row) - } - } - return rows -} - -func deriveHeaders(rows []DataTableRow) []string { - if len(rows) == 0 { - return nil - } - headers := make([]string, 0, len(rows[0].Cells)) - for key := range rows[0].Cells { - if key != "value" { - headers = append(headers, key) - } - } - return headers -} - -func dataTableRowCells(headers []string, row DataTableRow) []string { - if len(headers) == 0 { - cells := make([]string, 0, len(row.Cells)) - for _, value := range row.Cells { - cells = append(cells, stringifyCell(value)) - } - return cells - } - cells := make([]string, len(headers)) - for index, header := range headers { - cells[index] = stringifyCell(row.Cells[header]) - } - return cells -} - -func dataTableRowValue(row DataTableRow, index int) any { - if row.Value != nil { - return row.Value - } - return index -} - -func defaultDataTableIndex(rows []DataTableRow, value any, hasDefault bool) int { - if !hasDefault { - return 0 - } - for index, row := range rows { - if fmt.Sprint(dataTableRowValue(row, index)) == fmt.Sprint(value) { - return index - } - } - return 0 -} - -func dataTableNavigation(pressed string) (int, bool) { - switch pressed { - case key.First(key.Down), key.First(key.DownArrow), key.First(key.CtrlN): - return 1, true - case key.First(key.Up), key.First(key.UpArrow), key.First(key.CtrlP): - return -1, true - default: - return 0, false - } -} - -func clampSelection(selected int, rows []DataTableRow) int { - if len(rows) == 0 { - return 0 - } - if selected < 0 { - return 0 - } - if selected >= len(rows) { - return len(rows) - 1 - } - return selected -} diff --git a/provision/go/internal/output/notes.go b/provision/go/internal/output/notes.go deleted file mode 100644 index df75486e..00000000 --- a/provision/go/internal/output/notes.go +++ /dev/null @@ -1,96 +0,0 @@ -package output - -import ( - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/strings" - "github.com/oullin/tui/internal/theme" -) - -type NoteType string - -const ( - NoteAlert NoteType = "alert" - NoteError NoteType = "error" - NoteInfo NoteType = "info" - NoteIntro NoteType = "intro" - NoteOutro NoteType = "outro" - NoteWarning NoteType = "warning" -) - -func Note(message string, noteType NoteType) { - environment.Current().Output.Write(stdstrings.Join(renderNoteLines(message, noteType), "\n") + "\n") -} - -func Error(message string) { - Note(message, NoteError) -} - -func Warning(message string) { - Note(message, NoteWarning) -} - -func Alert(message string) { - Note(message, NoteAlert) -} - -func Info(message string) { - Note(message, NoteInfo) -} - -func Intro(message string) { - Note(message, NoteIntro) -} - -func Outro(message string) { - Note(message, NoteOutro) -} - -func renderNoteLines(message string, noteType NoteType) []string { - lines := stdstrings.Split(message, "\n") - if noteType == NoteIntro || noteType == NoteOutro { - lines = paddedIntroLines(lines) - } - - for index, line := range lines { - lines[index] = renderNoteLine(line, noteType) - } - - return lines -} - -func paddedIntroLines(lines []string) []string { - padded := make([]string, len(lines)) - longest := 0 - for index, line := range lines { - padded[index] = " " + line + " " - if width := strings.VisibleWidth(padded[index]); width > longest { - longest = width - } - } - for index, line := range padded { - padding := longest - strings.VisibleWidth(line) - if padding > 0 { - padded[index] = line + stdstrings.Repeat(" ", padding) - } - } - return padded -} - -func renderNoteLine(line string, noteType NoteType) string { - switch noteType { - case NoteIntro, NoteOutro: - return " " + theme.BackgroundCyan(theme.Black(line)) - case NoteWarning: - return theme.Yellow(" " + line) - case NoteError: - return theme.Red(" " + line) - case NoteAlert: - return " " + theme.BackgroundRed(theme.White(" "+line+" ")) - case NoteInfo: - return theme.Green(" " + line) - default: - return " " + line - } -} diff --git a/provision/go/internal/output/notify.go b/provision/go/internal/output/notify.go deleted file mode 100644 index 600c4819..00000000 --- a/provision/go/internal/output/notify.go +++ /dev/null @@ -1,90 +0,0 @@ -package output - -import "fmt" - -type NotificationCommand struct { - Bin string - Args []string -} - -type NotificationRuntime struct { - CommandExists func(string) bool - Execute func(NotificationCommand) bool -} - -func NotificationCommandFor(platform string, title string, body string, subtitle string, sound string, icon string) *NotificationCommand { - commands := NotificationCommands(platform, title, body, subtitle, sound, icon) - if len(commands) == 0 { - return nil - } - return &commands[0] -} - -func NotificationCommands(platform string, title string, body string, subtitle string, sound string, icon string) []NotificationCommand { - switch platform { - case "darwin": - script := fmt.Sprintf("display notification %q with title %q", body, title) - if subtitle != "" { - script += fmt.Sprintf(" subtitle %q", subtitle) - } - if sound != "" { - script += fmt.Sprintf(" sound name %q", sound) - } - return []NotificationCommand{{Bin: "osascript", Args: []string{"-e", script}}} - case "linux": - args := []string{} - if icon != "" { - args = append(args, "--icon", icon) - } - args = append(args, title) - if body != "" { - args = append(args, body) - } - message := title - if body != "" { - message += ": " + body - } - return []NotificationCommand{ - {Bin: "notify-send", Args: args}, - {Bin: "kdialog", Args: []string{"--passivepopup", message, "5", "--title", title}}, - } - default: - return nil - } -} - -func NotifyForPlatform(platform string, title string, body string, subtitle string, sound string, icon string, runtime NotificationRuntime) bool { - commands := NotificationCommands(platform, title, body, subtitle, sound, icon) - command := availableNotificationCommand(platform, commands, runtime.CommandExists) - if command != nil { - if runtime.Execute == nil { - return false - } - return runtime.Execute(*command) - } - - if body != "" { - Note(title+": "+body, NoteInfo) - } else { - Note(title, NoteInfo) - } - return false -} - -func availableNotificationCommand(platform string, commands []NotificationCommand, exists func(string) bool) *NotificationCommand { - if len(commands) == 0 { - return nil - } - if platform != "linux" { - return &commands[0] - } - if exists == nil { - return nil - } - for index, command := range commands { - if exists(command.Bin) { - return &commands[index] - } - } - return nil -} diff --git a/provision/go/internal/output/output_test.go b/provision/go/internal/output/output_test.go deleted file mode 100644 index 53f3aca4..00000000 --- a/provision/go/internal/output/output_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package output - -import ( - "reflect" - "strings" - "testing" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - textutil "github.com/oullin/tui/internal/strings" -) - -func withOutput(callback func(output *environment.MemoryOutput) error) error { - output := environment.NewMemoryOutput() - return environment.With(environment.Patch{Output: output, ErrorOutput: output}, func() error { - return callback(output) - }) -} - -func TestNoteHelpersRenderStyledLines(t *testing.T) { - err := withOutput(func(output *environment.MemoryOutput) error { - Note("Hello\nWorld", "") - Warning("Careful") - Error("Nope") - Alert("Heads up") - Info("Facts") - Intro("東京\nA") - Outro("Done") - - rendered := output.Text() - if !strings.Contains(rendered, "Hello") || !strings.Contains(rendered, "\x1b[33m Careful\x1b[39m") || !strings.Contains(rendered, "\x1b[31m Nope\x1b[39m") { - t.Fatalf("note output missing styled lines:\n%s", rendered) - } - if !strings.Contains(textutil.ParseAnsiText(rendered), " 東京 ") || !strings.Contains(textutil.ParseAnsiText(rendered), " A ") { - t.Fatalf("intro output missing visible-width padding:\n%s", rendered) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestTableGridAndTerminalHelpers(t *testing.T) { - err := withOutput(func(output *environment.MemoryOutput) error { - Table([]string{"Name", "Runtime"}, [][]any{{"Ollin", "OpenTUI"}}) - Grid([]any{"A", "B"}, 80) - Title("Prompt") - Clear() - - rendered := output.Text() - for _, want := range []string{"Name", "Runtime", "Ollin", "OpenTUI", "┌───┬───┐", "│ A │ B │", "\x1b]0;Prompt\x07", "\x1b[H\x1b[J"} { - if !strings.Contains(rendered, want) { - t.Fatalf("output missing %q:\n%s", want, rendered) - } - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestRenderGridBalancedRows(t *testing.T) { - got := RenderGrid([]any{"component-alpha", "api-client", "theme-box", "status-task", "prompt-input", "stream-log"}, 50) - want := strings.Join([]string{ - " ┌─────────────────┬─────────────┐", - " │ component-alpha │ api-client │", - " ├─────────────────┼─────────────┤", - " │ theme-box │ status-task │", - " ├─────────────────┼─────────────┤", - " │ prompt-input │ stream-log │", - " └─────────────────┴─────────────┘", - }, "\n") - if got != want { - t.Fatalf("RenderGrid() =\n%s\nwant\n%s", got, want) - } -} - -func TestNotificationCommandsAndFallback(t *testing.T) { - command := NotificationCommandFor("darwin", "Deploy", "Done", "Preview", "Glass", "") - if command == nil || command.Bin != "osascript" || !strings.Contains(command.Args[1], `display notification "Done"`) || !strings.Contains(command.Args[1], `sound name "Glass"`) { - t.Fatalf("darwin command = %#v", command) - } - - commands := NotificationCommands("linux", "Deploy", "Done", "", "", "/tmp/icon.png") - wantFirst := NotificationCommand{Bin: "notify-send", Args: []string{"--icon", "/tmp/icon.png", "Deploy", "Done"}} - if !reflect.DeepEqual(commands[0], wantFirst) { - t.Fatalf("linux command = %#v, want %#v", commands[0], wantFirst) - } - - executed := []NotificationCommand{} - ok := NotifyForPlatform("linux", "Deploy", "Done", "", "", "", NotificationRuntime{ - CommandExists: func(bin string) bool { return bin == "kdialog" }, - Execute: func(command NotificationCommand) bool { - executed = append(executed, command) - return true - }, - }) - if !ok || len(executed) != 1 || executed[0].Bin != "kdialog" { - t.Fatalf("NotifyForPlatform linux ok=%v executed=%#v", ok, executed) - } - - err := withOutput(func(output *environment.MemoryOutput) error { - if NotifyForPlatform("freebsd", "Deploy", "Done", "", "", "", NotificationRuntime{}) { - t.Fatalf("unsupported notification returned true") - } - if !strings.Contains(output.Text(), "Deploy: Done") { - t.Fatalf("fallback note missing:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestDataTableSelectsFiltersAndCancels(t *testing.T) { - rows := []DataTableRow{ - {Cells: map[string]any{"Name": "Alpha", "Runtime": "Node"}, Value: "alpha"}, - {Cells: map[string]any{"Name": "Beta", "Runtime": "OpenTUI"}, Value: "beta"}, - } - err := withDataTableEnvironment(environment.NewScriptedInput([]string{key.First(key.Down), key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := DataTable(DataTableOptions{Message: "Pick project", Headers: []string{"Name", "Runtime"}, Rows: rows}) - if err != nil { - return err - } - if result != "beta" { - t.Fatalf("DataTable() = %#v", result) - } - if !strings.Contains(output.Text(), "Pick project") || !strings.Contains(output.Text(), "›") || !strings.Contains(output.Text(), "Bob, Developer") && !strings.Contains(output.Text(), "Beta, OpenTUI") { - t.Fatalf("datatable output missing expected frame/summary:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withDataTableEnvironment(environment.NewScriptedInput([]string{"/", "B", key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := DataTable(DataTableOptions{Message: "Pick project", Headers: []string{"Name", "Runtime"}, Rows: rows}) - if err != nil { - return err - } - if result != "beta" { - t.Fatalf("filtered DataTable() = %#v", result) - } - if !strings.Contains(output.Text(), "Pick project B") { - t.Fatalf("datatable output missing search query:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withDataTableEnvironment(environment.NewScriptedInput([]string{key.First(key.Down), key.First(key.CtrlC)}), func(output *environment.MemoryOutput) error { - result, err := DataTable(DataTableOptions{Message: "Pick project", Headers: []string{"Name", "Runtime"}, Rows: rows}) - if err != nil { - return err - } - if result != "beta" || !strings.Contains(output.Text(), "Cancelled.") || !strings.Contains(output.Text(), "/ Search") { - t.Fatalf("cancelled DataTable() = %#v output:\n%s", result, output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func withDataTableEnvironment(input environment.Input, callback func(output *environment.MemoryOutput) error) error { - output := environment.NewMemoryOutput() - interactive := true - return environment.With(environment.Patch{Input: input, Output: output, ErrorOutput: output, Interactive: &interactive}, func() error { - return callback(output) - }) -} diff --git a/provision/go/internal/output/table.go b/provision/go/internal/output/table.go deleted file mode 100644 index 2089ccf3..00000000 --- a/provision/go/internal/output/table.go +++ /dev/null @@ -1,152 +0,0 @@ -package output - -import ( - "fmt" - "math" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - text "github.com/oullin/tui/internal/strings" - "github.com/oullin/tui/internal/theme" -) - -type TableRow map[string]any - -func Table(headers []string, rows [][]any) { - renderedRows := make([][]string, len(rows)) - for rowIndex, row := range rows { - renderedRows[rowIndex] = make([]string, len(row)) - for cellIndex, cell := range row { - renderedRows[rowIndex][cellIndex] = stringifyCell(cell) - } - } - - environment.Current().Output.Write(theme.RenderTable(headers, renderedRows) + "\n") -} - -func TableObjects(headers []string, rows []TableRow) { - if len(headers) == 0 && len(rows) > 0 { - for key := range rows[0] { - headers = append(headers, key) - } - } - - renderedRows := make([][]any, len(rows)) - for rowIndex, row := range rows { - renderedRows[rowIndex] = make([]any, len(headers)) - for headerIndex, header := range headers { - renderedRows[rowIndex][headerIndex] = row[header] - } - } - Table(headers, renderedRows) -} - -func Grid(items []any, maxWidth int) { - rendered := RenderGrid(items, maxWidth) - if rendered == "" { - return - } - - environment.Current().Output.Write(rendered + "\n") -} - -func RenderGrid(items []any, maxWidth int) string { - if len(items) == 0 { - return "" - } - - values := make([]string, len(items)) - for index, item := range items { - values[index] = fmt.Sprint(item) - } - - width := maxWidth - if width <= 0 { - width = 1 - } - availableWidth := width - 2 - cellWidth := 0 - for _, value := range values { - if valueWidth := text.VisibleWidth(value) + 4; valueWidth > cellWidth { - cellWidth = valueWidth - } - } - maxColumns := int(math.Max(1, math.Floor(float64((availableWidth-1)/(cellWidth+1))))) - columnCount := max(1, balancedColumnCount(len(values), maxColumns)) - rows := chunkItems(values, columnCount) - widths := make([]int, columnCount) - for column := range columnCount { - for _, row := range rows { - if width := text.VisibleWidth(row[column]); width > widths[column] { - widths[column] = width - } - } - } - - renderedRows := []string{horizontal("┌", "┬", "┐", widths)} - for index, row := range rows { - if index > 0 { - renderedRows = append(renderedRows, horizontal("├", "┼", "┤", widths)) - } - cells := make([]string, len(widths)) - for column, width := range widths { - cells[column] = padVisible(row[column], width) - } - renderedRows = append(renderedRows, "│ "+stdstrings.Join(cells, " │ ")+" │") - } - renderedRows = append(renderedRows, horizontal("└", "┴", "┘", widths)) - - for index, line := range renderedRows { - renderedRows[index] = " " + line - } - - return stdstrings.Join(renderedRows, "\n") -} - -func stringifyCell(value any) string { - if value == nil { - return "" - } - return fmt.Sprint(value) -} - -func padVisible(value string, width int) string { - padding := width - text.VisibleWidth(value) - if padding < 0 { - padding = 0 - } - return value + stdstrings.Repeat(" ", padding) -} - -func balancedColumnCount(itemCount int, maxColumns int) int { - if itemCount <= maxColumns { - return itemCount - } - for columns := maxColumns; columns >= 1; columns-- { - remainder := itemCount % columns - if remainder == 0 || remainder >= int(math.Ceil(float64(columns)/2)) { - return columns - } - } - return maxColumns -} - -func chunkItems(items []string, columnCount int) [][]string { - rows := make([][]string, 0) - for index := 0; index < len(items); index += columnCount { - row := append([]string{}, items[index:min(index+columnCount, len(items))]...) - for len(row) < columnCount { - row = append(row, "") - } - rows = append(rows, row) - } - return rows -} - -func horizontal(left string, middle string, right string, widths []int) string { - parts := make([]string, len(widths)) - for index, width := range widths { - parts[index] = stdstrings.Repeat("─", width+2) - } - return left + stdstrings.Join(parts, middle) + right -} diff --git a/provision/go/internal/output/terminal.go b/provision/go/internal/output/terminal.go deleted file mode 100644 index ad42c6bd..00000000 --- a/provision/go/internal/output/terminal.go +++ /dev/null @@ -1,14 +0,0 @@ -package output - -import ( - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/terminal" -) - -func Clear() { - environment.Current().Output.Write(terminal.ClearSequence()) -} - -func Title(value string) { - environment.Current().Output.Write(terminal.TitleSequence(value)) -} diff --git a/provision/go/internal/prompt/lifecycle.go b/provision/go/internal/prompt/lifecycle.go deleted file mode 100644 index 73c6c215..00000000 --- a/provision/go/internal/prompt/lifecycle.go +++ /dev/null @@ -1,71 +0,0 @@ -package prompt - -import ( - "errors" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/theme" -) - -type Options[T any] struct { - Message string - Default T - Required Required - Validate Validator[T] -} - -type Reader[T any] func(attempt int) (T, error) -type OnValid[T any] func(T) error - -func UntilValid[T any](options Options[T], read Reader[T], onValid OnValid[T]) (T, error) { - env := environment.Current() - - if !env.Interactive { - value := options.Default - if err := EnsureValid(value, options.Required, options.Validate); err != nil { - return value, err - } - - return value, nil - } - - attempt := 0 - for { - value, err := read(attempt) - if err != nil { - var validation environment.PromptValidationError - if errors.As(err, &validation) { - env.ErrorOutput.Write(theme.RenderError(validation.Message)) - attempt++ - continue - } - - return value, err - } - - if err := EnsureValid(value, options.Required, options.Validate); err != nil { - var validation environment.PromptValidationError - if errors.As(err, &validation) { - env.ErrorOutput.Write(theme.RenderError(validation.Message)) - options.Default = value - attempt++ - continue - } - - return value, err - } - - if onValid != nil { - if err := onValid(value); err != nil { - return value, err - } - } - - return value, nil - } -} - -func Ask(message string, hint string) (string, error) { - env := environment.Current() - return env.Input.ReadLine(theme.RenderQuestion(message, hint)) -} diff --git a/provision/go/internal/prompt/validation.go b/provision/go/internal/prompt/validation.go deleted file mode 100644 index ecdb1cc7..00000000 --- a/provision/go/internal/prompt/validation.go +++ /dev/null @@ -1,90 +0,0 @@ -package prompt - -import ( - "errors" - "reflect" - - "github.com/oullin/tui/internal/environment" -) - -type Required struct { - Enabled bool - Message string -} - -type Validator[T any] func(T) (string, error) - -func RequiredMessage(value any, required Required) string { - if !required.Enabled || !isInvalidRequiredValue(value) { - return "" - } - - if required.Message != "" { - return required.Message - } - - return "Required." -} - -func ValidationMessage[T any](value T, validator Validator[T]) (string, error) { - if validator == nil { - return "", nil - } - - message, err := validator(value) - if err != nil { - return "", err - } - - return message, nil -} - -func EnsureValid[T any](value T, required Required, validator Validator[T]) error { - if message := RequiredMessage(value, required); message != "" { - return environment.PromptValidationError{Message: message} - } - - message, err := ValidationMessage(value, validator) - if err != nil { - return err - } - if message != "" { - return environment.PromptValidationError{Message: message} - } - - return nil -} - -func isInvalidRequiredValue(value any) bool { - if value == nil { - return true - } - - switch typed := value.(type) { - case string: - return typed == "" - case bool: - return !typed - } - - reflected := reflect.ValueOf(value) - switch reflected.Kind() { - case reflect.Slice, reflect.Array: - return reflected.Len() == 0 - default: - return false - } -} - -func ValidationError(message string) error { - return environment.PromptValidationError{Message: message} -} - -func IsValidationError(err error) (string, bool) { - var validation environment.PromptValidationError - if ok := errors.As(err, &validation); ok { - return validation.Message, true - } - - return "", false -} diff --git a/provision/go/internal/prompts/basic_test.go b/provision/go/internal/prompts/basic_test.go deleted file mode 100644 index 536f5a5a..00000000 --- a/provision/go/internal/prompts/basic_test.go +++ /dev/null @@ -1,260 +0,0 @@ -package prompts - -import ( - "errors" - "strings" - "testing" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/prompt" - textutil "github.com/oullin/tui/internal/strings" -) - -type lineOnlyInput struct { - asked string - line string -} - -func (input *lineOnlyInput) ReadKey() (string, bool, error) { - return "", false, environment.ErrKeyInputUnsupported -} - -func (input *lineOnlyInput) ReadLine(message string) (string, error) { - input.asked = message - return input.line, nil -} - -func withTestEnvironment(input environment.Input, callback func(output *environment.MemoryOutput) error) error { - output := environment.NewMemoryOutput() - interactive := true - return environment.With(environment.Patch{Input: input, Output: output, ErrorOutput: output, Interactive: &interactive}, func() error { - return callback(output) - }) -} - -func TestTextPromptReadsAndRendersTypedValues(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"A", "d", "a", key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Text(TextOptions{Message: "Name"}) - if err != nil { - return err - } - if result != "Ada" { - t.Fatalf("Text() = %q", result) - } - if !strings.Contains(output.Text(), "\x1b[36mName\x1b[39m") || !strings.Contains(textutil.ParseAnsiText(output.Text()), "Ada") { - t.Fatalf("text output missing rendered prompt/value:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestTextRetriesValidationAndRendersSubmittedOnce(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"J", "e", "s", key.First(key.Enter), "s", key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Text(TextOptions{ - Message: "Name", - Validate: func(value string) (string, error) { - if value != "Jess" { - return "Invalid name.", nil - } - return "", nil - }, - }) - if err != nil { - return err - } - if result != "Jess" { - t.Fatalf("Text() = %q", result) - } - if !strings.Contains(output.Text(), "Invalid name.") { - t.Fatalf("output missing validation error:\n%s", output.Text()) - } - if count := strings.Count(output.Text(), "┌ \x1b[2mName\x1b[22m"); count != 1 { - t.Fatalf("submitted frame count = %d", count) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestTextNonInteractiveDefaultTransformAndValidation(t *testing.T) { - output := environment.NewMemoryOutput() - interactive := false - err := environment.With(environment.Patch{Output: output, ErrorOutput: output, Interactive: &interactive}, func() error { - result, err := Text(TextOptions{ - Message: "Name", - Default: " Ada ", - Transform: func(value string) (string, error) { - return strings.TrimSpace(value), nil - }, - Validate: func(value string) (string, error) { - if value != "Ada" { - return "Unexpected value.", nil - } - return "", nil - }, - }) - if err != nil { - return err - } - if result != "Ada" { - t.Fatalf("Text() = %q", result) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestTextareaPromptAcceptsMultilineInput(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"A", key.First(key.Enter), "B", key.First(key.CtrlD)}), func(output *environment.MemoryOutput) error { - result, err := Textarea(TextOptions{Message: "Description"}) - if err != nil { - return err - } - if result != "A\nB" { - t.Fatalf("Textarea() = %q", result) - } - if !strings.Contains(output.Text(), "Ctrl+D to submit") || !strings.Contains(textutil.ParseAnsiText(output.Text()), "│ A") || !strings.Contains(textutil.ParseAnsiText(output.Text()), "│ B") { - t.Fatalf("textarea output missing expected frame:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestPasswordPromptMasksValues(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"s", "e", "c", "r", "e", "t", key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Password(TextOptions{Message: "Password"}) - if err != nil { - return err - } - if result != "secret" { - t.Fatalf("Password() = %q", result) - } - if strings.Contains(output.Text(), "secret") || !strings.Contains(output.Text(), "••••••") { - t.Fatalf("password output leaked value or missed mask:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestNumberPromptParsesRetriesAndSteps(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"1", "2", "a", key.First(key.Enter), "4", "2", key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Number(NumberOptions{Message: "Amount"}) - if err != nil { - return err - } - if result != 42 { - t.Fatalf("Number() = %#v", result) - } - if !strings.Contains(output.Text(), "Must be a number") { - t.Fatalf("number output missing validation error:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withTestEnvironment(environment.NewScriptedInput([]string{key.First(key.Up), key.First(key.Up), key.First(key.Down), key.First(key.Enter)}), func(_ *environment.MemoryOutput) error { - result, err := Number(NumberOptions{Message: "Count", Step: 2, HasStep: true}) - if err != nil { - return err - } - if result != 1 { - t.Fatalf("stepped Number() = %#v", result) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestPausePromptWaitsForEnterAndFallsBackToLineInput(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"x", key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Pause("Continue") - if err != nil { - return err - } - if !result { - t.Fatalf("Pause() = false") - } - if !strings.Contains(output.Text(), "\x1b[36mContinue\x1b[39m") || !strings.HasSuffix(output.Text(), "\n") { - t.Fatalf("pause output missing frame/newline:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - input := &lineOnlyInput{} - err = withTestEnvironment(input, func(_ *environment.MemoryOutput) error { - result, err := Pause("Continue") - if err != nil { - return err - } - if !result || !strings.Contains(input.asked, "Continue") { - t.Fatalf("line fallback result=%v asked=%q", result, input.asked) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestCancellationUsesCustomHandlerAfterRendering(t *testing.T) { - environment.CancelUsing(func(string) (string, error) { - return "Manual", nil - }) - defer environment.CancelUsing(nil) - - err := withTestEnvironment(environment.NewScriptedInput([]string{key.First(key.CtrlC)}), func(output *environment.MemoryOutput) error { - result, err := Text(TextOptions{Message: "Name"}) - if err != nil { - return err - } - if result != "Manual" { - t.Fatalf("Text(cancelled) = %q", result) - } - if !strings.Contains(output.Text(), "Cancelled.") { - t.Fatalf("cancelled output missing message:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestPromptValidationHelpers(t *testing.T) { - if got := prompt.RequiredMessage("", prompt.Required{Enabled: true}); got != "Required." { - t.Fatalf("RequiredMessage(empty) = %q", got) - } - if got := prompt.RequiredMessage("", prompt.Required{Enabled: true, Message: "Choose something."}); got != "Choose something." { - t.Fatalf("RequiredMessage(custom) = %q", got) - } - if got := prompt.RequiredMessage("value", prompt.Required{Enabled: true}); got != "" { - t.Fatalf("RequiredMessage(value) = %q", got) - } - - _, err := Text(TextOptions{Message: "Name", Required: prompt.Required{Enabled: true}}) - var validation environment.PromptValidationError - if err != nil && !errors.As(err, &validation) { - t.Fatalf("expected validation error, got %v", err) - } -} diff --git a/provision/go/internal/prompts/choices.go b/provision/go/internal/prompts/choices.go deleted file mode 100644 index cb0a7faf..00000000 --- a/provision/go/internal/prompts/choices.go +++ /dev/null @@ -1,689 +0,0 @@ -package prompts - -import ( - "errors" - "fmt" - "reflect" - "sort" - "strconv" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/prompt" - "github.com/oullin/tui/internal/theme" - "github.com/oullin/tui/internal/typedvalue" -) - -type Choice struct { - Label string - Value any - Disabled bool - DisabledReason string - Hint string -} - -type ChoiceOptions struct { - Message string - Choices []Choice - Default any - HasDefault bool - Required prompt.Required - Validate prompt.Validator[any] - Hint string - Scroll int - Transform func(any) (any, error) -} - -type MultiChoiceOptions struct { - Message string - Choices []Choice - Defaults []any - Required prompt.Required - Validate prompt.Validator[[]any] - Hint string - Scroll int - Transform func([]any) ([]any, error) -} - -type ConfirmOptions struct { - Message string - Default bool - HasDefault bool - Yes string - No string - Required prompt.Required - Validate prompt.Validator[bool] - Hint string - Transform func(bool) (bool, error) -} - -func NewStringChoices(values ...string) []Choice { - choices := make([]Choice, len(values)) - for index, value := range values { - choices[index] = Choice{Label: value, Value: value} - } - - return choices -} - -func Select(options ChoiceOptions) (any, error) { - if options.Scroll == 0 { - options.Scroll = 5 - } - validate := preserveInvalidChoiceDefault(&options) - defaultValue := transformedChoiceDefault(options) - - return prompt.UntilValid( - prompt.Options[any]{Message: options.Message, Default: defaultValue, Required: requiredDefault(options.Required, true), Validate: validate}, - func(_ int) (any, error) { - value, label, submitted, err := readSelectedChoice(options) - if err != nil { - return nil, err - } - value, err = transformChoice(options, value) - if err != nil { - return nil, err - } - if submitted { - renderSubmittedChoice(options.Message, label) - } - return value, nil - }, - nil, - ) -} - -func Multiselect(options MultiChoiceOptions) ([]any, error) { - if options.Scroll == 0 { - options.Scroll = 5 - } - - defaultValue := options.Defaults - if options.Transform != nil { - transformed, err := options.Transform(defaultValue) - if err == nil { - defaultValue = transformed - } - } - - return prompt.UntilValid( - prompt.Options[[]any]{Message: options.Message, Default: defaultValue, Required: options.Required, Validate: options.Validate}, - func(_ int) ([]any, error) { - value, labels, submitted, err := readMultipleChoices(options) - if err != nil { - return nil, err - } - if options.Transform != nil { - value, err = options.Transform(value) - if err != nil { - return nil, err - } - } - if submitted { - renderSubmittedChoices(options.Message, labels) - } - return value, nil - }, - nil, - ) -} - -func Confirm(options ConfirmOptions) (bool, error) { - if options.Yes == "" { - options.Yes = "Yes" - } - if options.No == "" { - options.No = "No" - } - defaultValue := true - if options.HasDefault { - defaultValue = options.Default - } - if options.Transform != nil { - transformed, err := options.Transform(defaultValue) - if err == nil { - defaultValue = transformed - } - } - - return prompt.UntilValid( - prompt.Options[bool]{Message: options.Message, Default: defaultValue, Required: options.Required, Validate: options.Validate}, - func(_ int) (bool, error) { - value, submitted, err := readConfirm(options) - if err != nil { - return false, err - } - if options.Transform != nil { - value, err = options.Transform(value) - if err != nil { - return false, err - } - } - if submitted { - renderSubmittedConfirm(options, value) - } - return value, nil - }, - nil, - ) -} - -func readSelectedChoice(options ChoiceOptions) (any, string, bool, error) { - env := environment.Current() - selected := defaultChoiceIndex(options.Choices, options.Default, options.HasDefault) - - renderSelectedChoice(options.Message, options.Choices, selected, options.Scroll) - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(choiceLineQuestion(options.Message, options.Choices, options.Hint)) - if lineErr != nil { - return nil, "", false, lineErr - } - if stdstrings.TrimSpace(answer) == "" && options.HasDefault { - choice := choiceByValue(options.Choices, options.Default) - if choice != nil { - return choice.Value, choice.Label, false, nil - } - } - choice := findChoice(options.Choices, answer) - if choice == nil || choice.Disabled { - return nil, "", false, prompt.ValidationError("Please select a valid option.") - } - return choice.Value, choice.Label, false, nil - } - return nil, "", false, err - } - if !ok { - if options.HasDefault { - choice := choiceByValue(options.Choices, options.Default) - if choice != nil { - return choice.Value, choice.Label, false, nil - } - } - return nil, "", false, prompt.ValidationError("Please select a valid option.") - } - - if pressed == key.First(key.CtrlC) { - renderCancelledChoice(options.Message, options.Choices, selected, options.Scroll) - choice := options.Choices[selected] - value, cancelErr := environment.CancelPrompt(fmt.Sprint(choice.Value)) - if cancelErr != nil { - return nil, "", false, cancelErr - } - return valueOrOriginal(choice.Value, value), choice.Label, false, nil - } - - if numeric, ok := choiceIndex(pressed); ok && numeric >= 0 && numeric < len(options.Choices) && !options.Choices[numeric].Disabled { - choice := options.Choices[numeric] - return choice.Value, choice.Label, true, nil - } - - if action, ok := navigationDirection(pressed); ok { - selected = moveChoiceHighlight(options.Choices, selected, action) - renderSelectedChoice(options.Message, options.Choices, selected, options.Scroll) - continue - } - - if pressed == key.First(key.Enter) { - choice := options.Choices[selected] - if choice.Disabled { - return nil, "", false, prompt.ValidationError("Please select a valid option.") - } - return choice.Value, choice.Label, true, nil - } - } -} - -func readMultipleChoices(options MultiChoiceOptions) ([]any, []string, bool, error) { - env := environment.Current() - selected := firstEnabledIndex(options.Choices) - marked := markedChoiceIndexes(options.Choices, options.Defaults) - - renderMultipleChoices(options.Message, options.Choices, selected, marked, options.Scroll) - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(choiceLineQuestion(options.Message, options.Choices, options.Hint)) - if lineErr != nil { - return nil, nil, false, lineErr - } - if stdstrings.TrimSpace(answer) == "" { - return options.Defaults, nil, false, nil - } - return choicesFromCommaSeparated(options.Choices, answer), nil, false, nil - } - return nil, nil, false, err - } - if !ok || pressed == key.First(key.Enter) { - return markedChoiceValues(options.Choices, marked), markedChoiceLabels(options.Choices, marked), true, nil - } - if pressed == key.First(key.CtrlC) { - renderCancelledChoices(options.Message, options.Choices, selected, marked, options.Scroll) - return markedChoiceValues(options.Choices, marked), markedChoiceLabels(options.Choices, marked), false, nil - } - if stdstrings.Contains(pressed, ",") { - return choicesFromCommaSeparated(options.Choices, pressed), nil, false, nil - } - if numeric, ok := choiceIndex(pressed); ok && numeric >= 0 && numeric < len(options.Choices) && !options.Choices[numeric].Disabled { - toggleMarked(marked, numeric) - renderMultipleChoices(options.Message, options.Choices, selected, marked, options.Scroll) - continue - } - if action, ok := navigationDirection(pressed); ok { - selected = moveChoiceHighlight(options.Choices, selected, action) - renderMultipleChoices(options.Message, options.Choices, selected, marked, options.Scroll) - continue - } - if pressed == key.First(key.CtrlA) { - marked = toggleAllEnabledChoices(options.Choices, marked) - renderMultipleChoices(options.Message, options.Choices, selected, marked, options.Scroll) - continue - } - if pressed == key.First(key.Space) { - if !options.Choices[selected].Disabled { - toggleMarked(marked, selected) - } - renderMultipleChoices(options.Message, options.Choices, selected, marked, options.Scroll) - continue - } - } -} - -func readConfirm(options ConfirmOptions) (bool, bool, error) { - env := environment.Current() - confirmed := true - if options.HasDefault { - confirmed = options.Default - } - renderActiveConfirm(options, confirmed) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - suffix := " [Y/n]" - if options.HasDefault && !options.Default { - suffix = " [y/N]" - } - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(options.Message+suffix, options.Hint)) - if lineErr != nil { - return false, false, lineErr - } - normalized := stdstrings.ToLower(stdstrings.TrimSpace(answer)) - if normalized == "" && options.HasDefault { - return options.Default, false, nil - } - return normalized == "y" || normalized == "yes" || normalized == stdstrings.ToLower(options.Yes), false, nil - } - return false, false, err - } - if !ok { - return confirmed, true, nil - } - switch stdstrings.ToLower(pressed) { - case "y": - confirmed = true - renderActiveConfirm(options, confirmed) - case "n": - confirmed = false - renderActiveConfirm(options, confirmed) - default: - if pressed == key.First(key.Enter) { - return confirmed, true, nil - } - if pressed == key.First(key.CtrlC) { - renderCancelledConfirm(options, confirmed) - return confirmed, false, nil - } - if isConfirmToggleKey(pressed) { - confirmed = !confirmed - renderActiveConfirm(options, confirmed) - } - } - } -} - -func renderSelectedChoice(message string, choices []Choice, selected int, scroll int) { - rows := choiceRows(choices, selected, nil, false) - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: windowedRows(rows, selected, scroll), BorderStyle: theme.Cyan, Title: theme.Cyan(message)}) + "\n") -} - -func renderMultipleChoices(message string, choices []Choice, selected int, marked map[int]bool, scroll int) { - rows := choiceRows(choices, selected, marked, true) - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: windowedRows(rows, selected, scroll), BorderStyle: theme.Cyan, Info: "Use the space bar to select options.", Title: theme.Cyan(message)}) + "\n") -} - -func renderCancelledChoice(message string, choices []Choice, selected int, scroll int) { - rows := choiceRows(choices, selected, nil, false) - env := environment.Current() - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: windowedRows(rows, selected, scroll), BorderStyle: theme.Red, Title: message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func renderCancelledChoices(message string, choices []Choice, selected int, marked map[int]bool, scroll int) { - rows := choiceRows(choices, selected, marked, true) - env := environment.Current() - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: windowedRows(rows, selected, scroll), BorderStyle: theme.Red, Title: message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func renderSubmittedChoice(message string, label string) { - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: label, Title: theme.Dim(message)}) + "\n") -} - -func renderSubmittedChoices(message string, labels []string) { - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: stdstrings.Join(labels, "\n"), Title: theme.Dim(message)}) + "\n") -} - -func renderActiveConfirm(options ConfirmOptions, confirmed bool) { - yes := "○ " + options.Yes - no := "○ " + options.No - if confirmed { - yes = theme.Green("●") + " " + options.Yes - } else { - no = theme.Green("●") + " " + options.No - } - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: yes + " / " + no, BorderStyle: theme.Cyan, Info: options.Hint, Title: theme.Cyan(options.Message)}) + "\n") -} - -func renderCancelledConfirm(options ConfirmOptions, confirmed bool) { - yes := "○ " + options.Yes - no := "○ " + options.No - if confirmed { - yes = "● " + options.Yes - } else { - no = "● " + options.No - } - env := environment.Current() - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: yes + " / " + no, BorderStyle: theme.Red, Title: options.Message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func renderSubmittedConfirm(options ConfirmOptions, value bool) { - label := options.No - if value { - label = options.Yes - } - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: label, Title: theme.Dim(options.Message)}) + "\n") -} - -func choiceRows(choices []Choice, selected int, marked map[int]bool, multiple bool) []string { - rows := make([]string, len(choices)) - for index, choice := range choices { - pointer := " " - if index == selected { - pointer = "›" - } - marker := "○" - if multiple { - if marked[index] { - marker = "◼" - } else { - marker = "◻" - } - } else if index == selected { - marker = "●" - } - label := choice.Label - if choice.Hint != "" { - label += " " + choice.Hint - } - if choice.Disabled { - reason := "disabled" - if choice.DisabledReason != "" { - reason = choice.DisabledReason - } - label += " (" + reason + ")" - } - if index == selected { - rows[index] = theme.Cyan(pointer+" "+marker) + " " + label - } else { - rows[index] = " " + marker + " " + label - } - } - return rows -} - -func windowedRows(rows []string, selected int, scroll int) string { - if scroll <= 0 || scroll >= len(rows) { - return stdstrings.Join(rows, "\n") - } - start := selected - (scroll-1)/2 - if start < 0 { - start = 0 - } - if start+scroll > len(rows) { - start = len(rows) - scroll - } - window := append([]string{}, rows[start:start+scroll]...) - return stdstrings.Join(renderScrollbarRows(window, start, scroll, len(rows)), "\n") -} - -func choiceLineQuestion(message string, choices []Choice, hint string) string { - rendered := make([]string, len(choices)) - for index, choice := range choices { - rendered[index] = fmt.Sprintf(" %d. %s", index+1, choice.Label) - } - return theme.RenderQuestion(message+"\n"+stdstrings.Join(rendered, "\n")+"\n", hint) -} - -func firstEnabledIndex(choices []Choice) int { - for index, choice := range choices { - if !choice.Disabled { - return index - } - } - return 0 -} - -func defaultChoiceIndex(choices []Choice, value any, hasDefault bool) int { - if !hasDefault { - return firstEnabledIndex(choices) - } - for index, choice := range choices { - if !choice.Disabled && reflect.DeepEqual(choice.Value, value) { - return index - } - } - return firstEnabledIndex(choices) -} - -func choiceByValue(choices []Choice, value any) *Choice { - for index, choice := range choices { - if !choice.Disabled && reflect.DeepEqual(choice.Value, value) { - return &choices[index] - } - } - return nil -} - -func findChoice(choices []Choice, answer string) *Choice { - normalized := stdstrings.TrimSpace(answer) - if numeric, err := strconv.Atoi(normalized); err == nil { - index := numeric - 1 - if index >= 0 && index < len(choices) { - return &choices[index] - } - } - for index, choice := range choices { - if choice.Label == normalized || fmt.Sprint(choice.Value) == normalized { - return &choices[index] - } - } - return nil -} - -func moveChoiceHighlight(choices []Choice, current int, direction int) int { - if len(choices) == 0 { - return 0 - } - index := current - for range choices { - index = (index + direction + len(choices)) % len(choices) - if !choices[index].Disabled { - return index - } - } - return current -} - -func navigationDirection(pressed string) (int, bool) { - switch pressed { - case key.First(key.Down), key.First(key.DownArrow), key.First(key.Tab), "j", "l", key.First(key.Right), key.First(key.RightArrow), key.First(key.CtrlN), key.First(key.CtrlF): - return 1, true - case key.First(key.Up), key.First(key.UpArrow), key.First(key.ShiftTab), "k", "h", key.First(key.Left), key.First(key.LeftArrow), key.First(key.CtrlP), key.First(key.CtrlB): - return -1, true - default: - return 0, false - } -} - -func choiceIndex(value string) (int, bool) { - numeric, err := strconv.Atoi(value) - if err != nil { - return 0, false - } - return numeric - 1, true -} - -func markedChoiceIndexes(choices []Choice, defaults []any) map[int]bool { - marked := map[int]bool{} - for index, choice := range choices { - for _, value := range defaults { - if reflect.DeepEqual(choice.Value, value) { - marked[index] = true - } - } - } - return marked -} - -func markedChoiceValues(choices []Choice, marked map[int]bool) []any { - indexes := sortedMarkedIndexes(marked) - values := make([]any, 0, len(indexes)) - for _, index := range indexes { - values = append(values, choices[index].Value) - } - return values -} - -func markedChoiceLabels(choices []Choice, marked map[int]bool) []string { - indexes := sortedMarkedIndexes(marked) - labels := make([]string, 0, len(indexes)) - for _, index := range indexes { - labels = append(labels, choices[index].Label) - } - return labels -} - -func sortedMarkedIndexes(marked map[int]bool) []int { - indexes := make([]int, 0, len(marked)) - for index, enabled := range marked { - if enabled { - indexes = append(indexes, index) - } - } - sort.Ints(indexes) - return indexes -} - -func toggleMarked(marked map[int]bool, index int) { - if marked[index] { - delete(marked, index) - } else { - marked[index] = true - } -} - -func toggleAllEnabledChoices(choices []Choice, marked map[int]bool) map[int]bool { - allMarked := true - for index, choice := range choices { - if !choice.Disabled && !marked[index] { - allMarked = false - break - } - } - next := map[int]bool{} - if !allMarked { - for index, choice := range choices { - if !choice.Disabled { - next[index] = true - } - } - } - return next -} - -func choicesFromCommaSeparated(choices []Choice, answer string) []any { - parts := stdstrings.Split(answer, ",") - values := make([]any, 0, len(parts)) - for _, part := range parts { - choice := findChoice(choices, part) - if choice != nil && !choice.Disabled { - values = append(values, choice.Value) - } - } - return values -} - -func isConfirmToggleKey(pressed string) bool { - _, ok := navigationDirection(pressed) - return ok || pressed == key.First(key.PageDown) || pressed == key.First(key.PageUp) -} - -func valueOrOriginal(original any, value string) any { - if value == fmt.Sprint(original) { - return original - } - return value -} - -func transformChoice(options ChoiceOptions, value any) (any, error) { - if options.Transform == nil { - return value, nil - } - return options.Transform(value) -} - -func transformedChoiceDefault(options ChoiceOptions) any { - if !options.HasDefault { - return nil - } - value, err := transformChoice(options, options.Default) - if err != nil { - return options.Default - } - return value -} - -func preserveInvalidChoiceDefault(options *ChoiceOptions) prompt.Validator[any] { - return func(value any) (string, error) { - if options.Validate == nil { - return "", nil - } - message, err := options.Validate(value) - if err != nil { - return "", err - } - if message != "" { - options.Default = value - options.HasDefault = true - } - return message, nil - } -} - -func requiredDefault(required prompt.Required, enabled bool) prompt.Required { - if required.Enabled || required.Message != "" { - return required - } - return prompt.Required{Enabled: enabled} -} - -func currentInputState(value string) typedvalue.State { - return typedvalue.State{Cursor: typedvalue.CharacterLength(value), Value: value} -} diff --git a/provision/go/internal/prompts/choices_test.go b/provision/go/internal/prompts/choices_test.go deleted file mode 100644 index 362569a5..00000000 --- a/provision/go/internal/prompts/choices_test.go +++ /dev/null @@ -1,249 +0,0 @@ -package prompts - -import ( - "reflect" - "strings" - "testing" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/prompt" - textutil "github.com/oullin/tui/internal/strings" -) - -func TestConfirmSelectsAndToggles(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"y", key.First(key.Enter)}), func(_ *environment.MemoryOutput) error { - result, err := Confirm(ConfirmOptions{Message: "Continue?", Default: false, HasDefault: true}) - if err != nil { - return err - } - if !result { - t.Fatalf("Confirm() = false") - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withTestEnvironment(environment.NewScriptedInput([]string{key.First(key.Left), "l", key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Confirm(ConfirmOptions{Message: "Continue?"}) - if err != nil { - return err - } - if !result { - t.Fatalf("Confirm(toggle) = false") - } - if !strings.Contains(output.Text(), "\x1b[36mContinue?\x1b[39m") || !strings.Contains(output.Text(), "\x1b[32m●\x1b[39m Yes") { - t.Fatalf("confirm output missing active frame:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestSelectNavigatesDefaultsAndTransforms(t *testing.T) { - choices := NewStringChoices("first", "second", "third") - err := withTestEnvironment(environment.NewScriptedInput([]string{key.First(key.Down), key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Select(ChoiceOptions{Message: "Pick one", Choices: choices}) - if err != nil { - return err - } - if result != "second" { - t.Fatalf("Select() = %#v", result) - } - if !strings.Contains(output.Text(), "Pick one") || !strings.Contains(output.Text(), "second") { - t.Fatalf("select output missing expected frame:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - interactive := false - err = environment.With(environment.Patch{Output: environment.NewMemoryOutput(), ErrorOutput: environment.NewMemoryOutput(), Interactive: &interactive}, func() error { - result, err := Select(ChoiceOptions{ - Message: "Pick one", - Choices: choices, - Default: "second", - HasDefault: true, - Transform: func(value any) (any, error) { - return strings.ToUpper(value.(string)), nil - }, - Validate: func(value any) (string, error) { - if value == "SECOND" { - return "", nil - } - return "Unexpected value.", nil - }, - }) - if err != nil { - return err - } - if result != "SECOND" { - t.Fatalf("noninteractive Select() = %#v", result) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestMultiselectTogglesChoices(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{key.First(key.Space), key.First(key.Down), key.First(key.Space), key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Multiselect(MultiChoiceOptions{Message: "Pick many", Choices: NewStringChoices("first", "second")}) - if err != nil { - return err - } - if !reflect.DeepEqual(result, []any{"first", "second"}) { - t.Fatalf("Multiselect() = %#v", result) - } - if !strings.Contains(output.Text(), "Use the space bar") { - t.Fatalf("multiselect output missing hint:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestSearchFiltersAndValidatesSelections(t *testing.T) { - colors := func(query string) []Choice { - all := []Choice{{Label: "Red", Value: "red"}, {Label: "Green", Value: "green"}, {Label: "Blue", Value: "blue"}} - if query == "" { - return all - } - filtered := make([]Choice, 0) - for _, choice := range all { - if strings.Contains(strings.ToLower(choice.Label), strings.ToLower(query)) { - filtered = append(filtered, choice) - } - } - return filtered - } - - err := withTestEnvironment(environment.NewScriptedInput([]string{"u", "e", key.First(key.Down), key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Search(SearchOptions{Message: "Favorite color?", Source: colors}) - if err != nil { - return err - } - if result != "blue" { - t.Fatalf("Search() = %#v", result) - } - if !strings.Contains(textutil.ParseAnsiText(output.Text()), "ue") || !strings.Contains(output.Text(), "Blue") { - t.Fatalf("search output missing query/result:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withTestEnvironment(environment.NewScriptedInput([]string{key.First(key.Down), key.First(key.Enter), key.First(key.Down), key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Search(SearchOptions{ - Message: "Favorite color?", - Source: colors, - Validate: func(value any) (string, error) { - if value == "red" { - return "Please choose green.", nil - } - return "", nil - }, - }) - if err != nil { - return err - } - if result != "green" { - t.Fatalf("validated Search() = %#v", result) - } - if !strings.Contains(output.Text(), "Please choose green.") { - t.Fatalf("search output missing validation error:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestMultiSearchMarksHighlightedChoices(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{key.First(key.Down), key.First(key.Space), key.First(key.Down), key.First(key.Space), key.First(key.Enter)}), func(_ *environment.MemoryOutput) error { - result, err := MultiSearch(MultiSearchOptions{Message: "Pick colors", Choices: NewStringChoices("red", "green", "blue")}) - if err != nil { - return err - } - if len(result) != 2 || result[0] == result[1] { - t.Fatalf("MultiSearch() = %#v", result) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestSuggestAndAutocomplete(t *testing.T) { - err := withTestEnvironment(environment.NewScriptedInput([]string{"b", key.First(key.Tab), key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Suggest(SuggestOptions{Message: "Favorite color?", Options: []string{"Red", "Green", "Blue"}}) - if err != nil { - return err - } - if result != "Blue" { - t.Fatalf("Suggest() = %q", result) - } - if !strings.Contains(output.Text(), "Blue") { - t.Fatalf("suggest output missing match:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withTestEnvironment(environment.NewScriptedInput([]string{"b", key.First(key.Tab), key.First(key.Enter)}), func(output *environment.MemoryOutput) error { - result, err := Autocomplete(SuggestOptions{Message: "Favorite color?", Options: []string{"Red", "Green", "Blue"}}) - if err != nil { - return err - } - if result != "Blue" { - t.Fatalf("Autocomplete() = %q", result) - } - if !strings.Contains(textutil.ParseAnsiText(output.Text()), "Blue") { - t.Fatalf("autocomplete output missing completion:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestChoiceRequiredValidation(t *testing.T) { - interactive := false - err := environment.With(environment.Patch{Output: environment.NewMemoryOutput(), ErrorOutput: environment.NewMemoryOutput(), Interactive: &interactive}, func() error { - _, err := Select(ChoiceOptions{Message: "Pick one", Choices: NewStringChoices("first", "second")}) - var validation environment.PromptValidationError - if err == nil || !errorsAs(err, &validation) || validation.Message != "Required." { - t.Fatalf("expected required validation error, got %v", err) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func errorsAs(err error, target *environment.PromptValidationError) bool { - if validation, ok := err.(environment.PromptValidationError); ok { - *target = validation - return true - } - return false -} - -var _ = prompt.Required{} diff --git a/provision/go/internal/prompts/number.go b/provision/go/internal/prompts/number.go deleted file mode 100644 index 3ec2c5a3..00000000 --- a/provision/go/internal/prompts/number.go +++ /dev/null @@ -1,230 +0,0 @@ -package prompts - -import ( - "errors" - "fmt" - "math" - "strconv" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/prompt" - "github.com/oullin/tui/internal/theme" - "github.com/oullin/tui/internal/typedvalue" -) - -type NumberOptions struct { - Message string - Placeholder string - Default string - HasDefault bool - Required prompt.Required - Validate prompt.Validator[any] - Hint string - Min float64 - HasMin bool - Max float64 - HasMax bool - Step float64 - HasStep bool - Transform func(any) (any, error) -} - -func Number(options NumberOptions) (any, error) { - shouldRenderSubmittedFrame := false - defaultValue, defaultErr := numberDefault(options) - if defaultErr != nil { - return nil, defaultErr - } - - return prompt.UntilValid( - prompt.Options[any]{Message: options.Message, Default: defaultValue, Required: options.Required, Validate: options.Validate}, - func(_ int) (any, error) { - answer, err := readNumberValue(options.Message, options) - if err != nil { - return nil, err - } - - shouldRenderSubmittedFrame = !answer.Cancelled - if answer.Value == "" && options.HasDefault { - return numberDefault(options) - } - - parsed, err := ParseNumberInput(answer.Value, options) - if err != nil { - return nil, err - } - - return transformNumber(options, parsed) - }, - func(value any) error { - if shouldRenderSubmittedFrame { - renderSubmittedNumberValue(options.Message, value) - } - return nil - }, - ) -} - -func numberDefault(options NumberOptions) (any, error) { - if !options.HasDefault { - return "", nil - } - - parsed, err := ParseNumberInput(options.Default, options) - if err != nil { - return nil, err - } - - return transformNumber(options, parsed) -} - -func transformNumber(options NumberOptions, value any) (any, error) { - if options.Transform == nil { - return value, nil - } - - return options.Transform(value) -} - -func readNumberValue(message string, options NumberOptions) (typedReadResult, error) { - env := environment.Current() - state := typedvalue.State{} - if options.HasDefault { - state = typedvalue.InitialState(options.Default) - } - - renderNumberValue(message, state.Value, options) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(message, options.Hint)) - if lineErr != nil { - return typedReadResult{}, lineErr - } - if answer == "" && options.HasDefault { - answer = options.Default - } - return typedReadResult{Value: answer}, nil - } - return typedReadResult{}, err - } - if !ok { - return typedReadResult{Value: state.Value}, nil - } - - if pressed == key.First(key.Up) || pressed == key.First(key.UpArrow) { - state.Value = steppedNumberValue(state.Value, 1, options) - state.Cursor = typedvalue.CharacterLength(state.Value) - renderNumberValue(message, state.Value, options) - continue - } - - if pressed == key.First(key.Down) || pressed == key.First(key.DownArrow) { - state.Value = steppedNumberValue(state.Value, -1, options) - state.Cursor = typedvalue.CharacterLength(state.Value) - renderNumberValue(message, state.Value, options) - continue - } - - next := typedvalue.ApplyKey(state, pressed, false) - if next.Cancelled { - renderCancelledNumberValue(message, state.Value, options) - value, cancelErr := environment.CancelPrompt(state.Value) - return typedReadResult{Cancelled: true, Value: value}, cancelErr - } - - state = typedvalue.State{Cursor: next.Cursor, Value: next.Value} - if next.Submitted { - return typedReadResult{Value: state.Value}, nil - } - - renderNumberValue(message, state.Value, options) - } -} - -func ParseNumberInput(input string, options NumberOptions) (any, error) { - normalized := stdstrings.TrimSpace(input) - if normalized == "" { - return "", nil - } - - numeric, number := parseFloat(normalized) - if !numeric { - return nil, prompt.ValidationError("Must be a number") - } - - if options.HasMin && number < options.Min { - return nil, prompt.ValidationError(fmt.Sprintf("Must be at least %s", formatNumber(options.Min))) - } - - if options.HasMax && number > options.Max { - return nil, prompt.ValidationError(fmt.Sprintf("Must be less than %s", formatNumber(options.Max))) - } - - return int(math.Trunc(number)), nil -} - -func steppedNumberValue(value string, direction int, options NumberOptions) string { - step := numberStep(options) - if value == "" { - if direction == 1 { - if options.HasMin { - return formatNumber(options.Min) - } - return "1" - } - if options.HasMax { - return formatNumber(options.Max) - } - return "0" - } - - numeric, number := parseFloat(value) - if !numeric { - return value - } - - next := math.Trunc(number) + float64(step*direction) - if options.HasMin && next < options.Min { - next = options.Min - } - if options.HasMax && next > options.Max { - next = options.Max - } - - return formatNumber(next) -} - -func numberStep(options NumberOptions) int { - if options.HasStep && options.Step > 0 { - truncated := int(math.Trunc(options.Step)) - if truncated > 1 { - return truncated - } - } - - return 1 -} - -func parseFloat(value string) (bool, float64) { - if stdstrings.TrimSpace(value) == "" { - return false, 0 - } - number, err := strconv.ParseFloat(value, 64) - if err != nil || math.IsInf(number, 0) || math.IsNaN(number) { - return false, 0 - } - return true, number -} - -func formatNumber(value float64) string { - if math.Trunc(value) == value { - return strconv.FormatInt(int64(value), 10) - } - - return strconv.FormatFloat(value, 'f', -1, 64) -} diff --git a/provision/go/internal/prompts/render.go b/provision/go/internal/prompts/render.go deleted file mode 100644 index 3ace43de..00000000 --- a/provision/go/internal/prompts/render.go +++ /dev/null @@ -1,218 +0,0 @@ -package prompts - -import ( - "fmt" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/strings" - "github.com/oullin/tui/internal/theme" - "github.com/oullin/tui/internal/typedvalue" -) - -const textareaContentWidth = 60 - -func renderTypedValue(message string, state typedvalue.State, options TextOptions) { - env := environment.Current() - if options.AllowNewLine { - env.Output.Write(renderTextareaFrame(message, state, options) + "\n") - if options.Hint != "" { - env.Output.Write(theme.Dim(options.Hint) + "\n") - } - return - } - - display := theme.Dim(options.Placeholder) - if state.Value != "" { - display = typedvalue.VisibleLines(state.Value, state.Cursor, options.Rows) - } - - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: display, BorderStyle: theme.Cyan, Info: options.Hint, Title: theme.Cyan(message)}) + "\n") -} - -func renderSubmittedTypedValue(message string, value string) { - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: value, Title: theme.Dim(message)}) + "\n") -} - -func renderCancelledTypedValue(message string, value string, options TextOptions) { - env := environment.Current() - display := value - if display == "" { - display = options.Placeholder - } - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: theme.Strikethrough(theme.Dim(display)), BorderStyle: theme.Red, Title: message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func renderTextareaFrame(message string, state typedvalue.State, options TextOptions) string { - return theme.RenderBox(theme.BoxOptions{Body: textareaBody(state, options), BorderStyle: theme.Cyan, Info: "Ctrl+D to submit", Title: theme.Cyan(message)}) -} - -func renderSubmittedTextareaFrame(message string, value string) { - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: value, Title: theme.Dim(message)}) + "\n") -} - -func renderCancelledTextareaFrame(message string, value string, options TextOptions) { - env := environment.Current() - body := textareaCancelledBody(value, options) - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: body, BorderStyle: theme.Red, Title: message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func textareaBody(state typedvalue.State, options TextOptions) string { - rows := options.Rows - if rows <= 0 { - rows = 0 - } - - if state.Value == "" { - return placeholderBody(options, rows) - } - - window := typedvalue.VisibleLineWindowFor(state.Value, state.Cursor, rows, textareaContentWidth) - if rows <= 0 { - return stdstrings.Join(window.Lines, "\n") - } - - padded := append([]string{}, window.Lines...) - for len(padded) < rows { - padded = append(padded, "") - } - if len(padded) > rows { - padded = padded[:rows] - } - - return stdstrings.Join(renderScrollbarRows(padded, window.Start, rows, window.Total), "\n") -} - -func placeholderBody(options TextOptions, rows int) string { - lines := []string{theme.Dim(options.Placeholder)} - for rows > 0 && len(lines) < rows { - lines = append(lines, "") - } - - return stdstrings.Join(lines, "\n") -} - -func textareaCancelledBody(value string, options TextOptions) string { - text := value - if text == "" { - text = options.Placeholder - } - - lines := stdstrings.Split(text, "\n") - for index, line := range lines { - lines[index] = theme.Strikethrough(theme.Dim(line)) - } - - return stdstrings.Join(lines, "\n") -} - -func renderPasswordValue(message string, value string, options TextOptions) { - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: passwordDisplay(value, options), BorderStyle: theme.Cyan, Info: options.Hint, Title: theme.Cyan(message)}) + "\n") -} - -func renderSubmittedPasswordValue(message string, value string) { - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: maskPassword(value), Title: theme.Dim(message)}) + "\n") -} - -func renderCancelledPasswordValue(message string, value string, options TextOptions) { - env := environment.Current() - display := maskPassword(value) - if display == "" { - display = options.Placeholder - } - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: theme.Strikethrough(theme.Dim(display)), BorderStyle: theme.Red, Title: message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func maskPassword(value string) string { - return stdstrings.Repeat("•", typedvalue.CharacterLength(value)) -} - -func passwordDisplay(value string, options TextOptions) string { - if value != "" { - return maskPassword(value) - } - - return theme.Dim(options.Placeholder) -} - -func renderNumberValue(message string, value string, options NumberOptions) { - body := renderNumberBody(value, options, func(text string) string { return text }) - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: body, BorderStyle: theme.Cyan, Info: options.Hint, Title: theme.Cyan(message)}) + "\n") -} - -func renderSubmittedNumberValue(message string, value any) { - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: fmt.Sprint(value), Title: theme.Dim(message)}) + "\n") -} - -func renderCancelledNumberValue(message string, value string, options NumberOptions) { - env := environment.Current() - display := value - if display == "" { - display = options.Placeholder - } - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: theme.Strikethrough(theme.Dim(display)), BorderStyle: theme.Red, Title: message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func renderNumberBody(value string, options NumberOptions, style func(string) string) string { - display := value - if display == "" { - display = theme.Dim(options.Placeholder) - } - - return display + " " + renderNumberArrows(value, options, style) -} - -func renderNumberArrows(value string, options NumberOptions, style func(string) string) string { - numeric, number := parseFloat(value) - up := style("▲") - down := style("▼") - if numeric && options.HasMax && number >= options.Max { - up = theme.Dim("▲") - } - if numeric && options.HasMin && number <= options.Min { - down = theme.Dim("▼") - } - if value != "" && !numeric { - return theme.Dim("▲") + theme.Dim("▼") - } - - return up + down -} - -func renderPause(message string) string { - return theme.RenderBox(theme.BoxOptions{Body: "", BorderStyle: theme.Cyan, Title: theme.Cyan(message)}) -} - -func renderScrollbarRows(lines []string, start int, rows int, total int) []string { - if rows <= 0 || total <= rows { - return lines - } - - result := make([]string, len(lines)) - thumbStart := start * rows / total - thumbSize := rows * rows / total - if thumbSize < 1 { - thumbSize = 1 - } - if thumbStart+thumbSize > rows { - thumbStart = rows - thumbSize - } - - for index, line := range lines { - bar := theme.Dim("│") - if index >= thumbStart && index < thumbStart+thumbSize { - bar = theme.Cyan("┃") - } - padding := textareaContentWidth - strings.VisibleWidth(line) - if padding < 0 { - padding = 0 - } - result[index] = line + stdstrings.Repeat(" ", padding) + " " + bar - } - - return result -} diff --git a/provision/go/internal/prompts/search_suggest.go b/provision/go/internal/prompts/search_suggest.go deleted file mode 100644 index ea591b65..00000000 --- a/provision/go/internal/prompts/search_suggest.go +++ /dev/null @@ -1,728 +0,0 @@ -package prompts - -import ( - "errors" - "reflect" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/prompt" - "github.com/oullin/tui/internal/theme" - "github.com/oullin/tui/internal/typedvalue" -) - -type SearchSource func(query string) []Choice - -type SearchOptions struct { - Message string - Choices []Choice - Source SearchSource - Default any - HasDefault bool - Required prompt.Required - Validate prompt.Validator[any] - Placeholder string - Scroll int - Transform func(any) (any, error) -} - -type MultiSearchOptions struct { - Message string - Choices []Choice - Source SearchSource - Defaults []any - Required prompt.Required - Validate prompt.Validator[[]any] - Placeholder string - Scroll int - Transform func([]any) ([]any, error) -} - -type SuggestSource func(query string) []string - -type SuggestOptions struct { - Message string - Options []string - Source SuggestSource - Placeholder string - Default string - Required prompt.Required - Validate prompt.Validator[string] - Hint string - Scroll int - Transform func(string) (string, error) -} - -func Search(options SearchOptions) (any, error) { - if options.Scroll == 0 { - options.Scroll = 5 - } - validate := preserveInvalidSearchDefault(&options) - defaultValue := options.Default - if options.HasDefault && options.Transform != nil { - transformed, err := options.Transform(defaultValue) - if err == nil { - defaultValue = transformed - } - } - - return prompt.UntilValid( - prompt.Options[any]{Message: options.Message, Default: defaultValue, Required: requiredDefault(options.Required, true), Validate: validate}, - func(attempt int) (any, error) { - value, label, submitted, err := readSearchChoice(options, attempt) - if err != nil { - return nil, err - } - if value == nil { - return nil, prompt.ValidationError("Please select a valid option.") - } - if options.Transform != nil { - value, err = options.Transform(value) - if err != nil { - return nil, err - } - } - if submitted { - renderSubmittedChoice(options.Message, label) - } - return value, nil - }, - nil, - ) -} - -func MultiSearch(options MultiSearchOptions) ([]any, error) { - if options.Scroll == 0 { - options.Scroll = 5 - } - return prompt.UntilValid( - prompt.Options[[]any]{Message: options.Message, Default: options.Defaults, Required: options.Required, Validate: options.Validate}, - func(_ int) ([]any, error) { - value, labels, submitted, err := readMultiSearchChoices(options) - if err != nil { - return nil, err - } - if options.Transform != nil { - value, err = options.Transform(value) - if err != nil { - return nil, err - } - } - if submitted { - renderSubmittedChoices(options.Message, labels) - } - return value, nil - }, - nil, - ) -} - -func Suggest(options SuggestOptions) (string, error) { - shouldRenderSubmittedFrame := false - validate := preserveInvalidSuggestDefault(&options) - - return prompt.UntilValid( - prompt.Options[string]{Message: options.Message, Default: transformedSuggestDefault(options), Required: options.Required, Validate: validate}, - func(_ int) (string, error) { - value, rendered, err := readSuggestionValue(options) - if err != nil { - return "", err - } - if value == "" { - value = options.Default - } - shouldRenderSubmittedFrame = rendered - if options.Transform != nil { - return options.Transform(value) - } - return value, nil - }, - func(value string) error { - if shouldRenderSubmittedFrame { - renderSubmittedTypedValue(options.Message, value) - } - return nil - }, - ) -} - -func Autocomplete(options SuggestOptions) (string, error) { - shouldRenderSubmittedFrame := false - validate := preserveInvalidSuggestDefault(&options) - - return prompt.UntilValid( - prompt.Options[string]{Message: options.Message, Default: transformedSuggestDefault(options), Required: options.Required, Validate: validate}, - func(_ int) (string, error) { - value, rendered, err := readAutocompleteValue(options) - if err != nil { - return "", err - } - if value == "" { - value = options.Default - } - shouldRenderSubmittedFrame = rendered - if options.Transform != nil { - return options.Transform(value) - } - return value, nil - }, - func(value string) error { - if shouldRenderSubmittedFrame { - renderSubmittedTypedValue(options.Message, value) - } - return nil - }, - ) -} - -func readSearchChoice(options SearchOptions, attempt int) (any, string, bool, error) { - env := environment.Current() - state := typedvalue.State{} - choices := resolveSearchChoices(options, "") - highlighted := -1 - if attempt > 0 && len(choices) > 0 { - highlighted = 0 - } - renderSearchChoices(options.Message, state.Value, choices, highlighted, nil, false, options.Placeholder, options.Scroll) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(options.Message, "")) - if lineErr != nil { - return nil, "", false, lineErr - } - if stdstrings.TrimSpace(answer) == "" && options.HasDefault { - return options.Default, "", false, nil - } - choice := findChoice(resolveSearchChoices(options, answer), answer) - if choice == nil { - return nil, "", false, nil - } - return choice.Value, choice.Label, false, nil - } - return nil, "", false, err - } - if !ok { - return options.Default, "", false, nil - } - if pressed == key.First(key.CtrlC) { - renderCancelledSearch(options.Message, state.Value, options.Placeholder) - if highlighted >= 0 && highlighted < len(choices) && !choices[highlighted].Disabled { - return choices[highlighted].Value, choices[highlighted].Label, false, nil - } - return options.Default, "", false, nil - } - if action, ok := searchNavigationDirection(pressed); ok && (highlighted >= 0 || action > 0 || attempt > 0) { - choices = resolveSearchChoices(options, state.Value) - highlighted = moveSearchHighlight(choices, highlighted, action, options.Scroll) - renderSearchChoices(options.Message, state.Value, choices, highlighted, nil, false, options.Placeholder, options.Scroll) - continue - } - if clearsHighlight(pressed) && highlighted >= 0 { - highlighted = -1 - renderSearchChoices(options.Message, state.Value, choices, highlighted, nil, false, options.Placeholder, options.Scroll) - continue - } - if pressed == key.First(key.Enter) { - choices = resolveSearchChoices(options, state.Value) - if highlighted >= 0 && highlighted < len(choices) { - choice := choices[highlighted] - return choice.Value, choice.Label, !choice.Disabled, nil - } - if state.Value == "" && options.HasDefault { - choice := choiceByValue(choices, options.Default) - if choice != nil { - return choice.Value, choice.Label, true, nil - } - return options.Default, "", false, nil - } - highlighted = -1 - renderSearchChoices(options.Message, state.Value, choices, highlighted, nil, false, options.Placeholder, options.Scroll) - continue - } - next := typedvalue.ApplyKey(state, pressed, false) - if next.Cancelled { - renderCancelledSearch(options.Message, state.Value, options.Placeholder) - return options.Default, "", false, nil - } - state = typedvalue.State{Cursor: next.Cursor, Value: next.Value} - highlighted = -1 - choices = resolveSearchChoices(options, state.Value) - renderSearchChoices(options.Message, state.Value, choices, highlighted, nil, false, options.Placeholder, options.Scroll) - } -} - -func readMultiSearchChoices(options MultiSearchOptions) ([]any, []string, bool, error) { - env := environment.Current() - state := typedvalue.State{} - choices := resolveMultiSearchChoices(options, "") - highlighted := -1 - selected := map[any]string{} - for _, value := range options.Defaults { - if choice := choiceByValue(choices, value); choice != nil { - selected[choice.Value] = choice.Label - } - } - renderSearchChoices(options.Message, state.Value, choices, highlighted, searchMarked(choices, selected), true, options.Placeholder, options.Scroll) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(options.Message, "")) - if lineErr != nil { - return nil, nil, false, lineErr - } - if stdstrings.TrimSpace(answer) == "" { - return options.Defaults, nil, false, nil - } - return choicesFromCommaSeparated(resolveMultiSearchChoices(options, answer), answer), nil, false, nil - } - return nil, nil, false, err - } - if !ok || pressed == key.First(key.Enter) { - values, labels := selectedSearchValues(selected) - return values, labels, true, nil - } - if pressed == key.First(key.CtrlC) { - renderCancelledSearch(options.Message, state.Value, options.Placeholder) - values, labels := selectedSearchValues(selected) - return values, labels, false, nil - } - if action, ok := searchNavigationDirection(pressed); ok && (highlighted >= 0 || action > 0) { - choices = resolveMultiSearchChoices(options, state.Value) - highlighted = moveSearchHighlight(choices, highlighted, action, options.Scroll) - renderSearchChoices(options.Message, state.Value, choices, highlighted, searchMarked(choices, selected), true, options.Placeholder, options.Scroll) - continue - } - if pressed == key.First(key.Space) && highlighted >= 0 && highlighted < len(choices) { - toggleSearchSelection(selected, choices[highlighted]) - renderSearchChoices(options.Message, state.Value, choices, highlighted, searchMarked(choices, selected), true, options.Placeholder, options.Scroll) - continue - } - next := typedvalue.ApplyKey(state, pressed, false) - if next.Cancelled { - renderCancelledSearch(options.Message, state.Value, options.Placeholder) - return options.Defaults, nil, false, nil - } - state = typedvalue.State{Cursor: next.Cursor, Value: next.Value} - highlighted = -1 - choices = resolveMultiSearchChoices(options, state.Value) - renderSearchChoices(options.Message, state.Value, choices, highlighted, searchMarked(choices, selected), true, options.Placeholder, options.Scroll) - } -} - -func readSuggestionValue(options SuggestOptions) (string, bool, error) { - env := environment.Current() - state := typedvalue.InitialState(options.Default) - highlighted := -1 - matches := resolveSuggestions(options, state.Value) - renderSuggestions(options.Message, state.Value, matches, highlighted, options.Placeholder, options.Scroll) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(options.Message, options.Hint)) - return answer, false, lineErr - } - return "", false, err - } - if !ok { - return state.Value, true, nil - } - if action, ok := suggestionNavigationDirection(pressed); ok && (highlighted >= 0 || action > 0) { - matches = resolveSuggestions(options, state.Value) - highlighted = moveSuggestionHighlight(matches, highlighted, action, options.Scroll) - renderSuggestions(options.Message, state.Value, matches, highlighted, options.Placeholder, options.Scroll) - continue - } - if clearsHighlight(pressed) && highlighted >= 0 { - highlighted = -1 - renderSuggestions(options.Message, state.Value, matches, highlighted, options.Placeholder, options.Scroll) - continue - } - if pressed == key.First(key.Tab) && highlighted < 0 { - matches = resolveSuggestions(options, state.Value) - highlighted = moveSuggestionHighlight(matches, highlighted, 1, options.Scroll) - renderSuggestions(options.Message, state.Value, matches, highlighted, options.Placeholder, options.Scroll) - continue - } - if pressed == key.First(key.Enter) { - if highlighted >= 0 && highlighted < len(matches) { - return matches[highlighted], true, nil - } - return state.Value, true, nil - } - next := typedvalue.ApplyKey(state, pressed, false) - if next.Cancelled { - renderCancelledSuggestion(options.Message, state.Value, options.Placeholder) - value, cancelErr := environment.CancelPrompt(state.Value) - return value, true, cancelErr - } - state = typedvalue.State{Cursor: next.Cursor, Value: next.Value} - highlighted = -1 - matches = resolveSuggestions(options, state.Value) - renderSuggestions(options.Message, state.Value, matches, highlighted, options.Placeholder, options.Scroll) - } -} - -func readAutocompleteValue(options SuggestOptions) (string, bool, error) { - env := environment.Current() - state := typedvalue.InitialState(options.Default) - highlighted := 0 - matches := resolveSuggestions(options, state.Value) - renderAutocomplete(options.Message, state, matches, highlighted, options.Placeholder) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(options.Message, options.Hint)) - return answer, false, lineErr - } - return "", false, err - } - if !ok { - return state.Value, true, nil - } - if direction, ok := autocompleteNavigationDirection(pressed); ok { - matches = resolveSuggestions(options, state.Value) - highlighted = moveSuggestionHighlight(matches, highlighted, direction, 0) - renderAutocomplete(options.Message, state, matches, highlighted, options.Placeholder) - continue - } - if pressed == key.First(key.Tab) && canAcceptAutocomplete(state) { - matches = resolveSuggestions(options, state.Value) - if highlighted >= 0 && highlighted < len(matches) && typedvalue.CharacterLength(matches[highlighted]) > typedvalue.CharacterLength(state.Value) { - state = typedvalue.InitialState(matches[highlighted]) - matches = resolveSuggestions(options, state.Value) - } else { - highlighted = 0 - } - renderAutocomplete(options.Message, state, matches, highlighted, options.Placeholder) - continue - } - if (pressed == key.First(key.Right) || pressed == key.First(key.RightArrow)) && canAcceptAutocomplete(state) { - matches = resolveSuggestions(options, state.Value) - if highlighted >= 0 && highlighted < len(matches) { - state = typedvalue.InitialState(matches[highlighted]) - } - renderAutocomplete(options.Message, state, matches, highlighted, options.Placeholder) - continue - } - next := typedvalue.ApplyKey(state, pressed, false) - if next.Submitted { - return state.Value, true, nil - } - if next.Cancelled { - renderCancelledSuggestion(options.Message, state.Value, options.Placeholder) - value, cancelErr := environment.CancelPrompt(state.Value) - return value, true, cancelErr - } - state = typedvalue.State{Cursor: next.Cursor, Value: next.Value} - highlighted = 0 - matches = resolveSuggestions(options, state.Value) - renderAutocomplete(options.Message, state, matches, highlighted, options.Placeholder) - } -} - -func renderSearchChoices(message string, query string, choices []Choice, highlighted int, marked map[int]bool, multi bool, placeholder string, scroll int) { - bodyLines := []string{queryOrPlaceholder(query, placeholder)} - if len(choices) == 0 { - bodyLines = append(bodyLines, theme.Dim(" No results.")) - } else { - rows := make([]string, len(choices)) - for index, choice := range choices { - pointer := " " - if index == highlighted { - pointer = "›" - } - prefix := pointer + " " - if multi { - if marked[index] { - prefix += "◼ " - } else { - prefix += "◻ " - } - } - label := choice.Label - if choice.Disabled { - label = theme.Dim(label) - } - if index == highlighted { - rows[index] = theme.Cyan(prefix) + label - } else { - rows[index] = " " + prefix + label - } - } - bodyLines = append(bodyLines, windowedRows(rows, max(highlighted, 0), scroll)) - } - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: stdstrings.Join(bodyLines, "\n"), BorderStyle: theme.Cyan, Title: theme.Cyan(message)}) + "\n") -} - -func renderCancelledSearch(message string, query string, placeholder string) { - env := environment.Current() - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: theme.Strikethrough(theme.Dim(queryOrPlaceholder(query, placeholder))), BorderStyle: theme.Red, Title: theme.Dim(message)}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func renderSuggestions(message string, query string, matches []string, highlighted int, placeholder string, scroll int) { - bodyLines := []string{queryOrPlaceholder(query, placeholder)} - rows := make([]string, len(matches)) - for index, match := range matches { - pointer := " " - if index == highlighted { - pointer = "›" - rows[index] = theme.Cyan(pointer) + " " + match - } else { - rows[index] = " " + theme.Dim(match) - } - } - if len(rows) > 0 { - bodyLines = append(bodyLines, windowedRows(rows, max(highlighted, 0), scroll)) - } - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: stdstrings.Join(bodyLines, "\n"), BorderStyle: theme.Cyan, Title: theme.Cyan(message)}) + "\n") -} - -func renderAutocomplete(message string, state typedvalue.State, matches []string, highlighted int, placeholder string) { - body := queryOrPlaceholder(state.Value, placeholder) - if canAcceptAutocomplete(state) && highlighted >= 0 && highlighted < len(matches) && stdstrings.HasPrefix(stdstrings.ToLower(matches[highlighted]), stdstrings.ToLower(state.Value)) { - match := matches[highlighted] - if len(match) > len(state.Value) { - body = state.Value + theme.Inverse(match[len(state.Value):len(state.Value)+1]) + theme.Dim(match[len(state.Value)+1:]) - } else { - body = match - } - } - environment.Current().Output.Write(theme.RenderBox(theme.BoxOptions{Body: body, BorderStyle: theme.Cyan, Title: theme.Cyan(message)}) + "\n") -} - -func renderCancelledSuggestion(message string, value string, placeholder string) { - env := environment.Current() - env.Output.Write(theme.RenderBox(theme.BoxOptions{Body: theme.Strikethrough(theme.Dim(queryOrPlaceholder(value, placeholder))), BorderStyle: theme.Red, Title: message}) + "\n") - env.ErrorOutput.Write(theme.Red(" ⚠ Cancelled.") + "\n") -} - -func resolveSearchChoices(options SearchOptions, query string) []Choice { - if options.Source != nil { - return options.Source(query) - } - return options.Choices -} - -func resolveMultiSearchChoices(options MultiSearchOptions, query string) []Choice { - if options.Source != nil { - return options.Source(query) - } - return options.Choices -} - -func resolveSuggestions(options SuggestOptions, query string) []string { - values := options.Options - if options.Source != nil { - values = options.Source(query) - } - if query == "" { - return values - } - filtered := make([]string, 0, len(values)) - lower := stdstrings.ToLower(query) - for _, value := range values { - if stdstrings.Contains(stdstrings.ToLower(value), lower) { - filtered = append(filtered, value) - } - } - return filtered -} - -func queryOrPlaceholder(query string, placeholder string) string { - if query != "" { - return query - } - return theme.Dim(placeholder) -} - -func searchNavigationDirection(pressed string) (int, bool) { - switch pressed { - case key.First(key.Down), key.First(key.DownArrow), key.First(key.CtrlN): - return 1, true - case key.First(key.Up), key.First(key.UpArrow), key.First(key.CtrlP): - return -1, true - case key.First(key.PageDown), key.First(key.End): - return 5, true - case key.First(key.PageUp), key.Home[0]: - return -5, true - default: - return 0, false - } -} - -func suggestionNavigationDirection(pressed string) (int, bool) { - if direction, ok := searchNavigationDirection(pressed); ok { - return direction, true - } - switch pressed { - case key.First(key.Tab): - return 1, true - case key.First(key.ShiftTab): - return -1, true - default: - return 0, false - } -} - -func autocompleteNavigationDirection(pressed string) (int, bool) { - switch pressed { - case key.First(key.Down), key.First(key.DownArrow): - return 1, true - case key.First(key.Up), key.First(key.UpArrow): - return -1, true - default: - return 0, false - } -} - -func moveSearchHighlight(choices []Choice, highlighted int, direction int, scroll int) int { - if len(choices) == 0 { - return -1 - } - index := highlighted - if index < 0 { - if direction < 0 { - index = len(choices) - } else { - index = -1 - } - } - step := 1 - if direction < 0 { - step = -1 - } - attempts := abs(direction) - if attempts == 0 { - attempts = 1 - } - for range attempts { - index = (index + step + len(choices)) % len(choices) - for choices[index].Disabled { - index = (index + step + len(choices)) % len(choices) - } - } - return index -} - -func moveSuggestionHighlight(matches []string, highlighted int, direction int, _ int) int { - if len(matches) == 0 { - return -1 - } - if highlighted < 0 { - if direction < 0 { - highlighted = len(matches) - } else { - highlighted = -1 - } - } - next := (highlighted + direction) % len(matches) - if next < 0 { - next += len(matches) - } - return next -} - -func clearsHighlight(pressed string) bool { - return pressed == key.First(key.Left) || pressed == key.First(key.LeftArrow) || pressed == key.First(key.Right) || pressed == key.First(key.RightArrow) || pressed == key.First(key.CtrlB) || pressed == key.First(key.CtrlF) -} - -func canAcceptAutocomplete(state typedvalue.State) bool { - return state.Cursor >= typedvalue.CharacterLength(state.Value) -} - -func preserveInvalidSearchDefault(options *SearchOptions) prompt.Validator[any] { - return func(value any) (string, error) { - if options.Validate == nil { - return "", nil - } - message, err := options.Validate(value) - if err != nil { - return "", err - } - if message != "" { - options.Default = value - options.HasDefault = true - } - return message, nil - } -} - -func preserveInvalidSuggestDefault(options *SuggestOptions) prompt.Validator[string] { - return func(value string) (string, error) { - if options.Validate == nil { - return "", nil - } - message, err := options.Validate(value) - if err != nil { - return "", err - } - if message != "" { - options.Default = value - } - return message, nil - } -} - -func transformedSuggestDefault(options SuggestOptions) string { - if options.Transform == nil { - return options.Default - } - value, err := options.Transform(options.Default) - if err != nil { - return options.Default - } - return value -} - -func searchMarked(choices []Choice, selected map[any]string) map[int]bool { - marked := map[int]bool{} - for index, choice := range choices { - if _, ok := selected[choice.Value]; ok { - marked[index] = true - } - } - return marked -} - -func toggleSearchSelection(selected map[any]string, choice Choice) { - if choice.Disabled { - return - } - if _, ok := selected[choice.Value]; ok { - delete(selected, choice.Value) - return - } - selected[choice.Value] = choice.Label -} - -func selectedSearchValues(selected map[any]string) ([]any, []string) { - values := make([]any, 0, len(selected)) - labels := make([]string, 0, len(selected)) - for value, label := range selected { - values = append(values, value) - labels = append(labels, label) - } - return values, labels -} - -func abs(value int) int { - if value < 0 { - return -value - } - return value -} - -func choiceEqual(left any, right any) bool { - return reflect.DeepEqual(left, right) -} diff --git a/provision/go/internal/prompts/text.go b/provision/go/internal/prompts/text.go deleted file mode 100644 index 95cc43ee..00000000 --- a/provision/go/internal/prompts/text.go +++ /dev/null @@ -1,252 +0,0 @@ -package prompts - -import ( - "errors" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/key" - "github.com/oullin/tui/internal/prompt" - "github.com/oullin/tui/internal/theme" - "github.com/oullin/tui/internal/typedvalue" -) - -type TextOptions struct { - Message string - Placeholder string - Default string - Required prompt.Required - Validate prompt.Validator[string] - Hint string - Transform func(string) (string, error) - AllowNewLine bool - Rows int -} - -type typedReadResult struct { - Cancelled bool - Value string -} - -func Text(options TextOptions) (string, error) { - options.AllowNewLine = false - shouldRenderSubmittedFrame := false - validate := preserveInvalidTextDefault(&options) - - return prompt.UntilValid( - prompt.Options[string]{Message: options.Message, Default: transformedDefault(options), Required: options.Required, Validate: validate}, - func(_ int) (string, error) { - answer, err := readTypedValue(options.Message, options) - if err != nil { - return "", err - } - - value := answer.Value - if value == "" { - value = options.Default - } - shouldRenderSubmittedFrame = !answer.Cancelled - return transformText(options, value) - }, - func(value string) error { - if shouldRenderSubmittedFrame { - renderSubmittedTypedValue(options.Message, value) - } - return nil - }, - ) -} - -func Textarea(options TextOptions) (string, error) { - options.AllowNewLine = true - if options.Rows == 0 { - options.Rows = 5 - } - shouldRenderSubmittedFrame := false - validate := preserveInvalidTextDefault(&options) - - return prompt.UntilValid( - prompt.Options[string]{Message: options.Message, Default: transformedDefault(options), Required: options.Required, Validate: validate}, - func(_ int) (string, error) { - answer, err := readTypedValue(options.Message, options) - if err != nil { - return "", err - } - - value := answer.Value - if value == "" { - value = options.Default - } - shouldRenderSubmittedFrame = !answer.Cancelled - return transformText(options, value) - }, - func(value string) error { - if shouldRenderSubmittedFrame { - renderSubmittedTextareaFrame(options.Message, value) - } - return nil - }, - ) -} - -func Password(options TextOptions) (string, error) { - shouldRenderSubmittedFrame := false - validate := preserveInvalidTextDefault(&options) - - return prompt.UntilValid( - prompt.Options[string]{Message: options.Message, Default: transformedDefault(options), Required: options.Required, Validate: validate}, - func(_ int) (string, error) { - answer, err := readPasswordValue(options.Message, options) - if err != nil { - return "", err - } - shouldRenderSubmittedFrame = !answer.Cancelled - return transformText(options, answer.Value) - }, - func(value string) error { - if shouldRenderSubmittedFrame { - renderSubmittedPasswordValue(options.Message, value) - } - return nil - }, - ) -} - -func readTypedValue(message string, options TextOptions) (typedReadResult, error) { - env := environment.Current() - state := typedvalue.InitialState(options.Default) - - renderTypedValue(message, state, options) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(message, options.Hint)) - if lineErr != nil { - return typedReadResult{}, lineErr - } - if answer == "" { - answer = options.Default - } - return typedReadResult{Value: answer}, nil - } - return typedReadResult{}, err - } - if !ok { - return typedReadResult{Value: state.Value}, nil - } - - next := typedvalue.ApplyKey(state, pressed, options.AllowNewLine, textareaContentWidth) - if next.Cancelled { - if options.AllowNewLine { - renderCancelledTextareaFrame(message, state.Value, options) - } else { - renderCancelledTypedValue(message, state.Value, options) - } - value, cancelErr := environment.CancelPrompt(state.Value) - return typedReadResult{Cancelled: true, Value: value}, cancelErr - } - - state = typedvalue.State{Cursor: next.Cursor, Value: next.Value} - if next.Submitted { - return typedReadResult{Value: state.Value}, nil - } - - renderTypedValue(message, state, options) - } -} - -func readPasswordValue(message string, options TextOptions) (typedReadResult, error) { - env := environment.Current() - state := typedvalue.InitialState(options.Default) - - renderPasswordValue(message, state.Value, options) - - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - answer, lineErr := env.Input.ReadLine(theme.RenderQuestion(message, options.Hint)) - if lineErr != nil { - return typedReadResult{}, lineErr - } - return typedReadResult{Value: answer}, nil - } - return typedReadResult{}, err - } - if !ok { - return typedReadResult{Value: state.Value}, nil - } - - next := typedvalue.ApplyKey(state, pressed, false) - if next.Cancelled { - renderCancelledPasswordValue(message, state.Value, options) - value, cancelErr := environment.CancelPrompt(state.Value) - return typedReadResult{Cancelled: true, Value: value}, cancelErr - } - - state = typedvalue.State{Cursor: next.Cursor, Value: next.Value} - if next.Submitted { - return typedReadResult{Value: state.Value}, nil - } - - renderPasswordValue(message, state.Value, options) - } -} - -func Pause(message string) (bool, error) { - env := environment.Current() - if !env.Interactive { - return false, nil - } - - env.Output.Write(renderPause(message)) - for { - pressed, ok, err := env.Input.ReadKey() - if err != nil { - if errors.Is(err, environment.ErrKeyInputUnsupported) { - _, lineErr := prompt.Ask(message, "") - return lineErr == nil, lineErr - } - return false, err - } - if !ok || pressed == key.First(key.Enter) { - env.Output.Write("\n") - return true, nil - } - } -} - -func transformedDefault(options TextOptions) string { - value, err := transformText(options, options.Default) - if err != nil { - return options.Default - } - return value -} - -func transformText(options TextOptions, value string) (string, error) { - if options.Transform == nil { - return value, nil - } - - return options.Transform(value) -} - -func preserveInvalidTextDefault(options *TextOptions) prompt.Validator[string] { - return func(value string) (string, error) { - if options.Validate == nil { - return "", nil - } - - message, err := options.Validate(value) - if err != nil { - return "", err - } - if message != "" { - options.Default = value - } - - return message, nil - } -} diff --git a/provision/go/internal/status/frame.go b/provision/go/internal/status/frame.go deleted file mode 100644 index 91c96708..00000000 --- a/provision/go/internal/status/frame.go +++ /dev/null @@ -1,21 +0,0 @@ -package status - -import ( - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/terminal" -) - -func RenderedFrameLineCount(frame string) int { - trimmed := stdstrings.TrimSuffix(frame, "\n") - if trimmed == "" { - return 0 - } - return len(stdstrings.Split(trimmed, "\n")) -} - -func EraseRenderedFrame(frame string) { - count := RenderedFrameLineCount(frame) - environment.Current().Output.Write(terminal.ErasePreviousLinesSequence(count)) -} diff --git a/provision/go/internal/status/progress.go b/provision/go/internal/status/progress.go deleted file mode 100644 index 8f1a6991..00000000 --- a/provision/go/internal/status/progress.go +++ /dev/null @@ -1,154 +0,0 @@ -package status - -import ( - "fmt" - "math" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/terminal" - "github.com/oullin/tui/internal/theme" -) - -type Progress struct { - current int - label string - hint string - renderedFrame string - cursorHidden bool - Total int -} - -func NewProgress(total int, label string, hint string) *Progress { - if total < 1 { - total = 1 - } - return &Progress{Total: total, label: label, hint: hint} -} - -func (progress *Progress) Start() { - progress.render("active") -} - -func (progress *Progress) Advance(step int) { - progress.current += step - if progress.current < 0 { - progress.current = 0 - } - if progress.current > progress.Total { - progress.current = progress.Total - } - progress.render("active") -} - -func (progress *Progress) Finish() { - progress.render("submit") - progress.restore() -} - -func (progress *Progress) Fail() { - progress.render("error") - progress.restore() -} - -func (progress *Progress) Label(value string) *Progress { - progress.label = value - return progress -} - -func (progress *Progress) Hint(value string) *Progress { - progress.hint = value - return progress -} - -func (progress *Progress) Current() int { - return progress.current -} - -func (progress *Progress) Percentage() float64 { - return float64(progress.current) / float64(progress.Total) -} - -func (progress *Progress) Value() bool { - return true -} - -func (progress *Progress) render(state string) { - output := environment.Current().Output - if !progress.cursorHidden { - output.Write(terminal.HideCursorSequence()) - progress.cursorHidden = true - } - if progress.renderedFrame != "" { - EraseRenderedFrame(progress.renderedFrame) - } - frame := RenderProgressFrame(progress.current, progress.Total, progress.label, progress.hint, state, 60) - output.Write(frame) - progress.renderedFrame = frame -} - -func (progress *Progress) restore() { - if progress.renderedFrame != "" { - EraseRenderedFrame(progress.renderedFrame) - progress.renderedFrame = "" - } - if progress.cursorHidden { - environment.Current().Output.Write(terminal.ShowCursorSequence()) - progress.cursorHidden = false - } -} - -func RunProgress[T any, R any](label string, steps []T, callback func(T, *Progress) (R, error)) ([]R, error) { - bar := NewProgress(len(steps), label, "") - results := make([]R, 0, len(steps)) - bar.Start() - for _, step := range steps { - result, err := callback(step, bar) - if err != nil { - bar.Fail() - return results, err - } - results = append(results, result) - bar.Advance(1) - } - bar.Finish() - return results, nil -} - -func RenderProgressFrame(current int, total int, label string, hint string, state string, width int) string { - if total < 1 { - total = 1 - } - filled := int(math.Ceil(float64(width) * float64(current) / float64(total))) - body := "" - for range filled { - body += "█" - } - lines := []string{theme.RenderBox(theme.BoxOptions{Body: body, Info: FormatProgressFraction(current, total), Title: label, Width: width})} - if state == "active" { - if hint != "" { - lines = append(lines, " "+hint) - } else { - lines = append(lines, "") - } - } - return joinLines(lines) + "\n" -} - -func FormatProgressFraction(current int, total int) string { - return fmt.Sprintf("%s / %s", formatProgressNumber(current), formatProgressNumber(total)) -} - -func formatProgressNumber(value int) string { - text := fmt.Sprintf("%d", value) - if len(text) <= 3 { - return text - } - out := "" - for index, char := range text { - if index > 0 && (len(text)-index)%3 == 0 { - out += "," - } - out += string(char) - } - return out -} diff --git a/provision/go/internal/status/spinner.go b/provision/go/internal/status/spinner.go deleted file mode 100644 index b59de372..00000000 --- a/provision/go/internal/status/spinner.go +++ /dev/null @@ -1,52 +0,0 @@ -package status - -import ( - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/terminal" -) - -var SpinnerFrames = []string{"⠂", "⠒", "⠐", "⠰", "⠠", "⠤", "⠄", "⠆"} - -const StaticSpinnerFrame = "⠶" - -func SpinnerFrame(count int) string { - index := count % len(SpinnerFrames) - if index < 0 { - index += len(SpinnerFrames) - } - return SpinnerFrames[index] -} - -func RenderSpinnerFrame(message string, count ...int) string { - frame := StaticSpinnerFrame - if len(count) > 0 { - frame = SpinnerFrame(count[0]) - } - return " " + frame + " " + message + "\n" -} - -func Spin[T any](message string, callback func() (T, error)) (T, error) { - var zero T - if callback == nil { - return zero, errMissingCallback("spinner") - } - - output := environment.Current().Output - frame := RenderSpinnerFrame(message) - output.Write(terminal.HideCursorSequence()) - output.Write(frame) - defer output.Write(terminal.ShowCursorSequence()) - defer EraseRenderedFrame(frame) - - return callback() -} - -type missingCallbackError string - -func (err missingCallbackError) Error() string { - return string(err) -} - -func errMissingCallback(kind string) error { - return missingCallbackError("a " + kind + " callback is required") -} diff --git a/provision/go/internal/status/status_test.go b/provision/go/internal/status/status_test.go deleted file mode 100644 index 40fc718b..00000000 --- a/provision/go/internal/status/status_test.go +++ /dev/null @@ -1,194 +0,0 @@ -package status - -import ( - "errors" - "strings" - "testing" - - "github.com/oullin/tui/internal/environment" - textutil "github.com/oullin/tui/internal/strings" -) - -func withStatusOutput(callback func(output *environment.MemoryOutput) error) error { - output := environment.NewMemoryOutput() - return environment.With(environment.Patch{Output: output, ErrorOutput: output}, func() error { - return callback(output) - }) -} - -func TestSpinnerFramesAndCleanup(t *testing.T) { - if got := SpinnerFrame(3); got != "⠰" { - t.Fatalf("SpinnerFrame() = %q", got) - } - if got := RenderSpinnerFrame("Working", 3); got != " ⠰ Working\n" { - t.Fatalf("RenderSpinnerFrame() = %q", got) - } - - err := withStatusOutput(func(output *environment.MemoryOutput) error { - result, err := Spin("Working", func() (string, error) { return "done", nil }) - if err != nil { - return err - } - if result != "done" { - t.Fatalf("Spin() = %q", result) - } - rendered := output.Text() - for _, want := range []string{"\x1b[?25l", " ⠶ Working", "\x1b[1A\x1b[2K", "\x1b[?25h"} { - if !strings.Contains(rendered, want) { - t.Fatalf("spinner output missing %q:\n%s", want, rendered) - } - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestProgressManualAndRunner(t *testing.T) { - err := withStatusOutput(func(output *environment.MemoryOutput) error { - bar := NewProgress(2, "Adding States", "") - bar.Start() - bar.Label("ALABAMA").Hint("alabama").Advance(1) - if bar.Current() != 1 || !bar.Value() { - t.Fatalf("progress current/value = %d/%v", bar.Current(), bar.Value()) - } - bar.Finish() - if !strings.Contains(output.Text(), "ALABAMA") || !strings.Contains(output.Text(), "1 / 2") || !strings.Contains(output.Text(), "\x1b[?25h") { - t.Fatalf("progress output missing expected frame:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withStatusOutput(func(output *environment.MemoryOutput) error { - result, err := RunProgress("Uppercasing States", []string{"Alabama", "Alaska"}, func(step string, bar *Progress) (string, error) { - return strings.ToUpper(step), nil - }) - if err != nil { - return err - } - if strings.Join(result, ",") != "ALABAMA,ALASKA" { - t.Fatalf("RunProgress() = %#v", result) - } - if !strings.Contains(output.Text(), "2 / 2") { - t.Fatalf("progress runner output missing completion:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestStreamAppendsClosesAndRenders(t *testing.T) { - err := withStatusOutput(func(output *environment.MemoryOutput) error { - stream := NewStream() - if err := stream.Append("hello"); err != nil { - return err - } - if err := stream.Write(" world"); err != nil { - return err - } - stream.Close() - if stream.Value() != "hello world" || !stream.Closed() { - t.Fatalf("stream value/closed = %q/%v", stream.Value(), stream.Closed()) - } - if err := stream.Append(" later"); err == nil { - t.Fatalf("expected append after close to fail") - } - if !strings.Contains(output.Text(), "\x1b[?25l") || !strings.Contains(output.Text(), "\x1b[?25h") || !strings.Contains(textutil.ParseAnsiText(output.Text()), " hello world") { - t.Fatalf("stream output missing expected frame:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestTaskLoggerAndFrames(t *testing.T) { - err := withStatusOutput(func(output *environment.MemoryOutput) error { - result, err := Task("Running...", func(logger *Logger) (string, error) { - logger.Log("line one") - logger.Log("line two") - logger.Log("line three") - return "done", nil - }, 2, false, "") - if err != nil { - return err - } - if result != "done" { - t.Fatalf("Task() = %q", result) - } - rendered := output.Text() - if strings.Contains(rendered, "line one") || !strings.Contains(rendered, "line two") || !strings.Contains(rendered, "line three") || !strings.Contains(rendered, "\x1b[?25h") { - t.Fatalf("task output missing bounded logs:\n%s", rendered) - } - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = withStatusOutput(func(output *environment.MemoryOutput) error { - _, err := Task("Running...", func(logger *Logger) (string, error) { - logger.Success("created") - logger.Warning("check this") - logger.Error("failed optional step") - return "done", nil - }, 10, true, "") - if err != nil { - return err - } - rendered := output.Text() - for _, want := range []string{" • Running...", "✔ created", "⚠ check this", "✘ failed optional step"} { - if !strings.Contains(rendered, want) { - t.Fatalf("task summary missing %q:\n%s", want, rendered) - } - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestTaskFailureRestoresCursor(t *testing.T) { - failure := errors.New("failed") - err := withStatusOutput(func(output *environment.MemoryOutput) error { - _, err := Task("Running...", func(logger *Logger) (string, error) { - logger.Line("before\x1b[1G\x1b[2Kafter") - return "", failure - }, 10, false, "") - if !errors.Is(err, failure) { - t.Fatalf("Task() error = %v", err) - } - if !strings.Contains(output.Text(), "beforeafter") || !strings.Contains(output.Text(), "\x1b[?25h") { - t.Fatalf("failed task output missing cleanup/sanitized log:\n%s", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} - -func TestFrameLineCountingAndErasing(t *testing.T) { - frame := RenderTaskFrame(TaskFrameOptions{Label: "Running...", Limit: 2, Lines: []string{"line one"}}) - if got := RenderedFrameLineCount(frame); got != 4 { - t.Fatalf("RenderedFrameLineCount() = %d", got) - } - err := withStatusOutput(func(output *environment.MemoryOutput) error { - EraseRenderedFrame(frame) - if output.Text() != strings.Repeat("\x1b[1A\x1b[2K", 4) { - t.Fatalf("EraseRenderedFrame() output = %q", output.Text()) - } - return nil - }) - if err != nil { - t.Fatal(err) - } -} diff --git a/provision/go/internal/status/stream.go b/provision/go/internal/status/stream.go deleted file mode 100644 index 90960933..00000000 --- a/provision/go/internal/status/stream.go +++ /dev/null @@ -1,133 +0,0 @@ -package status - -import ( - "errors" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - text "github.com/oullin/tui/internal/strings" - "github.com/oullin/tui/internal/terminal" - "github.com/oullin/tui/internal/theme" -) - -type Stream struct { - closed bool - buffer *StreamBuffer -} - -func NewStream() *Stream { - environment.Current().Output.Write(terminal.HideCursorSequence()) - return &Stream{buffer: NewStreamBuffer(10)} -} - -func (stream *Stream) Write(content string) error { - return stream.Append(content) -} - -func (stream *Stream) Append(content string) error { - if stream.closed { - return errors.New("stream is closed") - } - stream.buffer.Append(content) - stream.render() - return nil -} - -func (stream *Stream) Close() { - if stream.closed { - return - } - for stream.buffer.FlushNext() { - stream.render() - } - stream.closed = true - environment.Current().Output.Write(terminal.ShowCursorSequence()) -} - -func (stream *Stream) Closed() bool { - return stream.closed -} - -func (stream *Stream) Value() string { - return stream.buffer.Value() -} - -func (stream *Stream) Lines() []string { - return StreamLines(stream.Value(), 60) -} - -func (stream *Stream) render() { - environment.Current().Output.Write(RenderStreamFrame(stream.buffer.StableValue(), stream.buffer.Fading, StreamFadeStyles(false), 60)) -} - -type StreamBuffer struct { - Fading []string - message string - fadeLimit int -} - -func NewStreamBuffer(fadeLimit int) *StreamBuffer { - return &StreamBuffer{fadeLimit: fadeLimit} -} - -func (buffer *StreamBuffer) Append(message string) { - buffer.Fading = append(buffer.Fading, message) - for len(buffer.Fading) > buffer.fadeLimit { - buffer.message += buffer.Fading[0] - buffer.Fading = buffer.Fading[1:] - } -} - -func (buffer *StreamBuffer) FlushNext() bool { - if len(buffer.Fading) == 0 { - return false - } - buffer.message += buffer.Fading[0] - buffer.Fading = buffer.Fading[1:] - return true -} - -func (buffer *StreamBuffer) Value() string { - return buffer.message + stdstrings.Join(buffer.Fading, "") -} - -func (buffer *StreamBuffer) StableValue() string { - return buffer.message -} - -type FadeStyle func(string) string - -func StreamFadeStyles(trueColor bool) []FadeStyle { - if trueColor { - return []FadeStyle{ - func(value string) string { return theme.ForegroundRGB(value, 100, 50, 0) }, - func(value string) string { return theme.ForegroundRGB(value, 50, 25, 0) }, - } - } - return []FadeStyle{func(value string) string { return value }, theme.Dim} -} - -func RenderStreamFrame(value string, fading []string, styles []FadeStyle, width int) string { - rendered := value - for index, chunk := range fading { - style := styles[len(styles)-1] - if index < len(styles) { - style = styles[index] - } - rendered += style(chunk) - } - lines := StreamLines(rendered, width) - for index, line := range lines { - lines[index] = " " + line - } - return stdstrings.Join(lines, "\n") + "\n" -} - -func StreamLines(value string, width int) []string { - parts := stdstrings.Split(value, "\n") - lines := make([]string, 0) - for _, part := range parts { - lines = append(lines, text.Wrap(part, width)...) - } - return lines -} diff --git a/provision/go/internal/status/task.go b/provision/go/internal/status/task.go deleted file mode 100644 index 0bd753db..00000000 --- a/provision/go/internal/status/task.go +++ /dev/null @@ -1,205 +0,0 @@ -package status - -import ( - "regexp" - stdstrings "strings" - - "github.com/oullin/tui/internal/environment" - "github.com/oullin/tui/internal/terminal" -) - -type StableMessage struct { - Type string - Message string -} - -type Logger struct { - LabelValue string - SubLabelValue string - Lines []string - Stable []StableMessage - limit int - stableLimit int - partialBuffer string - partialStart int - hasPartial bool -} - -func NewLogger(limit int, label string, subLabel string) *Logger { - if limit < 0 { - limit = 0 - } - if limit == 0 { - limit = 10 - } - return &Logger{LabelValue: label, SubLabelValue: subLabel, limit: limit, stableLimit: limit} -} - -func (logger *Logger) Limit() int { - return logger.limit -} - -func (logger *Logger) Line(message string) { - logger.writeLines(stdstrings.TrimRight(message, " \t\r\n")) -} - -func (logger *Logger) Log(message string) { - logger.Line(message) -} - -func (logger *Logger) Label(message string) { - logger.LabelValue = message -} - -func (logger *Logger) SubLabel(message string) { - logger.SubLabelValue = message -} - -func (logger *Logger) Partial(chunk string) { - logger.partialBuffer += chunk - if !logger.hasPartial { - logger.partialStart = len(logger.Lines) - logger.hasPartial = true - } - logger.Lines = logger.Lines[:logger.partialStart] - logger.writeLines(logger.partialBuffer) - if logger.partialStart > len(logger.Lines) { - logger.partialStart = len(logger.Lines) - } -} - -func (logger *Logger) CommitPartial() { - logger.partialBuffer = "" - logger.partialStart = 0 - logger.hasPartial = false -} - -func (logger *Logger) Info(message string) { - logger.Line(message) -} - -func (logger *Logger) Success(message string) { - logger.stable("success", message) -} - -func (logger *Logger) Warning(message string) { - logger.stable("warning", message) -} - -func (logger *Logger) Error(message string) { - logger.stable("error", message) -} - -func (logger *Logger) stable(kind string, message string) { - logger.Stable = append(logger.Stable, StableMessage{Type: kind, Message: message}) - logger.Lines = nil - logger.partialBuffer = "" - logger.hasPartial = false - for len(logger.Stable) > logger.stableLimit { - logger.Stable = logger.Stable[1:] - } -} - -func (logger *Logger) writeLines(message string) { - for _, line := range stdstrings.Split(message, "\n") { - if line != "" { - logger.Lines = append(logger.Lines, sanitizeTaskLine(line)) - } - } - for len(logger.Lines) > logger.limit { - logger.Lines = logger.Lines[1:] - } -} - -func Task[T any](label string, callback func(*Logger) (T, error), limit int, keepSummary bool, subLabel string) (T, error) { - var zero T - if callback == nil { - return zero, errMissingCallback("task") - } - logger := NewLogger(limit, label, subLabel) - output := environment.Current().Output - output.Write(terminal.HideCursorSequence()) - defer output.Write(terminal.ShowCursorSequence()) - - frame := RenderTaskFrame(TaskFrameOptions{Label: logger.LabelValue, SubLabel: logger.SubLabelValue, Limit: logger.Limit(), Lines: logger.Lines, StableMessages: logger.Stable}) - output.Write(frame) - - result, err := callback(logger) - EraseRenderedFrame(frame) - if err != nil { - output.Write(RenderTaskFrame(TaskFrameOptions{Label: logger.LabelValue, SubLabel: logger.SubLabelValue, Limit: logger.Limit(), Lines: logger.Lines, StableMessages: logger.Stable})) - return zero, err - } - output.Write(RenderTaskFrame(TaskFrameOptions{Finished: true, KeepSummary: keepSummary, Label: logger.LabelValue, SubLabel: logger.SubLabelValue, Limit: logger.Limit(), Lines: logger.Lines, StableMessages: logger.Stable})) - return result, nil -} - -type TaskFrameOptions struct { - FrameCount int - Finished bool - KeepSummary bool - Label string - Limit int - Lines []string - StableMessages []StableMessage - SubLabel string -} - -func RenderTaskFrame(options TaskFrameOptions) string { - if options.Finished && options.KeepSummary && len(options.StableMessages) > 0 { - lines := []string{" • " + options.Label} - for _, message := range options.StableMessages { - lines = append(lines, renderStableMessage(message)) - } - lines = append(lines, "") - return joinLines(lines) + "\n" - } - - output := []string{stdstrings.TrimRight(RenderSpinnerFrame(options.Label, options.FrameCount), "\n")} - if options.FrameCount == 0 { - output[0] = stdstrings.TrimRight(RenderSpinnerFrame(options.Label), "\n") - } - if options.SubLabel != "" { - output = append(output, " "+options.SubLabel) - } - for _, message := range options.StableMessages { - output = append(output, renderStableMessage(message)) - } - if len(options.StableMessages) > 0 || len(options.Lines) > 0 { - output = append(output, " "+stdstrings.Repeat("─", 60)) - } else { - output = append(output, "") - } - visible := options.Lines - if len(visible) > options.Limit { - visible = visible[len(visible)-options.Limit:] - } - for _, line := range visible { - output = append(output, " "+line) - } - for remaining := options.Limit - len(visible); remaining > 0; remaining-- { - output = append(output, "") - } - return joinLines(output) + "\n" -} - -func renderStableMessage(message StableMessage) string { - symbol := "⚠" - if message.Type == "success" { - symbol = "✔" - } - if message.Type == "error" { - symbol = "✘" - } - return " " + symbol + " " + message.Message -} - -var taskControlPattern = regexp.MustCompile(`\x1b\[1G|\x1b\[2K|\r`) - -func sanitizeTaskLine(line string) string { - return taskControlPattern.ReplaceAllString(line, "") -} - -func joinLines(lines []string) string { - return stdstrings.Join(lines, "\n") -} diff --git a/provision/go/internal/strings/strings.go b/provision/go/internal/strings/strings.go deleted file mode 100644 index 4d1bcbb2..00000000 --- a/provision/go/internal/strings/strings.go +++ /dev/null @@ -1,300 +0,0 @@ -package strings - -import ( - stdstrings "strings" - "unicode/utf8" - - "github.com/mattn/go-runewidth" -) - -const esc = "\x1b" - -type AnsiSegment struct { - Codes string - Text string -} - -var resetCodes = map[string]bool{ - "0": true, - "22": true, - "23": true, - "24": true, - "27": true, - "29": true, - "39": true, - "49": true, -} - -func VisibleWidth(value string) int { - return runewidth.StringWidth(ParseAnsiText(value)) -} - -func Truncate(value string, width int, marker ...string) string { - suffix := "..." - if len(marker) > 0 { - suffix = marker[0] - } - - if width <= 0 { - return "" - } - - if VisibleWidth(value) <= width { - return value - } - - if width <= VisibleWidth(suffix) { - clipped := "" - for _, char := range suffix { - next := clipped + string(char) - if VisibleWidth(next) > width { - break - } - clipped = next - } - - return clipped - } - - result := "" - activeCodes := "" - markerWidth := VisibleWidth(suffix) - - for _, segment := range ParseAnsiSegments(value) { - if segment.Codes != activeCodes { - if activeCodes != "" { - result += ansiCloseSequence(activeCodes) - } - if segment.Codes != "" { - result += segment.Codes - } - activeCodes = segment.Codes - } - - for _, char := range segment.Text { - if VisibleWidth(result+string(char))+markerWidth > width { - if activeCodes != "" { - result += ansiCloseSequence(activeCodes) - } - - return result + suffix - } - - result += string(char) - } - } - - return result -} - -func ParseAnsiSegments(value string) []AnsiSegment { - segments := make([]AnsiSegment, 0) - currentCodes := "" - currentText := "" - - for index := 0; index < len(value); { - if value[index] == '\x1b' && index+1 < len(value) && value[index+1] == '[' { - if currentText != "" { - segments = append(segments, AnsiSegment{Codes: currentCodes, Text: currentText}) - currentText = "" - } - - start := index - index += 2 - for index < len(value) && value[index] != 'm' { - index++ - } - - if index < len(value) && value[index] == 'm' { - index++ - sequence := value[start:index] - code := sequence[2 : len(sequence)-1] - if resetCodes[code] { - currentCodes = "" - } else { - currentCodes = sequence - } - continue - } - - currentText += value[start:] - break - } - - runeValue, size := utf8.DecodeRuneInString(value[index:]) - currentText += string(runeValue) - index += size - } - - if currentText != "" { - segments = append(segments, AnsiSegment{Codes: currentCodes, Text: currentText}) - } - - return segments -} - -func ParseAnsiText(value string) string { - var builder stdstrings.Builder - - for _, segment := range ParseAnsiSegments(value) { - builder.WriteString(segment.Text) - } - - return builder.String() -} - -func Wrap(value string, width int) []string { - plainLines := plainWrap(ParseAnsiText(value), width) - characters := codedCharacters(value) - result := make([]string, 0, len(plainLines)) - characterIndex := 0 - - for _, plainLine := range plainLines { - line := "" - activeCodes := "" - - for _, plainCharacter := range plainLine { - for characterIndex < len(characters) && characters[characterIndex].Text != string(plainCharacter) { - if characters[characterIndex].Text == " " { - characterIndex++ - continue - } - - break - } - - if characterIndex >= len(characters) { - line += string(plainCharacter) - continue - } - - character := characters[characterIndex] - if character.Codes != activeCodes { - if activeCodes != "" { - line += "\x1b[0m" - } - if character.Codes != "" { - line += character.Codes - } - activeCodes = character.Codes - } - - line += string(plainCharacter) - characterIndex++ - } - - if activeCodes != "" { - line += ansiCloseSequence(activeCodes) - } - - result = append(result, line) - } - - return result -} - -func ansiCloseSequence(codes string) string { - code := codes[2 : len(codes)-1] - - switch code { - case "1", "2": - return esc + "[22m" - case "3": - return esc + "[23m" - case "4": - return esc + "[24m" - case "7": - return esc + "[27m" - case "9": - return esc + "[29m" - default: - return esc + "[0m" - } -} - -func codedCharacters(value string) []AnsiSegment { - characters := make([]AnsiSegment, 0) - - for _, segment := range ParseAnsiSegments(value) { - for _, char := range segment.Text { - characters = append(characters, AnsiSegment{Codes: segment.Codes, Text: string(char)}) - } - } - - return characters -} - -func plainWrap(value string, width int) []string { - if width <= 0 { - return []string{value} - } - - lines := make([]string, 0) - for _, originalLine := range stdstrings.Split(value, "\n") { - line := "" - - for _, word := range splitWhitespace(originalLine) { - if VisibleWidth(line+word) <= width { - line += word - continue - } - - if line != "" { - lines = append(lines, stdstrings.TrimRight(line, " \t\r\n")) - line = "" - } - - if VisibleWidth(word) > width { - chunk := "" - for _, char := range word { - next := chunk + string(char) - if VisibleWidth(next) > width { - if chunk != "" { - lines = append(lines, chunk) - } - chunk = "" - } - chunk += string(char) - } - line = chunk - continue - } - - line = stdstrings.TrimLeft(word, " \t\r\n") - } - - lines = append(lines, stdstrings.TrimRight(line, " \t\r\n")) - } - - return lines -} - -func splitWhitespace(value string) []string { - if value == "" { - return []string{""} - } - - parts := make([]string, 0) - current := "" - currentWhitespace := isWhitespace(rune(value[0])) - - for _, char := range value { - whitespace := isWhitespace(char) - if current != "" && whitespace != currentWhitespace { - parts = append(parts, current) - current = "" - } - current += string(char) - currentWhitespace = whitespace - } - - if current != "" { - parts = append(parts, current) - } - - return parts -} - -func isWhitespace(char rune) bool { - return char == ' ' || char == '\t' || char == '\n' || char == '\r' -} diff --git a/provision/go/internal/strings/strings_test.go b/provision/go/internal/strings/strings_test.go deleted file mode 100644 index 920c086f..00000000 --- a/provision/go/internal/strings/strings_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package strings - -import ( - "reflect" - stdstrings "strings" - "testing" -) - -func TestVisibleWidthIgnoresANSI(t *testing.T) { - if got := VisibleWidth("\x1b[31mPrompts\x1b[39m"); got != 7 { - t.Fatalf("VisibleWidth() = %d, want 7", got) - } -} - -func TestTruncate(t *testing.T) { - if got := Truncate("Ollin Prompts", 10); got != "Ollin P..." { - t.Fatalf("Truncate() = %q", got) - } -} - -func TestTruncateClosesANSIStyles(t *testing.T) { - result := Truncate("\x1b[31mOllin Prompts\x1b[39m", 10) - - if got := ParseAnsiText(result); got != "Ollin P..." { - t.Fatalf("ParseAnsiText(truncated) = %q", got) - } - if !stdstrings.Contains(result, "\x1b[31m") { - t.Fatalf("expected red ANSI open sequence in %q", result) - } - if !stdstrings.Contains(result, "\x1b[0m...") { - t.Fatalf("expected reset before marker in %q", result) - } - if stdstrings.HasSuffix(result, "\x1b[39m") { - t.Fatalf("did not expect foreground reset suffix in %q", result) - } -} - -func TestTruncateClipsMarkers(t *testing.T) { - if got := Truncate("Ollin Prompts", 1, "…"); got != "…" { - t.Fatalf("Truncate(marker) = %q", got) - } - if got := Truncate("Ollin Prompts", 1, "東京"); got != "" { - t.Fatalf("Truncate(wide marker) = %q", got) - } -} - -func TestWrap(t *testing.T) { - if got := Wrap("Ollin Prompts", 7); !reflect.DeepEqual(got, []string{"Ollin", "Prompts"}) { - t.Fatalf("Wrap() = %#v", got) - } - - if got := Wrap("😀", 1); !reflect.DeepEqual(got, []string{"😀"}) { - t.Fatalf("Wrap(wide) = %#v", got) - } -} - -func TestParseAnsi(t *testing.T) { - if got := ParseAnsiText("\x1b[32mDone\x1b[39m"); got != "Done" { - t.Fatalf("ParseAnsiText() = %q", got) - } - - if got := ParseAnsiSegments("Hello, World!"); !reflect.DeepEqual(got, []AnsiSegment{{Text: "Hello, World!", Codes: ""}}) { - t.Fatalf("ParseAnsiSegments(plain) = %#v", got) - } - - want := []AnsiSegment{{Text: "Hello ", Codes: ""}, {Text: "Bold", Codes: "\x1b[1m"}, {Text: " World", Codes: ""}} - if got := ParseAnsiSegments("Hello \x1b[1mBold\x1b[0m World"); !reflect.DeepEqual(got, want) { - t.Fatalf("ParseAnsiSegments(styled) = %#v", got) - } - - want = []AnsiSegment{{Text: "Colored", Codes: "\x1b[38;2;255;100;50m"}} - if got := ParseAnsiSegments("\x1b[38;2;255;100;50mColored\x1b[0m"); !reflect.DeepEqual(got, want) { - t.Fatalf("ParseAnsiSegments(rgb) = %#v", got) - } -} - -func TestWrapPreservesANSI(t *testing.T) { - result := Wrap("\x1b[31mHello World\x1b[0m", 5) - - if len(result) != 2 { - t.Fatalf("Wrap() len = %d, want 2: %#v", len(result), result) - } - for _, want := range []string{"Hello", "World"} { - found := false - for _, line := range result { - found = found || stdstrings.Contains(line, want) - } - if !found { - t.Fatalf("expected wrapped output to contain %q: %#v", want, result) - } - } - for _, line := range result { - if !stdstrings.Contains(line, "\x1b[31m") || !stdstrings.HasSuffix(line, "\x1b[0m") { - t.Fatalf("wrapped line does not preserve ANSI: %q", line) - } - } -} diff --git a/provision/go/internal/terminal/terminal.go b/provision/go/internal/terminal/terminal.go deleted file mode 100644 index b446c297..00000000 --- a/provision/go/internal/terminal/terminal.go +++ /dev/null @@ -1,93 +0,0 @@ -package terminal - -import ( - "io" - "math" - "os" -) - -type Size struct { - Columns int - Rows int -} - -type Color [3]int - -func DefaultSize() Size { - return Size{Columns: 80, Rows: 24} -} - -func ClearSequence() string { - return "\x1b[H\x1b[J" -} - -func TitleSequence(title string) string { - return "\x1b]0;" + title + "\x07" -} - -func EraseLineSequence() string { - return "\x1b[2K" -} - -func ErasePreviousLinesSequence(count int) string { - lines := int(math.Max(0, math.Floor(float64(count)))) - result := "" - for range lines { - result += "\x1b[1A\x1b[2K" - } - - return result -} - -func CursorToStartSequence() string { - return "\r" -} - -func HideCursorSequence() string { - return "\x1b[?25l" -} - -func ShowCursorSequence() string { - return "\x1b[?25h" -} - -func WriteClear(writer io.Writer) error { - _, err := io.WriteString(writer, ClearSequence()) - return err -} - -func WriteTitle(writer io.Writer, title string) error { - _, err := io.WriteString(writer, TitleSequence(title)) - return err -} - -func SupportsTrueColor(value ...string) bool { - colorTerm := os.Getenv("COLORTERM") - if len(value) > 0 { - colorTerm = value[0] - } - - return colorTerm == "truecolor" || colorTerm == "24bit" -} - -func DefaultForegroundColor() Color { - return Color{204, 204, 204} -} - -func DefaultBackgroundColor() Color { - return Color{0, 0, 0} -} - -func ParseColor(value []int, fallback Color) Color { - if len(value) != 3 { - return fallback - } - - for _, part := range value { - if part < 0 || part > 255 { - return fallback - } - } - - return Color{value[0], value[1], value[2]} -} diff --git a/provision/go/internal/terminal/terminal_test.go b/provision/go/internal/terminal/terminal_test.go deleted file mode 100644 index c6ccf2a5..00000000 --- a/provision/go/internal/terminal/terminal_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package terminal - -import "testing" - -func TestControlSequences(t *testing.T) { - if got := ClearSequence(); got != "\x1b[H\x1b[J" { - t.Fatalf("ClearSequence() = %q", got) - } - if got := TitleSequence("Demo"); got != "\x1b]0;Demo\x07" { - t.Fatalf("TitleSequence() = %q", got) - } - if got := CursorToStartSequence() + EraseLineSequence() + ErasePreviousLinesSequence(2) + ErasePreviousLinesSequence(-1) + HideCursorSequence() + ShowCursorSequence(); got != "\r\x1b[2K\x1b[1A\x1b[2K\x1b[1A\x1b[2K\x1b[?25l\x1b[?25h" { - t.Fatalf("combined sequences = %q", got) - } -} - -func TestSupportsTrueColor(t *testing.T) { - if !SupportsTrueColor("truecolor") { - t.Fatalf("expected truecolor to be supported") - } - if !SupportsTrueColor("24bit") { - t.Fatalf("expected 24bit to be supported") - } - if SupportsTrueColor("256color") { - t.Fatalf("expected 256color to be unsupported") - } -} - -func TestParseColor(t *testing.T) { - if got := ParseColor([]int{1, 2, 3}, DefaultForegroundColor()); got != (Color{1, 2, 3}) { - t.Fatalf("ParseColor() = %#v", got) - } - if got := ParseColor([]int{0, 0, 300}, DefaultBackgroundColor()); got != DefaultBackgroundColor() { - t.Fatalf("ParseColor(invalid) = %#v", got) - } - if got := ParseColor([]int{1, 2}, DefaultForegroundColor()); got != DefaultForegroundColor() { - t.Fatalf("ParseColor(short) = %#v", got) - } -} diff --git a/provision/go/internal/theme/box.go b/provision/go/internal/theme/box.go deleted file mode 100644 index f7245da2..00000000 --- a/provision/go/internal/theme/box.go +++ /dev/null @@ -1,79 +0,0 @@ -package theme - -import ( - stdstrings "strings" - - text "github.com/oullin/tui/internal/strings" -) - -const defaultBoxWidth = 60 - -type BoxOptions struct { - Body string - BorderStyle func(string) string - Info string - Title string - Width int -} - -func RenderBox(options BoxOptions) string { - borderStyle := options.BorderStyle - if borderStyle == nil { - borderStyle = func(value string) string { return value } - } - - width := options.Width - if width == 0 { - width = defaultBoxWidth - } - - bodyLines := stdstrings.Split(options.Body, "\n") - contentWidth := width - if titleWidth := text.VisibleWidth(options.Title); titleWidth > contentWidth { - contentWidth = titleWidth - } - for _, line := range bodyLines { - if lineWidth := text.VisibleWidth(line); lineWidth > contentWidth { - contentWidth = lineWidth - } - } - - titleWidth := text.VisibleWidth(options.Title) - titleLabel := "" - if titleWidth > 0 { - titleLabel = " " + options.Title + " " - } - - topBorderWidth := contentWidth - titleWidth - if titleWidth == 0 { - topBorderWidth += 2 - } - - renderedInfo := "" - if options.Info != "" { - renderedInfo = text.Truncate(options.Info, contentWidth-1) - } - - bottomBorderWidth := contentWidth + 2 - if renderedInfo != "" { - bottomBorderWidth = contentWidth - text.VisibleWidth(renderedInfo) - } - - lines := []string{ - borderStyle(" ┌") + titleLabel + borderStyle(stdstrings.Repeat("─", topBorderWidth)+"┐"), - } - - for _, line := range bodyLines { - lines = append(lines, borderStyle(" │")+" "+padVisible(line, contentWidth)+" "+borderStyle("│")) - } - - bottom := " └" + stdstrings.Repeat("─", bottomBorderWidth) - if renderedInfo != "" { - bottom += " " + renderedInfo + " " - } - bottom += "┘" - - lines = append(lines, borderStyle(bottom)) - - return stdstrings.Join(lines, "\n") -} diff --git a/provision/go/internal/theme/styles.go b/provision/go/internal/theme/styles.go deleted file mode 100644 index f573253f..00000000 --- a/provision/go/internal/theme/styles.go +++ /dev/null @@ -1,63 +0,0 @@ -package theme - -import "fmt" - -func ansi(open int, close int, value string) string { - if value == "" { - return "" - } - - return fmt.Sprintf("\x1b[%dm%s\x1b[%dm", open, value, close) -} - -func Dim(value string) string { - return ansi(2, 22, value) -} - -func Cyan(value string) string { - return ansi(36, 39, value) -} - -func Green(value string) string { - return ansi(32, 39, value) -} - -func Inverse(value string) string { - return ansi(7, 27, value) -} - -func Black(value string) string { - return ansi(30, 39, value) -} - -func Red(value string) string { - return ansi(31, 39, value) -} - -func Strikethrough(value string) string { - return ansi(9, 29, value) -} - -func White(value string) string { - return ansi(37, 39, value) -} - -func Yellow(value string) string { - return ansi(33, 39, value) -} - -func BackgroundCyan(value string) string { - return ansi(46, 49, value) -} - -func BackgroundRed(value string) string { - return ansi(41, 49, value) -} - -func ForegroundRGB(value string, red int, green int, blue int) string { - if value == "" { - return "" - } - - return fmt.Sprintf("\x1b[38;2;%d;%d;%dm%s\x1b[0m", red, green, blue, value) -} diff --git a/provision/go/internal/theme/theme.go b/provision/go/internal/theme/theme.go deleted file mode 100644 index d424d367..00000000 --- a/provision/go/internal/theme/theme.go +++ /dev/null @@ -1,121 +0,0 @@ -package theme - -import ( - "fmt" - stdstrings "strings" - - text "github.com/oullin/tui/internal/strings" -) - -const ( - SymbolQuestion = "?" - SymbolAnswer = ">" - SymbolError = "!" - SymbolInfo = "i" - SymbolSelected = "●" - SymbolUnselected = "○" - SymbolPointer = "›" - SymbolSuccess = "✓" - SymbolWarning = "!" -) - -func RenderQuestion(message string, hint string) string { - suffix := "" - if hint != "" { - suffix = " " + hint - } - - return fmt.Sprintf("%s %s%s ", SymbolQuestion, message, suffix) -} - -func RenderError(message string) string { - return Red(fmt.Sprintf("%s %s", SymbolError, message)) + "\n" -} - -func RenderTable(headers []string, rows [][]string) string { - columnCount := len(headers) - for _, row := range rows { - if len(row) > columnCount { - columnCount = len(row) - } - } - - if columnCount <= 0 { - return "" - } - - widths := make([]int, columnCount) - for index := range columnCount { - widths[index] = text.VisibleWidth(valueAt(headers, index)) - for _, row := range rows { - width := text.VisibleWidth(valueAt(row, index)) - if width > widths[index] { - widths[index] = width - } - } - } - - renderRow := func(columns []string) string { - parts := make([]string, len(widths)) - for index, width := range widths { - parts[index] = padVisible(valueAt(columns, index), width) - } - - return " │ " + stdstrings.Join(parts, " │ ") + " │" - } - - renderBorder := func(left string, middle string, right string) string { - parts := make([]string, len(widths)) - for index, width := range widths { - parts[index] = stdstrings.Repeat("─", width+2) - } - - return " " + left + stdstrings.Join(parts, middle) + right - } - - top := renderBorder("┌", "┬", "┐") - divider := renderBorder("├", "┼", "┤") - bottom := renderBorder("└", "┴", "┘") - - if len(headers) == 0 { - lines := append([]string{top}, mapRows(rows, renderRow)...) - lines = append(lines, bottom) - return stdstrings.Join(lines, "\n") - } - - dimmedHeaders := make([]string, len(headers)) - for index, header := range headers { - dimmedHeaders[index] = Dim(header) - } - - lines := []string{top, renderRow(dimmedHeaders), divider} - lines = append(lines, mapRows(rows, renderRow)...) - lines = append(lines, bottom) - return stdstrings.Join(lines, "\n") -} - -func valueAt(values []string, index int) string { - if index < 0 || index >= len(values) { - return "" - } - - return values[index] -} - -func padVisible(value string, width int) string { - padding := width - text.VisibleWidth(value) - if padding < 0 { - padding = 0 - } - - return value + stdstrings.Repeat(" ", padding) -} - -func mapRows(rows [][]string, render func([]string) string) []string { - result := make([]string, len(rows)) - for index, row := range rows { - result[index] = render(row) - } - - return result -} diff --git a/provision/go/internal/theme/theme_test.go b/provision/go/internal/theme/theme_test.go deleted file mode 100644 index 6b7c89a8..00000000 --- a/provision/go/internal/theme/theme_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package theme - -import ( - stdstrings "strings" - "testing" -) - -func TestStyles(t *testing.T) { - if got := Red("Error"); got != "\x1b[31mError\x1b[39m" { - t.Fatalf("Red() = %q", got) - } - if got := Dim(""); got != "" { - t.Fatalf("Dim(empty) = %q", got) - } - if got := ForegroundRGB("Text", 1, 2, 3); got != "\x1b[38;2;1;2;3mText\x1b[0m" { - t.Fatalf("ForegroundRGB() = %q", got) - } -} - -func TestRenderQuestionAndError(t *testing.T) { - if got := RenderQuestion("Name?", "required"); got != "? Name? required " { - t.Fatalf("RenderQuestion() = %q", got) - } - if got := RenderError("Required"); got != "\x1b[31m! Required\x1b[39m\n" { - t.Fatalf("RenderError() = %q", got) - } -} - -func TestRenderTable(t *testing.T) { - result := RenderTable([]string{"Name", "Role"}, [][]string{{"Ada", "Admin"}, {"Linus", "User"}}) - - for _, want := range []string{"┌───────┬───────┐", "\x1b[2mName\x1b[22m", "Ada", "Linus", "└───────┴───────┘"} { - if !stdstrings.Contains(result, want) { - t.Fatalf("RenderTable() missing %q in:\n%s", want, result) - } - } -} - -func TestRenderBox(t *testing.T) { - result := RenderBox(BoxOptions{Body: "Ready", Title: "Task", Width: 10}) - - for _, want := range []string{" ┌ Task ──────┐", " │ Ready │", " └────────────┘"} { - if !stdstrings.Contains(result, want) { - t.Fatalf("RenderBox() missing %q in:\n%s", want, result) - } - } -} diff --git a/provision/go/internal/typedvalue/lines.go b/provision/go/internal/typedvalue/lines.go deleted file mode 100644 index 37a58aa9..00000000 --- a/provision/go/internal/typedvalue/lines.go +++ /dev/null @@ -1,168 +0,0 @@ -package typedvalue - -import text "github.com/oullin/tui/internal/strings" - -type LineRange struct { - Start int - End int -} - -type VisibleLineWindow struct { - Lines []string - Start int - Total int -} - -func VisibleLines(value string, cursor int, rows int) string { - lines := VisibleLineWindowFor(value, cursor, rows).Lines - result := "" - for index, line := range lines { - if index > 0 { - result += "\n" - } - result += line - } - - return result -} - -func VisibleLineWindowFor(value string, cursor int, rows int, width ...int) VisibleLineWindow { - valueCharacters := Characters(value) - wrapWidth := 0 - if len(width) > 0 { - wrapWidth = width[0] - } - ranges := lineRanges(valueCharacters, wrapWidth) - - if rows <= 0 { - return VisibleLineWindow{ - Lines: linesForRanges(valueCharacters, ranges), - Start: 0, - Total: len(ranges), - } - } - - line := currentLine(ranges, cursor) - start := max(0, line-rows+1) - end := start + rows - if end > len(ranges) { - end = len(ranges) - } - - return VisibleLineWindow{ - Lines: linesForRanges(valueCharacters, ranges[start:end]), - Start: start, - Total: len(ranges), - } -} - -func MoveLine(value []string, cursor int, direction int, width int) int { - ranges := lineRanges(value, width) - index := currentLine(ranges, cursor) - if index < 0 || index >= len(ranges) { - return cursor - } - - targetIndex := index + direction - if targetIndex < 0 { - return 0 - } - if targetIndex >= len(ranges) { - return len(value) - } - - current := ranges[index] - target := ranges[targetIndex] - column := min(cursor-current.Start, current.End-current.Start) - targetColumn := min(column, target.End-target.Start) - - return target.Start + targetColumn -} - -func MoveToLineBoundary(value []string, cursor int, boundary string) int { - ranges := lineRanges(value, 0) - index := currentLine(ranges, cursor) - if index < 0 || index >= len(ranges) { - return cursor - } - - if boundary == "start" { - return ranges[index].Start - } - - return ranges[index].End -} - -func lineRanges(value []string, width int) []LineRange { - ranges := make([]LineRange, 0) - start := 0 - - for index, char := range value { - if char == "\n" { - ranges = append(ranges, wrappedRanges(value, start, index, width)...) - start = index + 1 - } - } - - ranges = append(ranges, wrappedRanges(value, start, len(value), width)...) - - return ranges -} - -func wrappedRanges(value []string, start int, end int, width int) []LineRange { - if width <= 0 || start == end { - return []LineRange{{Start: start, End: end}} - } - - ranges := make([]LineRange, 0) - rangeStart := start - rangeWidth := 0 - - for index := start; index < end; index++ { - characterWidth := text.VisibleWidth(value[index]) - if rangeWidth > 0 && rangeWidth+characterWidth > width { - ranges = append(ranges, LineRange{Start: rangeStart, End: index}) - rangeStart = index - rangeWidth = 0 - } - - rangeWidth += characterWidth - } - - ranges = append(ranges, LineRange{Start: rangeStart, End: end}) - - return ranges -} - -func currentLine(ranges []LineRange, cursor int) int { - for index, lineRange := range ranges { - if cursor <= lineRange.End { - return index - } - } - - return len(ranges) - 1 -} - -func linesForRanges(value []string, ranges []LineRange) []string { - lines := make([]string, len(ranges)) - for index, lineRange := range ranges { - lines[index] = FromCharacters(value[lineRange.Start:lineRange.End]) - } - - return lines -} - -func min(left int, right int) int { - if left < right { - return left - } - return right -} - -func max(left int, right int) int { - if left > right { - return left - } - return right -} diff --git a/provision/go/internal/typedvalue/typedvalue.go b/provision/go/internal/typedvalue/typedvalue.go deleted file mode 100644 index 9b602a6b..00000000 --- a/provision/go/internal/typedvalue/typedvalue.go +++ /dev/null @@ -1,247 +0,0 @@ -package typedvalue - -import ( - "unicode" - - "github.com/oullin/tui/internal/key" -) - -type State struct { - Cursor int - Value string -} - -type AppliedKey struct { - Cursor int - Value string - Cancelled bool - Submitted bool -} - -func InitialState(value string) State { - return State{Cursor: CharacterLength(value), Value: value} -} - -func ApplyKey(state State, pressed string, allowNewLine bool, wrapWidth ...int) AppliedKey { - value := Characters(state.Value) - cursor := clamp(state.Cursor, 0, len(value)) - width := 0 - if len(wrapWidth) > 0 { - width = wrapWidth[0] - } - - if pressed == key.First(key.CtrlC) { - return result(value, cursor, true, false) - } - - if pressed == key.First(key.CtrlD) && allowNewLine { - return result(value, cursor, false, true) - } - - if pressed == key.First(key.Enter) { - if !allowNewLine { - return result(value, cursor, false, true) - } - - value = insertAt(value, cursor, "\n") - return result(value, cursor+1, false, false) - } - - if moved, ok := moveCursor(value, cursor, pressed, allowNewLine, width); ok { - return result(value, moved, false, false) - } - - if next, ok := deleteKey(value, cursor, pressed, allowNewLine); ok { - return result(next.value, next.cursor, false, false) - } - - if next, ok := insertPrintable(value, cursor, pressed); ok { - return result(next.value, next.cursor, false, false) - } - - return result(value, cursor, false, false) -} - -func Characters(value string) []string { - characters := make([]string, 0) - for _, char := range value { - characters = append(characters, string(char)) - } - - return characters -} - -func FromCharacters(value []string) string { - result := "" - for _, char := range value { - result += char - } - - return result -} - -func CharacterLength(value string) int { - return len(Characters(value)) -} - -func IsPrintable(value string) bool { - if value == "" { - return false - } - - for _, char := range value { - if char < 32 || char == 127 { - return false - } - } - - return true -} - -type cursorResult struct { - cursor int - value []string -} - -func result(value []string, cursor int, cancelled bool, submitted bool) AppliedKey { - return AppliedKey{ - Cancelled: cancelled, - Cursor: cursor, - Submitted: submitted, - Value: FromCharacters(value), - } -} - -func moveCursor(value []string, cursor int, pressed string, allowNewLine bool, wrapWidth int) (int, bool) { - switch pressed { - case key.First(key.Left), key.First(key.LeftArrow), key.First(key.CtrlB): - return max(0, cursor-1), true - case key.First(key.Right), key.First(key.RightArrow), key.First(key.CtrlF): - return min(len(value), cursor+1), true - } - - if allowNewLine { - switch pressed { - case key.First(key.Up), key.First(key.UpArrow), key.First(key.CtrlP): - return MoveLine(value, cursor, -1, wrapWidth), true - case key.First(key.Down), key.First(key.DownArrow), key.First(key.CtrlN): - return MoveLine(value, cursor, 1, wrapWidth), true - } - } - - if _, ok := key.OneOf([]key.Value{key.Home, key.CtrlA}, pressed); ok { - if allowNewLine { - return MoveToLineBoundary(value, cursor, "start"), true - } - return 0, true - } - - if _, ok := key.OneOf([]key.Value{key.End, key.CtrlE}, pressed); ok { - if allowNewLine { - return MoveToLineBoundary(value, cursor, "end"), true - } - return len(value), true - } - - return 0, false -} - -func deleteKey(value []string, cursor int, pressed string, allowNewLine bool) (cursorResult, bool) { - switch pressed { - case key.First(key.Delete): - return cursorResult{cursor: cursor, value: deleteRange(value, cursor, cursor+1)}, true - case key.First(key.CtrlU): - start := 0 - if allowNewLine { - start = MoveToLineBoundary(value, cursor, "start") - } - return cursorResult{cursor: start, value: deleteRange(value, start, cursor)}, true - case key.First(key.Backspace), key.First(key.CtrlH): - if cursor == 0 { - return cursorResult{cursor: cursor, value: value}, true - } - return cursorResult{cursor: cursor - 1, value: deleteRange(value, cursor-1, cursor)}, true - case key.First(key.OptionBackspace): - start := previousWordStart(value, cursor) - return cursorResult{cursor: start, value: deleteRange(value, start, cursor)}, true - default: - return cursorResult{}, false - } -} - -func insertPrintable(value []string, cursor int, pressed string) (cursorResult, bool) { - if !IsPrintable(pressed) { - return cursorResult{}, false - } - - next := append([]string{}, value...) - nextCursor := cursor - for _, char := range Characters(pressed) { - next = insertAt(next, nextCursor, char) - nextCursor++ - } - - return cursorResult{cursor: nextCursor, value: next}, true -} - -func insertAt(value []string, cursor int, char string) []string { - next := append([]string{}, value[:cursor]...) - next = append(next, char) - next = append(next, value[cursor:]...) - return next -} - -func deleteRange(value []string, start int, end int) []string { - start = clamp(start, 0, len(value)) - end = clamp(end, start, len(value)) - next := append([]string{}, value[:start]...) - next = append(next, value[end:]...) - return next -} - -func previousWordStart(value []string, cursor int) int { - index := clamp(cursor, 0, len(value)) - for index > 0 && isSpace([]rune(value[index-1])[0]) { - index-- - } - - if index == 0 { - return 0 - } - - char := []rune(value[index-1])[0] - if isWord(char) { - for index > 0 && isWord([]rune(value[index-1])[0]) { - index-- - } - return index - } - - for index > 0 { - previous := []rune(value[index-1])[0] - if isWord(previous) || isSpace(previous) { - break - } - index-- - } - - return index -} - -func isWord(char rune) bool { - return unicode.IsLetter(char) || unicode.IsMark(char) || unicode.IsNumber(char) -} - -func isSpace(char rune) bool { - return unicode.IsSpace(char) -} - -func clamp(value int, low int, high int) int { - if value < low { - return low - } - if value > high { - return high - } - return value -} diff --git a/provision/go/internal/typedvalue/typedvalue_test.go b/provision/go/internal/typedvalue/typedvalue_test.go deleted file mode 100644 index 0b71ea42..00000000 --- a/provision/go/internal/typedvalue/typedvalue_test.go +++ /dev/null @@ -1,139 +0,0 @@ -package typedvalue - -import ( - "reflect" - "testing" - - "github.com/oullin/tui/internal/key" -) - -func apply(keys []string) string { - state := State{} - for _, pressed := range keys { - next := ApplyKey(state, pressed, false) - state = State{Cursor: next.Cursor, Value: next.Value} - } - - return state.Value -} - -func applyMultiline(keys []string) AppliedKey { - state := State{} - var next AppliedKey - for _, pressed := range keys { - next = ApplyKey(state, pressed, true) - state = State{Cursor: next.Cursor, Value: next.Value} - } - - return next -} - -func applyMultilineState(value string, cursor int, keys []string, wrapWidth ...int) State { - state := State{Cursor: cursor, Value: value} - for _, pressed := range keys { - next := ApplyKey(state, pressed, true, wrapWidth...) - state = State{Cursor: next.Cursor, Value: next.Value} - } - - return state -} - -func TestTypedValueInsertionAndDeletion(t *testing.T) { - if got := apply([]string{"Je", "ss"}); got != "Jess" { - t.Fatalf("apply(insert) = %q", got) - } - - if got := apply([]string{"J", "e", "z", key.First(key.Backspace), "s", "s"}); got != "Jess" { - t.Fatalf("apply(backspace) = %q", got) - } - - if got := apply([]string{"J", "e", "z", key.First(key.Left), key.First(key.Delete), "s", "s"}); got != "Jess" { - t.Fatalf("apply(delete) = %q", got) - } - - if got := apply([]string{"J", "e", "s", "s", key.First(key.Delete)}); got != "Jess" { - t.Fatalf("apply(delete at end) = %q", got) - } -} - -func TestTypedValueMovementAndCancellation(t *testing.T) { - if got := apply([]string{"J", "a", "n", "e", key.First(key.Left), key.First(key.Left), key.First(key.CtrlU), "D", "o"}); got != "Done" { - t.Fatalf("apply(ctrl-u) = %q", got) - } - - if got := apply([]string{"J", "z", "e", key.First(key.CtrlB), key.First(key.CtrlH), key.First(key.CtrlF), "s", "s"}); got != "Jess" { - t.Fatalf("apply(emacs movement) = %q", got) - } - - got := ApplyKey(State{Cursor: 3, Value: "Ada"}, key.First(key.CtrlC), false) - want := AppliedKey{Cancelled: true, Cursor: 3, Submitted: false, Value: "Ada"} - if got != want { - t.Fatalf("ApplyKey(ctrl-c) = %#v, want %#v", got, want) - } -} - -func TestTypedValueUnicodeAndPreviousWordDeletion(t *testing.T) { - if got := applyMultilineState("😀", len("😀"), []string{"!"}); got != (State{Cursor: 2, Value: "😀!"}) { - t.Fatalf("unicode clamp = %#v", got) - } - - if got := applyMultilineState("😀 hello", len([]rune("😀 hello")), []string{key.First(key.OptionBackspace)}); got != (State{Cursor: 2, Value: "😀 "}) { - t.Fatalf("previous word after emoji = %#v", got) - } - - if got := applyMultilineState("hello --", len([]rune("hello --")), []string{key.First(key.OptionBackspace)}); got != (State{Cursor: 6, Value: "hello "}) { - t.Fatalf("previous punctuation group = %#v", got) - } -} - -func TestTypedValueLineMovement(t *testing.T) { - if got := apply([]string{"A", "r", key.Home[0], "J", key.End[0], "c", "h", "e", "r"}); got != "JArcher" { - t.Fatalf("home/end = %q", got) - } - - if got := applyMultiline([]string{"A", key.First(key.Enter), "B", key.First(key.CtrlD)}); !got.Submitted || got.Value != "A\nB" { - t.Fatalf("multiline submit = %#v", got) - } - - tests := []struct { - name string - got State - want State - }{ - {name: "up", got: applyMultilineState("abc\nde\nfghi", 6, []string{key.First(key.Up)}), want: State{Cursor: 2, Value: "abc\nde\nfghi"}}, - {name: "down", got: applyMultilineState("abc\nde\nfghi", 2, []string{key.First(key.Down)}), want: State{Cursor: 6, Value: "abc\nde\nfghi"}}, - {name: "down long", got: applyMultilineState("abc\nde\nfghi", 6, []string{key.First(key.Down)}), want: State{Cursor: 9, Value: "abc\nde\nfghi"}}, - {name: "ctrl-p", got: applyMultilineState("abc\nde\nfghi", 6, []string{key.First(key.CtrlP)}), want: State{Cursor: 2, Value: "abc\nde\nfghi"}}, - {name: "ctrl-n", got: applyMultilineState("abc\nde\nfghi", 2, []string{key.First(key.CtrlN)}), want: State{Cursor: 6, Value: "abc\nde\nfghi"}}, - {name: "wrapped up", got: applyMultilineState("abcdefghijkl", 7, []string{key.First(key.Up)}, 5), want: State{Cursor: 2, Value: "abcdefghijkl"}}, - {name: "wrapped down", got: applyMultilineState("abcdefghijkl", 2, []string{key.First(key.Down)}, 5), want: State{Cursor: 7, Value: "abcdefghijkl"}}, - {name: "wrapped up from end", got: applyMultilineState("abcdefghijkl", 11, []string{key.First(key.Up)}, 5), want: State{Cursor: 6, Value: "abcdefghijkl"}}, - {name: "home line", got: applyMultilineState("abc\nde\nfghi", 5, []string{key.Home[0]}), want: State{Cursor: 4, Value: "abc\nde\nfghi"}}, - {name: "end line", got: applyMultilineState("abc\nde\nfghi", 5, []string{key.End[0]}), want: State{Cursor: 6, Value: "abc\nde\nfghi"}}, - {name: "ctrl-u line", got: applyMultilineState("abc\nde\nfghi", 9, []string{key.First(key.CtrlU)}), want: State{Cursor: 7, Value: "abc\nde\nhi"}}, - } - - for _, test := range tests { - if test.got != test.want { - t.Fatalf("%s = %#v, want %#v", test.name, test.got, test.want) - } - } - - if got := applyMultilineState("abc\nde\nfghi", 9, []string{key.First(key.CtrlA), "X", key.First(key.CtrlE), "Y"}); got != (State{Cursor: 13, Value: "abc\nde\nXfghiY"}) { - t.Fatalf("ctrl-a/ctrl-e edit = %#v", got) - } -} - -func TestVisibleLineWindow(t *testing.T) { - got := VisibleLineWindowFor("A\nB\nC", 5, 2) - want := VisibleLineWindow{Lines: []string{"B", "C"}, Start: 1, Total: 3} - if !reflect.DeepEqual(got, want) { - t.Fatalf("VisibleLineWindowFor() = %#v, want %#v", got, want) - } - - got = VisibleLineWindowFor("abcdefghijkl", 12, 2, 5) - want = VisibleLineWindow{Lines: []string{"fghij", "kl"}, Start: 1, Total: 3} - if !reflect.DeepEqual(got, want) { - t.Fatalf("VisibleLineWindowFor(wrapped) = %#v, want %#v", got, want) - } -} diff --git a/provision/go/package.json b/provision/go/package.json deleted file mode 100644 index a12205f2..00000000 --- a/provision/go/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@ollin/shell", - "version": "0.1.0", - "private": true, - "scripts": { - "build": "mkdir -p ../.cache/bin ../.cache/go-build ../.cache/go-mod ../.cache/go-tmp && GOCACHE=$PWD/../.cache/go-build GOMODCACHE=$PWD/../.cache/go-mod GOTMPDIR=$PWD/../.cache/go-tmp go build -o ../.cache/bin/shell ./portal", - "test": "mkdir -p ../.cache/go-build ../.cache/go-mod ../.cache/go-tmp && GOCACHE=$PWD/../.cache/go-build GOMODCACHE=$PWD/../.cache/go-mod GOTMPDIR=$PWD/../.cache/go-tmp go test ./...", - "typecheck": "mkdir -p ../.cache/go-build ../.cache/go-mod ../.cache/go-tmp && GOCACHE=$PWD/../.cache/go-build GOMODCACHE=$PWD/../.cache/go-mod GOTMPDIR=$PWD/../.cache/go-tmp go test ./... -run '^$'" - } -} diff --git a/provision/go/portal/config.go b/provision/go/portal/config.go deleted file mode 100644 index 9fc40811..00000000 --- a/provision/go/portal/config.go +++ /dev/null @@ -1,157 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "io" - "os" - "path/filepath" - stdstrings "strings" - - "github.com/spf13/pflag" - "github.com/spf13/viper" -) - -const ( - defaultCommand = "home" - versionCommand = "version" - formCommand = "form" -) - -type portalConfig struct { - Command string - ProjectDefault string - RuntimeDefault string - CreateDefault bool - Interactive bool -} - -func loadPortalConfig(args []string) (portalConfig, error) { - settings := viper.New() - settings.SetEnvPrefix("OLLIN_SHELL") - settings.SetEnvKeyReplacer(stdstrings.NewReplacer(".", "_", "-", "_")) - settings.AutomaticEnv() - - settings.SetDefault("command", defaultCommand) - settings.SetDefault("form.project", "") - settings.SetDefault("form.runtime", "Go") - settings.SetDefault("form.create", true) - settings.SetDefault("interactive", true) - - flags := pflag.NewFlagSet("shell", pflag.ContinueOnError) - flags.SetOutput(io.Discard) - flags.String("config", "", "Path to a shell config file.") - flags.String("command", "", "Command to run.") - flags.String("project", "", "Default project name for the form command.") - flags.String("runtime", "", "Default runtime for the form command.") - flags.Bool("create", true, "Default create confirmation for the form command.") - flags.Bool("interactive", true, "Enable interactive prompts.") - flags.Bool("version", false, "Print the shell version.") - - if err := flags.Parse(args); err != nil { - return portalConfig{}, err - } - - if err := settings.BindPFlag("config", flags.Lookup("config")); err != nil { - return portalConfig{}, err - } - if err := settings.BindPFlag("command", flags.Lookup("command")); err != nil { - return portalConfig{}, err - } - if err := settings.BindPFlag("form.project", flags.Lookup("project")); err != nil { - return portalConfig{}, err - } - if err := settings.BindPFlag("form.runtime", flags.Lookup("runtime")); err != nil { - return portalConfig{}, err - } - if err := settings.BindPFlag("form.create", flags.Lookup("create")); err != nil { - return portalConfig{}, err - } - if err := settings.BindPFlag("interactive", flags.Lookup("interactive")); err != nil { - return portalConfig{}, err - } - - if configPath := settings.GetString("config"); configPath != "" { - settings.SetConfigFile(configPath) - if !hasKnownConfigExtension(configPath) { - settings.SetConfigType("yaml") - } - if err := settings.ReadInConfig(); err != nil { - return portalConfig{}, err - } - } else { - settings.SetConfigName("shell") - settings.SetConfigType("yaml") - settings.AddConfigPath(".") - if home, err := os.UserHomeDir(); err == nil { - settings.AddConfigPath(home + "/.config/ollin") - } - if err := settings.ReadInConfig(); err != nil { - var notFound viper.ConfigFileNotFoundError - if !errors.As(err, ¬Found) { - return portalConfig{}, err - } - } - } - - if flags.Changed("version") && settings.GetBool("version") { - settings.Set("command", versionCommand) - } - - if command := firstPositionalCommand(flags.Args()); command != "" && !flags.Changed("command") { - settings.Set("command", command) - } - - config := portalConfig{ - Command: normalizeCommand(settings.GetString("command")), - ProjectDefault: settings.GetString("form.project"), - RuntimeDefault: settings.GetString("form.runtime"), - CreateDefault: settings.GetBool("form.create"), - Interactive: settings.GetBool("interactive"), - } - if err := config.validate(); err != nil { - return portalConfig{}, err - } - - return config, nil -} - -func firstPositionalCommand(args []string) string { - if len(args) == 0 { - return "" - } - - return args[0] -} - -func normalizeCommand(command string) string { - command = stdstrings.TrimSpace(stdstrings.ToLower(command)) - if command == "" { - return defaultCommand - } - - return command -} - -func hasKnownConfigExtension(path string) bool { - switch stdstrings.ToLower(filepath.Ext(path)) { - case ".json", ".toml", ".yaml", ".yml", ".env", ".hcl", ".ini", ".properties", ".props", ".prop": - return true - default: - return false - } -} - -func (config portalConfig) validate() error { - switch config.Command { - case defaultCommand, versionCommand, formCommand: - default: - return fmt.Errorf("unknown command %q", config.Command) - } - - if config.RuntimeDefault != "Go" && config.RuntimeDefault != "TypeScript" { - return fmt.Errorf("unsupported runtime %q", config.RuntimeDefault) - } - - return nil -} diff --git a/provision/go/portal/main.go b/provision/go/portal/main.go deleted file mode 100644 index 78c6f1a3..00000000 --- a/provision/go/portal/main.go +++ /dev/null @@ -1,89 +0,0 @@ -package main - -import ( - "fmt" - "os" - - tui "github.com/oullin/tui" - "golang.org/x/term" -) - -func main() { - if err := run(os.Args[1:]); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func run(args []string) error { - config, err := loadPortalConfig(args) - if err != nil { - return err - } - - if config.Command == versionCommand { - fmt.Println("@ollin/shell 0.1.0") - return nil - } - - configureStdioEnvironment(config) - - if config.Command == formCommand { - return runFormCommand(config) - } - - tui.Intro("Oullin TUI shell") - tui.Info("Commands: version, form") - return nil -} - -func configureStdioEnvironment(config portalConfig) { - interactive := config.Interactive - tui.Configure(tui.Patch{ - Input: tui.NewStdioInput(os.Stdin, os.Stdout), - Output: tui.NewWriterOutput(os.Stdout), - ErrorOutput: tui.NewWriterOutput(os.Stderr), - Interactive: &interactive, - }) -} - -func runFormCommand(config portalConfig) error { - restore, err := enableRawInput() - if err != nil { - return err - } - defer restore() - - responses, err := tui.Form(). - Text(tui.TextOptions{Message: "Project name", Default: config.ProjectDefault, Required: tui.Required{Enabled: true}}). - Select(tui.ChoiceOptions{Message: "Runtime", Choices: tui.NewStringChoices("Go", "TypeScript"), Default: config.RuntimeDefault, HasDefault: true}). - Confirm(tui.ConfirmOptions{Message: "Create project?", Default: config.CreateDefault, HasDefault: true}). - Submit() - if err != nil { - return err - } - - tui.Table([]string{"Field", "Value"}, [][]any{ - {"Project", responses.At(0)}, - {"Runtime", responses.At(1)}, - {"Create", responses.At(2)}, - }) - - return nil -} - -func enableRawInput() (func(), error) { - file := os.Stdin - if !term.IsTerminal(int(file.Fd())) { - return func() {}, nil - } - - state, err := term.MakeRaw(int(file.Fd())) - if err != nil { - return nil, err - } - - return func() { - _ = term.Restore(int(file.Fd()), state) - }, nil -} diff --git a/provision/go/portal/main_test.go b/provision/go/portal/main_test.go deleted file mode 100644 index 9baadaa4..00000000 --- a/provision/go/portal/main_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package main - -import ( - "bytes" - "os" - "os/exec" - "path/filepath" - "strings" - "testing" -) - -func TestPortalVersionCommand(t *testing.T) { - output := runPortal(t, nil, "version") - - if strings.TrimSpace(output) != "@ollin/shell 0.1.0" { - t.Fatalf("version output = %q", output) - } -} - -func TestPortalDefaultCommandShowsRealCommands(t *testing.T) { - output := runPortal(t, nil) - - if !strings.Contains(output, "Oullin TUI shell") || !strings.Contains(output, "Commands: version, form") { - t.Fatalf("default output = %q", output) - } -} - -func TestPortalFormCommandUsesRealStdio(t *testing.T) { - output := runPortal(t, []byte("Ada\n\n\n"), "form") - - for _, want := range []string{"Project name", "Runtime", "Create project?", "Project", "Ada", "Runtime", "Go", "Create", "true"} { - if !strings.Contains(output, want) { - t.Fatalf("form output missing %q:\n%s", want, output) - } - } -} - -func TestPortalBindsViperFlagsIntoFormDefaults(t *testing.T) { - output := runPortal(t, []byte("\n\n\n"), "form", "--project", "Flag App", "--runtime", "TypeScript", "--create=false") - - for _, want := range []string{"Flag App", "TypeScript", "false"} { - if !strings.Contains(output, want) { - t.Fatalf("flag-backed form output missing %q:\n%s", want, output) - } - } -} - -func TestPortalBindsViperEnvIntoCommandAndDefaults(t *testing.T) { - output := runPortalWithEnv(t, []byte("\n\n\n"), []string{ - "OLLIN_SHELL_COMMAND=form", - "OLLIN_SHELL_FORM_PROJECT=Env App", - "OLLIN_SHELL_FORM_RUNTIME=TypeScript", - "OLLIN_SHELL_FORM_CREATE=false", - }) - - for _, want := range []string{"Env App", "TypeScript", "false"} { - if !strings.Contains(output, want) { - t.Fatalf("env-backed form output missing %q:\n%s", want, output) - } - } -} - -func TestPortalReadsViperConfigFile(t *testing.T) { - configPath := filepath.Join(t.TempDir(), "shell") - err := os.WriteFile(configPath, []byte(strings.Join([]string{ - "command: form", - "form:", - " project: Config App", - " runtime: TypeScript", - " create: false", - "", - }, "\n")), 0o600) - if err != nil { - t.Fatal(err) - } - - output := runPortal(t, []byte("\n\n\n"), "--config", configPath) - - for _, want := range []string{"Config App", "TypeScript", "false"} { - if !strings.Contains(output, want) { - t.Fatalf("config-backed form output missing %q:\n%s", want, output) - } - } -} - -func runPortal(t *testing.T, stdin []byte, args ...string) string { - return runPortalWithEnv(t, stdin, nil, args...) -} - -func runPortalWithEnv(t *testing.T, stdin []byte, env []string, args ...string) string { - t.Helper() - - commandArgs := append([]string{"run", "."}, args...) - command := exec.Command("go", commandArgs...) - command.Stdin = bytes.NewReader(stdin) - command.Env = append(os.Environ(), env...) - - output, err := command.CombinedOutput() - if err != nil { - t.Fatalf("go run . %s failed: %v\n%s", strings.Join(args, " "), err, output) - } - - return string(output) -} diff --git a/provision/ts/package.json b/provision/ts/package.json deleted file mode 100644 index c1231910..00000000 --- a/provision/ts/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@ollin/provision-ts", - "version": "0.1.0", - "private": true, - "type": "module", - "imports": { - "#provision-ts/*": "./src/*.ts" - }, - "scripts": { - "build": "XDG_CACHE_HOME=../.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../.cache/playwright tsc -p tsconfig.json --noEmit", - "test": "node -e \"\"", - "typecheck": "XDG_CACHE_HOME=../.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../.cache/playwright tsc -p tsconfig.json --noEmit" - }, - "devDependencies": { - "@ollin/tsconfig": "workspace:*" - } -} diff --git a/provision/ts/src/cache.ts b/provision/ts/src/cache.ts deleted file mode 100644 index 1b9c151f..00000000 --- a/provision/ts/src/cache.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { dirname, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -export const provisionRoot = dirname(dirname(fileURLToPath(import.meta.url))); - -export const provisionPath = (...segments: string[]): string => resolve(provisionRoot, ...segments); - -export const toolCachePath = (...segments: string[]): string => provisionPath('.cache', ...segments); - -export const toolBinCachePath = (...segments: string[]): string => toolCachePath('bin', ...segments); - -export const goBuildCachePath = (...segments: string[]): string => toolCachePath('go-build', ...segments); - -export const goModCachePath = (...segments: string[]): string => toolCachePath('go-mod', ...segments); - -export const goTmpCachePath = (...segments: string[]): string => toolCachePath('go-tmp', ...segments); - -export const playwrightCachePath = (...segments: string[]): string => toolCachePath('playwright', ...segments); - -export const turboCachePath = (...segments: string[]): string => toolCachePath('turbo', ...segments); - -export const vitestCachePath = (...segments: string[]): string => toolCachePath('vitest', ...segments); - -export const tsBuildCachePath = (...segments: string[]): string => toolCachePath('tsbuild', ...segments); - -export const xdgCachePath = (...segments: string[]): string => toolCachePath('xdg', ...segments); diff --git a/provision/ts/src/index.ts b/provision/ts/src/index.ts deleted file mode 100644 index c32d8a30..00000000 --- a/provision/ts/src/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -export { - goBuildCachePath, - goModCachePath, - goTmpCachePath, - playwrightCachePath, - provisionPath, - provisionRoot, - toolBinCachePath, - toolCachePath, - tsBuildCachePath, - turboCachePath, - vitestCachePath, - xdgCachePath, -} from '#provision-ts/cache'; diff --git a/provision/ts/tsconfig.json b/provision/ts/tsconfig.json deleted file mode 100644 index 3d1f5420..00000000 --- a/provision/ts/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "@ollin/tsconfig/base.json", - "compilerOptions": { - "baseUrl": ".", - "tsBuildInfoFile": "../.cache/tsbuild/provision-ts.tsbuildinfo", - "paths": { - "#provision-ts/*": ["./src/*"] - } - }, - "include": ["src/**/*.ts"] -} diff --git a/turbo.json b/turbo.json index 7744ae79..ac4e37ae 100644 --- a/turbo.json +++ b/turbo.json @@ -3,7 +3,7 @@ "tasks": { "build": { "dependsOn": ["^build"], - "outputs": ["dist/**", "src/.vitepress/dist/**", "src/api/**", "$TURBO_ROOT$/provision/.cache/bin/**"] + "outputs": ["dist/**", "src/.vitepress/dist/**", "src/api/**"] }, "test": { "dependsOn": ["^test"], From fda8fa983c4190ab0bd74e109a672d0a79d0dbdd Mon Sep 17 00:00:00 2001 From: Gustavo Ocanto Date: Wed, 17 Jun 2026 15:32:52 +0800 Subject: [PATCH 2/4] format --- .gitignore | 11 +- README.md | 6 +- UPSTREAM.md | 394 +++++++++--------- {packages => apps}/docs/components.json | 0 .../docs/examples/basic-prompts.ts | 2 +- .../docs/examples/choice-prompts.ts | 2 +- {packages => apps}/docs/examples/forms.ts | 2 +- {packages => apps}/docs/examples/output.ts | 2 +- .../docs/examples/search-prompts.ts | 2 +- {packages => apps}/docs/examples/status.ts | 2 +- {packages => apps}/docs/examples/testing.ts | 2 +- {packages => apps}/docs/package.json | 4 +- .../docs/src/guide/autocomplete.md | 6 +- .../docs/src/guide/available-prompts.md | 6 +- .../docs/src/guide/clearing-terminal.md | 8 +- {packages => apps}/docs/src/guide/confirm.md | 6 +- .../docs/src/guide/fallbacks.md | 8 +- {packages => apps}/docs/src/guide/forms.md | 8 +- .../docs/src/guide/informational-messages.md | 6 +- .../docs/src/guide/installation.md | 12 +- .../docs/src/guide/introduction.md | 12 +- .../docs/src/guide/multisearch.md | 6 +- .../docs/src/guide/multiselect.md | 6 +- {packages => apps}/docs/src/guide/number.md | 8 +- {packages => apps}/docs/src/guide/password.md | 8 +- {packages => apps}/docs/src/guide/pause.md | 8 +- {packages => apps}/docs/src/guide/progress.md | 8 +- {packages => apps}/docs/src/guide/search.md | 6 +- {packages => apps}/docs/src/guide/select.md | 8 +- {packages => apps}/docs/src/guide/spin.md | 6 +- {packages => apps}/docs/src/guide/stream.md | 8 +- {packages => apps}/docs/src/guide/suggest.md | 6 +- {packages => apps}/docs/src/guide/tables.md | 16 +- {packages => apps}/docs/src/guide/task.md | 6 +- .../docs/src/guide/terminal-considerations.md | 8 +- .../docs/src/guide/terminal-title.md | 8 +- {packages => apps}/docs/src/guide/testing.md | 6 +- {packages => apps}/docs/src/guide/text.md | 8 +- {packages => apps}/docs/src/guide/textarea.md | 6 +- .../docs/src/guide/transforms.md | 6 +- {packages => apps}/docs/src/index.md | 8 +- {packages => apps}/docs/tests/docs.test.ts | 0 {packages => apps}/docs/tsconfig.json | 10 +- {packages => apps}/docs/typedoc.json | 4 +- {packages => apps}/docs/vitepress/config.ts | 6 +- .../theme/components/TerminalOutput.vue | 0 .../theme/components/ui/badge/Badge.vue | 0 .../theme/components/ui/badge/index.ts | 0 .../theme/components/ui/badge/variants.ts | 0 .../theme/components/ui/card/Card.vue | 0 .../theme/components/ui/card/CardAction.vue | 0 .../theme/components/ui/card/CardContent.vue | 0 .../components/ui/card/CardDescription.vue | 0 .../theme/components/ui/card/CardFooter.vue | 0 .../theme/components/ui/card/CardHeader.vue | 0 .../theme/components/ui/card/CardTitle.vue | 0 .../theme/components/ui/card/index.ts | 0 .../components/ui/separator/Separator.vue | 0 .../theme/components/ui/separator/index.ts | 0 .../docs/vitepress/theme/index.ts | 0 .../docs/vitepress/theme/lib/utils.ts | 0 .../docs/vitepress/theme/styles.css | 0 {packages => apps}/docs/vitepress/vue.d.ts | 0 {packages => apps}/docs/vitest.config.ts | 10 +- infra/.gitignore | 1 - infra/README.md | 6 +- infra/make/fresh.mk | 12 +- infra/package.json | 2 +- infra/src/index.ts | 2 +- infra/tsconfig/console.json | 5 + infra/tsconfig/tui.json | 5 - package.json | 2 +- packages/acceptance/tests/helpers.test.ts | 121 ------ packages/acceptance/tsconfig.json | 12 - packages/tui/src/concerns/choices.ts | 4 - packages/tui/src/environment.ts | 5 - packages/tui/src/form/builder/output/index.ts | 5 - packages/tui/src/form/builder/prompts.ts | 11 - .../src/form/builder/prompts/basic/index.ts | 4 - .../src/form/builder/prompts/choice/index.ts | 8 - .../form/builder/prompts/contracts/choices.ts | 17 - .../form/builder/prompts/contracts/index.ts | 4 - .../tui/src/form/builder/prompts/types.ts | 3 - .../form/builder/prompts/validators/basic.ts | 7 - .../form/builder/prompts/validators/search.ts | 6 - .../form/builder/prompts/validators/select.ts | 7 - .../builder/prompts/validators/suggest.ts | 6 - packages/tui/src/form/builder/status/index.ts | 4 - .../tui/src/form/builder/validators/output.ts | 5 - .../tui/src/form/builder/validators/status.ts | 9 - packages/tui/src/key.ts | 4 - packages/tui/src/output.ts | 7 - packages/tui/src/output/data-table/read.ts | 15 - .../tui/src/output/data-table/render-body.ts | 5 - packages/tui/src/output/data-table/rows.ts | 4 - packages/tui/src/output/table.ts | 2 - packages/tui/src/prompt.ts | 10 - packages/tui/src/prompts.ts | 3 - packages/tui/src/prompts/basic.ts | 4 - packages/tui/src/prompts/choices.ts | 5 - packages/tui/src/prompts/search/index.ts | 2 - packages/tui/src/prompts/search/keys.ts | 4 - .../src/prompts/search/read-multi/cancel.ts | 21 - .../search/read-multi/state/context.ts | 26 -- .../prompts/search/read-multi/state/labels.ts | 6 - .../tui/src/prompts/search/read-single.ts | 15 - .../tui/src/prompts/search/render-body.ts | 1 - packages/tui/src/prompts/select/index.ts | 3 - .../prompts/select/read-multiple/cancel.ts | 17 - .../read-selected/interactive/cancel.ts | 26 -- packages/tui/src/prompts/suggest/index.ts | 3 - .../suggest/read-autocomplete/cancel.ts | 16 - .../suggest/read-autocomplete/submission.ts | 7 - .../tui/src/prompts/suggest/read/cancel.ts | 16 - packages/tui/src/status.ts | 6 - packages/tui/src/status/task/logger.ts | 1 - .../task/process-output/validators/writer.ts | 6 - packages/tui/src/string-utils/ansi.ts | 7 - packages/tui/src/strings.ts | 5 - packages/tui/src/theme.ts | 5 - packages/tui/src/typed-value.ts | 4 - packages/tui/tsconfig.json | 11 - pkgs-go/go.mod | 3 + pkgs-go/package.json | 10 + .../tui => pkgs-ts/console}/package.json | 8 +- .../console}/src/concerns/choice-label.ts | 4 +- .../console}/src/concerns/choice-match.ts | 4 +- .../src/concerns/choice-navigation.ts | 4 +- .../console}/src/concerns/choice-normalize.ts | 6 +- .../console}/src/concerns/choice-render.ts | 12 +- pkgs-ts/console/src/concerns/choices.ts | 4 + .../console}/src/concerns/info.ts | 2 +- .../console}/src/concerns/scrollbar.ts | 6 +- .../console}/src/concerns/text-options.ts | 4 +- .../src/concerns/validators/choice-answer.ts | 0 .../src/concerns/validators/choice.ts | 2 +- .../console}/src/concerns/validators/info.ts | 2 +- .../src/concerns/validators/scroll.ts | 0 .../src/concerns/validators/scrollbar.ts | 0 .../src/concerns/validators/text-options.ts | 0 .../console}/src/contracts/base.ts | 0 .../console}/src/contracts/choices.ts | 0 .../console}/src/contracts/environment.ts | 2 +- .../console}/src/contracts/options.ts | 2 +- .../console}/src/contracts/output.ts | 4 +- .../console}/src/contracts/prompts.ts | 6 +- .../console}/src/contracts/status.ts | 0 pkgs-ts/console/src/environment.ts | 5 + .../console}/src/environment/default-input.ts | 4 +- .../console}/src/environment/memory-output.ts | 4 +- .../console}/src/environment/raw-key.ts | 6 +- .../console}/src/environment/raw-key/mode.ts | 2 +- .../src/environment/raw-key/normalize.ts | 4 +- .../src/environment/raw-key/session.ts | 8 +- .../console}/src/environment/raw-key/types.ts | 0 .../environment/raw-key/validators/chunk.ts | 0 .../console}/src/environment/runtime.ts | 6 +- .../console}/src/environment/scope.ts | 12 +- .../console}/src/environment/scope/merge.ts | 4 +- .../src/environment/scope/validators/patch.ts | 4 +- .../src/environment/scripted-input.ts | 4 +- .../console}/src/environment/stream-output.ts | 6 +- .../src/environment/validators/output.ts | 0 .../environment/validators/scripted-input.ts | 0 .../environment/validators/stream-output.ts | 2 +- {packages/tui => pkgs-ts/console}/src/form.ts | 8 +- .../console}/src/form/builder/conditions.ts | 4 +- .../console}/src/form/builder/index.ts | 12 +- .../console}/src/form/builder/methods.ts | 14 +- .../console}/src/form/builder/output.ts | 8 +- .../src/form/builder/output/contracts.ts | 4 +- .../src/form/builder/output/data-table.ts | 10 +- .../src/form/builder/output/display.ts | 4 +- .../console/src/form/builder/output/index.ts | 5 + .../src/form/builder/output/notification.ts | 4 +- .../console}/src/form/builder/output/table.ts | 8 +- .../src/form/builder/output/terminal.ts | 4 +- .../console}/src/form/builder/previous.ts | 2 +- pkgs-ts/console/src/form/builder/prompts.ts | 11 + .../src/form/builder/prompts/basic.ts | 6 +- .../src/form/builder/prompts/basic/index.ts | 4 + .../src/form/builder/prompts/basic/number.ts | 10 +- .../builder/prompts/basic/number/defaults.ts | 8 +- .../builder/prompts/basic/number/options.ts | 6 +- .../form/builder/prompts/basic/number/step.ts | 6 +- .../form/builder/prompts/basic/password.ts | 10 +- .../src/form/builder/prompts/basic/text.ts | 10 +- .../form/builder/prompts/basic/textarea.ts | 10 +- .../builder/prompts/choice/autocomplete.ts | 12 +- .../form/builder/prompts/choice/confirm.ts | 10 +- .../src/form/builder/prompts/choice/index.ts | 8 + .../builder/prompts/choice/multisearch.ts | 10 +- .../builder/prompts/choice/multiselect.ts | 10 +- .../src/form/builder/prompts/choice/pause.ts | 4 +- .../src/form/builder/prompts/choice/search.ts | 10 +- .../src/form/builder/prompts/choice/select.ts | 10 +- .../form/builder/prompts/choice/suggest.ts | 12 +- .../src/form/builder/prompts/choices.ts | 6 +- .../form/builder/prompts/contracts/basic.ts | 6 +- .../form/builder/prompts/contracts/choices.ts | 17 + .../prompts/contracts/choices/autocomplete.ts | 6 +- .../prompts/contracts/choices/confirm.ts | 4 +- .../prompts/contracts/choices/multisearch.ts | 4 +- .../prompts/contracts/choices/multiselect.ts | 4 +- .../prompts/contracts/choices/pause.ts | 2 +- .../prompts/contracts/choices/search.ts | 4 +- .../prompts/contracts/choices/select.ts | 4 +- .../prompts/contracts/choices/suggest.ts | 6 +- .../form/builder/prompts/contracts/index.ts | 4 + .../console/src/form/builder/prompts/types.ts | 3 + .../builder/prompts/validators/basic-label.ts | 0 .../prompts/validators/basic-number.ts | 4 +- .../builder/prompts/validators/basic-text.ts | 4 +- .../prompts/validators/basic-textarea.ts | 4 +- .../form/builder/prompts/validators/basic.ts | 7 + .../form/builder/prompts/validators/search.ts | 6 + .../prompts/validators/search/common.ts | 6 +- .../prompts/validators/search/multisearch.ts | 4 +- .../prompts/validators/search/search.ts | 4 +- .../form/builder/prompts/validators/select.ts | 7 + .../prompts/validators/select/common.ts | 4 +- .../prompts/validators/select/confirm.ts | 4 +- .../prompts/validators/select/multiselect.ts | 4 +- .../prompts/validators/select/select.ts | 4 +- .../builder/prompts/validators/suggest.ts | 6 + .../validators/suggest/autocomplete.ts | 6 +- .../prompts/validators/suggest/common.ts | 4 +- .../prompts/validators/suggest/suggest.ts | 6 +- .../console}/src/form/builder/responses.ts | 2 +- .../console}/src/form/builder/revert.ts | 8 +- .../console}/src/form/builder/status.ts | 8 +- .../console/src/form/builder/status/index.ts | 4 + .../src/form/builder/status/progress.ts | 10 +- .../console}/src/form/builder/status/spin.ts | 8 +- .../src/form/builder/status/stream.ts | 6 +- .../console}/src/form/builder/status/task.ts | 10 +- .../console}/src/form/builder/step.ts | 2 +- .../console}/src/form/builder/submit.ts | 8 +- .../src/form/builder/validators/conditions.ts | 4 +- .../src/form/builder/validators/output.ts | 5 + .../form/builder/validators/output/common.ts | 0 .../builder/validators/output/data-table.ts | 8 +- .../form/builder/validators/output/table.ts | 8 +- .../src/form/builder/validators/previous.ts | 0 .../src/form/builder/validators/revert.ts | 2 +- .../src/form/builder/validators/status.ts | 9 + .../form/builder/validators/status/common.ts | 6 +- .../builder/validators/status/progress.ts | 8 +- .../form/builder/validators/status/spin.ts | 4 +- .../form/builder/validators/status/stream.ts | 4 +- .../form/builder/validators/status/task.ts | 10 +- .../tui => pkgs-ts/console}/src/form/types.ts | 2 +- .../tui => pkgs-ts/console}/src/index.ts | 48 +-- pkgs-ts/console/src/key.ts | 4 + .../console}/src/key/constants.ts | 0 .../tui => pkgs-ts/console}/src/key/event.ts | 10 +- .../console}/src/key/event/maps.ts | 4 +- .../console}/src/key/event/value.ts | 6 +- .../tui => pkgs-ts/console}/src/key/match.ts | 4 +- .../tui => pkgs-ts/console}/src/key/types.ts | 2 +- .../console}/src/key/validators/event.ts | 2 +- .../console}/src/key/validators/match.ts | 2 +- .../console}/src/key/validators/value.ts | 4 +- .../tui => pkgs-ts/console}/src/opentui.ts | 0 pkgs-ts/console/src/output.ts | 7 + .../console}/src/output/data-table.ts | 8 +- .../src/output/data-table/body/active.ts | 18 +- .../src/output/data-table/body/cancelled.ts | 8 +- .../src/output/data-table/body/headers.ts | 0 .../src/output/data-table/body/submitted.ts | 4 +- .../src/output/data-table/body/types.ts | 4 +- .../console}/src/output/data-table/keys.ts | 2 +- .../src/output/data-table/multiline.ts | 0 .../src/output/data-table/navigation.ts | 6 +- .../console}/src/output/data-table/options.ts | 8 +- pkgs-ts/console/src/output/data-table/read.ts | 15 + .../src/output/data-table/reader/cancel.ts | 16 +- .../src/output/data-table/reader/fallback.ts | 12 +- .../output/data-table/reader/interactive.ts | 16 +- .../src/output/data-table/reader/result.ts | 10 +- .../src/output/data-table/reader/session.ts | 12 +- .../data-table/reader/session/render.ts | 8 +- .../src/output/data-table/reader/state.ts | 16 +- .../output/data-table/reader/state/search.ts | 4 +- .../data-table/reader/state/selection.ts | 10 +- .../src/output/data-table/reader/types.ts | 2 +- .../src/output/data-table/render-body.ts | 5 + .../console}/src/output/data-table/render.ts | 16 +- pkgs-ts/console/src/output/data-table/rows.ts | 4 + .../src/output/data-table/rows/cells.ts | 2 +- .../src/output/data-table/rows/fields.ts | 6 +- .../src/output/data-table/rows/headers.ts | 6 +- .../src/output/data-table/rows/visible.ts | 6 +- .../console}/src/output/data-table/run.ts | 20 +- .../src/output/data-table/scrollbar.ts | 4 +- .../console}/src/output/data-table/search.ts | 6 +- .../src/output/data-table/selection.ts | 6 +- .../console}/src/output/data-table/types.ts | 2 +- .../output/data-table/validators/selection.ts | 0 .../src/output/data-table/visual-window.ts | 2 +- .../console}/src/output/data-table/widths.ts | 8 +- .../src/output/data-table/widths/available.ts | 2 +- .../src/output/data-table/widths/columns.ts | 8 +- .../src/output/data-table/widths/natural.ts | 4 +- .../src/output/data-table/widths/shrink.ts | 0 .../src/output/data-table/widths/truncate.ts | 4 +- .../widths/validators/dimensions.ts | 0 .../console}/src/output/grid-output.ts | 4 +- .../console}/src/output/grid.ts | 8 +- .../console}/src/output/grid/layout.ts | 4 +- .../console}/src/output/grid/lines.ts | 4 +- .../src/output/grid/validators/layout.ts | 0 .../console}/src/output/notes.ts | 8 +- .../console}/src/output/notes/render.ts | 8 +- .../console}/src/output/notes/types.ts | 0 .../src/output/notes/validators/message.ts | 0 .../console}/src/output/notify.ts | 14 +- .../console}/src/output/notify/commands.ts | 8 +- .../console}/src/output/notify/executor.ts | 4 +- .../src/output/notify/validators/command.ts | 2 +- .../src/output/notify/validators/options.ts | 0 .../src/output/notify/validators/platform.ts | 0 .../console}/src/output/table-output.ts | 8 +- pkgs-ts/console/src/output/table.ts | 2 + .../console}/src/output/terminal.ts | 2 +- .../console}/src/output/validators/cells.ts | 2 +- .../src/output/validators/data-table.ts | 6 +- .../output/validators/data-table/options.ts | 4 +- .../output/validators/data-table/row-shape.ts | 4 +- .../output/validators/data-table/schemas.ts | 4 +- .../console}/src/output/validators/table.ts | 8 +- .../src/output/validators/table/rows.ts | 4 +- .../src/output/validators/table/schemas.ts | 4 +- pkgs-ts/console/src/prompt.ts | 10 + .../console}/src/prompt/active-frame.ts | 2 +- .../tui => pkgs-ts/console}/src/prompt/ask.ts | 6 +- .../console}/src/prompt/cancel.ts | 4 +- .../console}/src/prompt/error.ts | 0 .../console}/src/prompt/fallback.ts | 4 +- .../console}/src/prompt/lifecycle.ts | 10 +- .../src/prompt/lifecycle/interactive.ts | 14 +- .../src/prompt/lifecycle/non-interactive.ts | 8 +- .../console}/src/prompt/lifecycle/types.ts | 0 .../src/prompt/lifecycle/validation.ts | 4 +- .../console}/src/prompt/revert.ts | 4 +- .../console}/src/prompt/submission.ts | 0 .../console}/src/prompt/validate-using.ts | 4 +- .../console}/src/prompt/validation.ts | 8 +- .../console}/src/prompt/validators/cancel.ts | 0 .../console}/src/prompt/validators/error.ts | 2 +- .../src/prompt/validators/fallback.ts | 6 +- .../prompt/validators/global-validation.ts | 2 +- .../console}/src/prompt/validators/invalid.ts | 0 pkgs-ts/console/src/prompts.ts | 3 + pkgs-ts/console/src/prompts/basic.ts | 4 + pkgs-ts/console/src/prompts/choices.ts | 5 + .../console}/src/prompts/number.ts | 6 +- .../console}/src/prompts/number/defaults.ts | 6 +- .../console}/src/prompts/number/fallback.ts | 8 +- .../console}/src/prompts/number/input.ts | 8 +- .../src/prompts/number/interactive.ts | 10 +- .../console}/src/prompts/number/options.ts | 8 +- .../console}/src/prompts/number/render.ts | 12 +- .../console}/src/prompts/number/run.ts | 18 +- .../console}/src/prompts/number/session.ts | 8 +- .../src/prompts/number/session/state.ts | 8 +- .../console}/src/prompts/number/step.ts | 6 +- .../console}/src/prompts/number/types.ts | 0 .../src/prompts/number/validators/overload.ts | 0 .../src/prompts/number/validators/step.ts | 0 .../src/prompts/number/validators/value.ts | 2 +- .../console}/src/prompts/password.ts | 6 +- .../console}/src/prompts/password/fallback.ts | 8 +- .../console}/src/prompts/password/input.ts | 10 +- .../console}/src/prompts/password/options.ts | 6 +- .../console}/src/prompts/password/render.ts | 10 +- .../console}/src/prompts/password/run.ts | 14 +- .../console}/src/prompts/password/session.ts | 8 +- .../console}/src/prompts/password/types.ts | 0 .../console}/src/prompts/pause.ts | 4 +- .../console}/src/prompts/pause/read.ts | 8 +- .../console}/src/prompts/pause/render.ts | 4 +- .../src/prompts/search/body/render.ts | 8 +- .../console}/src/prompts/search/body/rows.ts | 10 +- .../console}/src/prompts/search/choices.ts | 6 +- .../console}/src/prompts/search/defaults.ts | 4 +- pkgs-ts/console/src/prompts/search/index.ts | 2 + pkgs-ts/console/src/prompts/search/keys.ts | 4 + .../src/prompts/search/keys/highlight.ts | 8 +- .../src/prompts/search/keys/navigation.ts | 2 +- .../console}/src/prompts/search/line-mode.ts | 10 +- .../src/prompts/search/multi-options.ts | 8 +- .../console}/src/prompts/search/multi-run.ts | 16 +- .../src/prompts/search/multisearch.ts | 6 +- .../console}/src/prompts/search/navigation.ts | 8 +- .../console}/src/prompts/search/options.ts | 12 +- .../console}/src/prompts/search/read-multi.ts | 18 +- .../src/prompts/search/read-multi/cancel.ts | 21 + .../prompts/search/read-multi/choice-query.ts | 12 +- .../src/prompts/search/read-multi/frame.ts | 8 +- .../src/prompts/search/read-multi/keys.ts | 6 +- .../src/prompts/search/read-multi/result.ts | 10 +- .../src/prompts/search/read-multi/session.ts | 14 +- .../search/read-multi/session/actions.ts | 6 +- .../src/prompts/search/read-multi/state.ts | 16 +- .../search/read-multi/state/context.ts | 26 ++ .../search/read-multi/state/displayed.ts | 12 +- .../search/read-multi/state/highlight.ts | 6 +- .../prompts/search/read-multi/state/input.ts | 4 +- .../prompts/search/read-multi/state/labels.ts | 6 + .../search/read-multi/state/selection.ts | 8 +- .../console/src/prompts/search/read-single.ts | 15 + .../search/read-single/choice-query.ts | 10 +- .../prompts/search/read-single/interactive.ts | 16 +- .../search/read-single/interactive/cancel.ts | 16 +- .../search/read-single/interactive/result.ts | 6 +- .../src/prompts/search/read-single/result.ts | 8 +- .../src/prompts/search/read-single/session.ts | 14 +- .../search/read-single/session/actions.ts | 6 +- .../search/read-single/session/frame.ts | 8 +- .../src/prompts/search/read-single/state.ts | 16 +- .../search/read-single/state/highlight.ts | 8 +- .../search/read-single/state/selection.ts | 10 +- .../src/prompts/search/read-single/types.ts | 2 +- .../console/src/prompts/search/render-body.ts | 1 + .../console}/src/prompts/search/render.ts | 12 +- .../console}/src/prompts/search/run.ts | 16 +- .../console}/src/prompts/search/search.ts | 6 +- .../console}/src/prompts/search/selection.ts | 4 +- .../src/prompts/search/validators/defaults.ts | 0 .../src/prompts/search/validators/options.ts | 2 +- .../src/prompts/search/validators/overload.ts | 0 .../src/prompts/search/validators/source.ts | 6 +- .../src/prompts/select/confirm-options.ts | 6 +- .../src/prompts/select/confirm-run.ts | 16 +- .../console}/src/prompts/select/confirm.ts | 6 +- .../console}/src/prompts/select/defaults.ts | 4 +- pkgs-ts/console/src/prompts/select/index.ts | 3 + .../console}/src/prompts/select/keys.ts | 8 +- .../console}/src/prompts/select/multiple.ts | 8 +- .../src/prompts/select/multiselect.ts | 6 +- .../src/prompts/select/multiselect/options.ts | 6 +- .../src/prompts/select/multiselect/run.ts | 16 +- .../console}/src/prompts/select/navigation.ts | 8 +- .../console}/src/prompts/select/options.ts | 8 +- .../src/prompts/select/read-confirm.ts | 20 +- .../src/prompts/select/read-confirm/keys.ts | 2 +- .../prompts/select/read-confirm/line-mode.ts | 4 +- .../prompts/select/read-confirm/session.ts | 6 +- .../src/prompts/select/read-confirm/types.ts | 2 +- .../src/prompts/select/read-multiple.ts | 12 +- .../prompts/select/read-multiple/cancel.ts | 17 + .../select/read-multiple/interactive.ts | 14 +- .../src/prompts/select/read-multiple/keys.ts | 16 +- .../prompts/select/read-multiple/line-mode.ts | 12 +- .../prompts/select/read-multiple/result.ts | 6 +- .../prompts/select/read-multiple/session.ts | 8 +- .../select/read-multiple/session/frame.ts | 6 +- .../select/read-multiple/session/state.ts | 10 +- .../src/prompts/select/read-multiple/types.ts | 0 .../src/prompts/select/read-selected.ts | 12 +- .../select/read-selected/interactive.ts | 16 +- .../read-selected/interactive/cancel.ts | 26 ++ .../read-selected/interactive/result.ts | 8 +- .../prompts/select/read-selected/line-mode.ts | 12 +- .../prompts/select/read-selected/result.ts | 8 +- .../prompts/select/read-selected/session.ts | 12 +- .../src/prompts/select/read-selected/types.ts | 0 .../src/prompts/select/render-confirm.ts | 8 +- .../src/prompts/select/render-rows.ts | 8 +- .../src/prompts/select/render-rows/window.ts | 6 +- .../console}/src/prompts/select/render.ts | 12 +- .../console}/src/prompts/select/run.ts | 20 +- .../console}/src/prompts/select/select.ts | 6 +- .../src/prompts/select/validators/defaults.ts | 0 .../src/prompts/select/validators/options.ts | 2 +- .../src/prompts/select/validators/overload.ts | 4 +- .../prompts/suggest/autocomplete-prompt.ts | 14 +- .../src/prompts/suggest/autocomplete.ts | 8 +- .../src/prompts/suggest/ghost-text.ts | 8 +- pkgs-ts/console/src/prompts/suggest/index.ts | 3 + .../console}/src/prompts/suggest/keys.ts | 4 +- .../console}/src/prompts/suggest/lifecycle.ts | 12 +- .../src/prompts/suggest/navigation.ts | 2 +- .../console}/src/prompts/suggest/options.ts | 4 +- .../src/prompts/suggest/read-autocomplete.ts | 20 +- .../suggest/read-autocomplete/cancel.ts | 16 + .../suggest/read-autocomplete/frame.ts | 8 +- .../suggest/read-autocomplete/session.ts | 8 +- .../suggest/read-autocomplete/state.ts | 10 +- .../read-autocomplete/state/highlight.ts | 2 +- .../suggest/read-autocomplete/submission.ts | 7 + .../src/prompts/suggest/read-result.ts | 4 +- .../console}/src/prompts/suggest/read.ts | 20 +- .../src/prompts/suggest/read/cancel.ts | 16 + .../src/prompts/suggest/read/frame.ts | 8 +- .../src/prompts/suggest/read/session.ts | 10 +- .../src/prompts/suggest/read/state.ts | 10 +- .../prompts/suggest/read/state/highlight.ts | 4 +- .../src/prompts/suggest/read/submission.ts | 6 +- .../prompts/suggest/render-autocomplete.ts | 14 +- .../console}/src/prompts/suggest/render.ts | 12 +- .../src/prompts/suggest/render/body.ts | 6 +- .../src/prompts/suggest/render/rows.ts | 6 +- .../console}/src/prompts/suggest/resolve.ts | 4 +- .../src/prompts/suggest/state/query.ts | 10 +- .../console}/src/prompts/suggest/suggest.ts | 12 +- .../prompts/suggest/validators/overload.ts | 0 .../src/prompts/suggest/validators/source.ts | 4 +- .../console}/src/prompts/text-default.ts | 2 +- .../console}/src/prompts/text.ts | 6 +- .../console}/src/prompts/text/options.ts | 6 +- .../console}/src/prompts/text/run.ts | 14 +- .../console}/src/prompts/textarea.ts | 6 +- .../console}/src/prompts/textarea/options.ts | 4 +- .../console}/src/prompts/textarea/run.ts | 14 +- pkgs-ts/console/src/status.ts | 6 + .../console}/src/status/frame.ts | 2 +- .../console}/src/status/progress.ts | 12 +- .../src/status/progress/controller.ts | 8 +- .../console}/src/status/progress/labels.ts | 2 +- .../console}/src/status/progress/progress.ts | 12 +- .../console}/src/status/progress/prompt.ts | 0 .../console}/src/status/progress/readback.ts | 2 +- .../console}/src/status/progress/render.ts | 6 +- .../console}/src/status/progress/renderer.ts | 8 +- .../console}/src/status/progress/run.ts | 2 +- .../console}/src/status/progress/state.ts | 12 +- .../src/status/progress/state/snapshot.ts | 2 +- .../src/status/progress/state/value.ts | 2 +- .../console}/src/status/progress/steps.ts | 2 +- .../console}/src/status/progress/terminal.ts | 10 +- .../src/status/progress/terminal/signals.ts | 4 +- .../status/progress/validators/arguments.ts | 2 +- .../src/status/progress/validators/frame.ts | 0 .../console}/src/status/signals.ts | 4 +- .../console}/src/status/spinner.ts | 6 +- .../console}/src/status/spinner/lifecycle.ts | 12 +- .../console}/src/status/spinner/options.ts | 4 +- .../console}/src/status/spinner/render.ts | 0 .../src/status/spinner/validators/options.ts | 4 +- .../console}/src/status/stream.ts | 4 +- .../console}/src/status/stream/buffer.ts | 2 +- .../console}/src/status/stream/fade.ts | 8 +- .../console}/src/status/stream/lifecycle.ts | 4 +- .../console}/src/status/stream/output.ts | 14 +- .../src/status/stream/output/context.ts | 8 +- .../src/status/stream/output/errors.ts | 0 .../console}/src/status/stream/output/pipe.ts | 0 .../src/status/stream/output/readback.ts | 4 +- .../src/status/stream/output/rendering.ts | 4 +- .../console}/src/status/stream/render.ts | 8 +- .../console}/src/status/stream/renderer.ts | 10 +- .../console}/src/status/stream/scheduler.ts | 0 .../src/status/stream/validators/chunk.ts | 0 .../src/status/stream/validators/fade.ts | 4 +- .../console}/src/status/task.ts | 12 +- .../console}/src/status/task/definition.ts | 6 +- .../console}/src/status/task/frame.ts | 4 +- .../console}/src/status/task/lifecycle.ts | 16 +- .../src/status/task/lifecycle/rendering.ts | 8 +- pkgs-ts/console/src/status/task/logger.ts | 1 + .../console}/src/status/task/logger/events.ts | 0 .../console}/src/status/task/logger/labels.ts | 0 .../console}/src/status/task/logger/limits.ts | 2 +- .../console}/src/status/task/logger/lines.ts | 6 +- .../console}/src/status/task/logger/logger.ts | 22 +- .../src/status/task/logger/methods.ts | 10 +- .../console}/src/status/task/logger/output.ts | 4 +- .../console}/src/status/task/logger/stable.ts | 4 +- .../console}/src/status/task/logger/sync.ts | 4 +- .../status/task/logger/validators/message.ts | 0 .../console}/src/status/task/messages.ts | 0 .../src/status/task/process-output.ts | 8 +- .../src/status/task/process-output/buffer.ts | 4 +- .../task/process-output/validators/chunk.ts | 0 .../task/process-output/validators/writer.ts | 6 + .../validators/writer/callback.ts | 2 +- .../process-output/validators/writer/chunk.ts | 4 +- .../validators/writer/stream.ts | 2 +- .../src/status/task/process-output/writer.ts | 4 +- .../console}/src/status/task/render.ts | 6 +- .../console}/src/status/task/sanitize.ts | 0 .../src/status/task/validators/definition.ts | 8 +- .../console}/src/status/validators/limit.ts | 0 .../src/status/validators/progress.ts | 2 +- .../src/status/validators/signal-target.ts | 2 +- pkgs-ts/console/src/string-utils/ansi.ts | 7 + .../console}/src/string-utils/ansi/codes.ts | 0 .../src/string-utils/ansi/segments.ts | 2 +- .../console}/src/string-utils/truncate.ts | 6 +- .../src/string-utils/validators/width.ts | 0 .../console}/src/string-utils/width.ts | 0 .../console}/src/string-utils/wrap.ts | 4 +- .../console}/src/string-utils/wrap/ansi.ts | 4 +- .../console}/src/string-utils/wrap/plain.ts | 4 +- pkgs-ts/console/src/strings.ts | 5 + .../tui => pkgs-ts/console}/src/terminal.ts | 10 +- .../console}/src/terminal/capabilities.ts | 2 +- .../console}/src/terminal/validators/color.ts | 2 +- .../console}/src/terminal/validators/size.ts | 0 .../console}/src/terminal/validators/title.ts | 0 pkgs-ts/console/src/theme.ts | 5 + .../tui => pkgs-ts/console}/src/theme/box.ts | 6 +- .../console}/src/theme/choice-disabled.ts | 2 +- .../console}/src/theme/choices.ts | 4 +- .../console}/src/theme/error.ts | 4 +- .../console}/src/theme/question.ts | 2 +- .../console}/src/theme/styles.ts | 0 .../console}/src/theme/symbols.ts | 0 .../console}/src/theme/table.ts | 4 +- .../console}/src/theme/validators/box.ts | 0 .../console}/src/theme/validators/disabled.ts | 0 .../console}/src/theme/validators/table.ts | 0 pkgs-ts/console/src/typed-value.ts | 4 + .../console}/src/typed-value/characters.ts | 0 .../console}/src/typed-value/cursor.ts | 6 +- .../console}/src/typed-value/delete.ts | 4 +- .../console}/src/typed-value/edit.ts | 16 +- .../console}/src/typed-value/edit/deletion.ts | 4 +- .../src/typed-value/edit/insertion.ts | 2 +- .../src/typed-value/edit/navigation.ts | 4 +- .../console}/src/typed-value/edit/result.ts | 4 +- .../console}/src/typed-value/line-ranges.ts | 4 +- .../console}/src/typed-value/lines.ts | 10 +- .../src/typed-value/lines/text-window.ts | 8 +- .../console}/src/typed-value/lines/types.ts | 0 .../console}/src/typed-value/lines/window.ts | 10 +- .../console}/src/typed-value/read.ts | 16 +- .../console}/src/typed-value/read/cancel.ts | 12 +- .../console}/src/typed-value/read/fallback.ts | 10 +- .../console}/src/typed-value/render.ts | 14 +- .../src/typed-value/textarea-frame.ts | 18 +- .../console}/src/typed-value/textarea.ts | 0 .../console}/src/typed-value/types.ts | 0 .../src/typed-value/validators/cursor.ts | 0 .../src/typed-value/validators/rows.ts | 0 .../src/typed-value/validators/width.ts | 0 .../tui => pkgs-ts/console}/src/types.ts | 14 +- .../console}/src/validators/default.ts | 0 .../console}/src/validators/function.ts | 0 .../console}/src/validators/iterable.ts | 2 +- .../console}/src/validators/required.ts | 0 .../console}/src/validators/result.ts | 2 +- .../console}/tests/choices.test.ts | 4 +- .../console}/tests/environment.test.ts | 6 +- .../console}/tests/form.test.ts | 2 +- .../tui => pkgs-ts/console}/tests/key.test.ts | 2 +- .../console}/tests/notify.test.ts | 4 +- .../console}/tests/number.test.ts | 4 +- .../console}/tests/output.test.ts | 4 +- .../console}/tests/password.test.ts | 2 +- .../console}/tests/pause.test.ts | 2 +- .../console}/tests/progress.test.ts | 2 +- .../console}/tests/prompt.test.ts | 10 +- .../console}/tests/search.test.ts | 4 +- .../console}/tests/spinner.test.ts | 4 +- .../console}/tests/stream.test.ts | 6 +- .../console}/tests/strings.test.ts | 2 +- .../console}/tests/suggest.test.ts | 2 +- .../console}/tests/table.test.ts | 2 +- .../console}/tests/task.test.ts | 6 +- .../console}/tests/terminal.test.ts | 2 +- .../console}/tests/text.test.ts | 2 +- .../console}/tests/textarea.test.ts | 2 +- .../console}/tests/typed-value.test.ts | 4 +- .../console}/tsconfig.build.json | 2 +- pkgs-ts/console/tsconfig.json | 11 + .../tui => pkgs-ts/console}/vitest.config.ts | 4 +- .../acceptance => pkgs-ts/tests}/package.json | 6 +- .../tests/tests/distribution}/package.test.ts | 18 +- .../tests/tests/forms/form-builder.test.ts | 16 + pkgs-ts/tests/tests/output/messages.test.ts | 27 ++ pkgs-ts/tests/tests/output/status.test.ts | 26 ++ pkgs-ts/tests/tests/prompts/prompts.test.ts | 35 ++ .../tests/tests/rendering}/opentui.test.ts | 2 +- pkgs-ts/tests/tests/support/scripted.ts | 17 + pkgs-ts/tests/tsconfig.json | 12 + .../tests}/vitest.config.ts | 10 +- pnpm-lock.yaml | 195 +++------ pnpm-workspace.yaml | 4 +- 681 files changed, 2415 insertions(+), 2493 deletions(-) rename {packages => apps}/docs/components.json (100%) rename {packages => apps}/docs/examples/basic-prompts.ts (93%) rename {packages => apps}/docs/examples/choice-prompts.ts (98%) rename {packages => apps}/docs/examples/forms.ts (95%) rename {packages => apps}/docs/examples/output.ts (92%) rename {packages => apps}/docs/examples/search-prompts.ts (93%) rename {packages => apps}/docs/examples/status.ts (90%) rename {packages => apps}/docs/examples/testing.ts (89%) rename {packages => apps}/docs/package.json (96%) rename {packages => apps}/docs/src/guide/autocomplete.md (88%) rename {packages => apps}/docs/src/guide/available-prompts.md (92%) rename {packages => apps}/docs/src/guide/clearing-terminal.md (87%) rename {packages => apps}/docs/src/guide/confirm.md (88%) rename {packages => apps}/docs/src/guide/fallbacks.md (85%) rename {packages => apps}/docs/src/guide/forms.md (92%) rename {packages => apps}/docs/src/guide/informational-messages.md (92%) rename {packages => apps}/docs/src/guide/installation.md (83%) rename {packages => apps}/docs/src/guide/introduction.md (73%) rename {packages => apps}/docs/src/guide/multisearch.md (90%) rename {packages => apps}/docs/src/guide/multiselect.md (91%) rename {packages => apps}/docs/src/guide/number.md (86%) rename {packages => apps}/docs/src/guide/password.md (86%) rename {packages => apps}/docs/src/guide/pause.md (86%) rename {packages => apps}/docs/src/guide/progress.md (87%) rename {packages => apps}/docs/src/guide/search.md (91%) rename {packages => apps}/docs/src/guide/select.md (90%) rename {packages => apps}/docs/src/guide/spin.md (91%) rename {packages => apps}/docs/src/guide/stream.md (84%) rename {packages => apps}/docs/src/guide/suggest.md (90%) rename {packages => apps}/docs/src/guide/tables.md (78%) rename {packages => apps}/docs/src/guide/task.md (89%) rename {packages => apps}/docs/src/guide/terminal-considerations.md (78%) rename {packages => apps}/docs/src/guide/terminal-title.md (83%) rename {packages => apps}/docs/src/guide/testing.md (91%) rename {packages => apps}/docs/src/guide/text.md (89%) rename {packages => apps}/docs/src/guide/textarea.md (89%) rename {packages => apps}/docs/src/guide/transforms.md (91%) rename {packages => apps}/docs/src/index.md (82%) rename {packages => apps}/docs/tests/docs.test.ts (100%) rename {packages => apps}/docs/tsconfig.json (62%) rename {packages => apps}/docs/typedoc.json (66%) rename {packages => apps}/docs/vitepress/config.ts (94%) rename {packages => apps}/docs/vitepress/theme/components/TerminalOutput.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/badge/Badge.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/badge/index.ts (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/badge/variants.ts (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/Card.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/CardAction.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/CardContent.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/CardDescription.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/CardFooter.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/CardHeader.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/CardTitle.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/card/index.ts (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/separator/Separator.vue (100%) rename {packages => apps}/docs/vitepress/theme/components/ui/separator/index.ts (100%) rename {packages => apps}/docs/vitepress/theme/index.ts (100%) rename {packages => apps}/docs/vitepress/theme/lib/utils.ts (100%) rename {packages => apps}/docs/vitepress/theme/styles.css (100%) rename {packages => apps}/docs/vitepress/vue.d.ts (100%) rename {packages => apps}/docs/vitest.config.ts (84%) delete mode 100644 infra/.gitignore create mode 100644 infra/tsconfig/console.json delete mode 100644 infra/tsconfig/tui.json delete mode 100644 packages/acceptance/tests/helpers.test.ts delete mode 100644 packages/acceptance/tsconfig.json delete mode 100644 packages/tui/src/concerns/choices.ts delete mode 100644 packages/tui/src/environment.ts delete mode 100644 packages/tui/src/form/builder/output/index.ts delete mode 100644 packages/tui/src/form/builder/prompts.ts delete mode 100644 packages/tui/src/form/builder/prompts/basic/index.ts delete mode 100644 packages/tui/src/form/builder/prompts/choice/index.ts delete mode 100644 packages/tui/src/form/builder/prompts/contracts/choices.ts delete mode 100644 packages/tui/src/form/builder/prompts/contracts/index.ts delete mode 100644 packages/tui/src/form/builder/prompts/types.ts delete mode 100644 packages/tui/src/form/builder/prompts/validators/basic.ts delete mode 100644 packages/tui/src/form/builder/prompts/validators/search.ts delete mode 100644 packages/tui/src/form/builder/prompts/validators/select.ts delete mode 100644 packages/tui/src/form/builder/prompts/validators/suggest.ts delete mode 100644 packages/tui/src/form/builder/status/index.ts delete mode 100644 packages/tui/src/form/builder/validators/output.ts delete mode 100644 packages/tui/src/form/builder/validators/status.ts delete mode 100644 packages/tui/src/key.ts delete mode 100644 packages/tui/src/output.ts delete mode 100644 packages/tui/src/output/data-table/read.ts delete mode 100644 packages/tui/src/output/data-table/render-body.ts delete mode 100644 packages/tui/src/output/data-table/rows.ts delete mode 100644 packages/tui/src/output/table.ts delete mode 100644 packages/tui/src/prompt.ts delete mode 100644 packages/tui/src/prompts.ts delete mode 100644 packages/tui/src/prompts/basic.ts delete mode 100644 packages/tui/src/prompts/choices.ts delete mode 100644 packages/tui/src/prompts/search/index.ts delete mode 100644 packages/tui/src/prompts/search/keys.ts delete mode 100644 packages/tui/src/prompts/search/read-multi/cancel.ts delete mode 100644 packages/tui/src/prompts/search/read-multi/state/context.ts delete mode 100644 packages/tui/src/prompts/search/read-multi/state/labels.ts delete mode 100644 packages/tui/src/prompts/search/read-single.ts delete mode 100644 packages/tui/src/prompts/search/render-body.ts delete mode 100644 packages/tui/src/prompts/select/index.ts delete mode 100644 packages/tui/src/prompts/select/read-multiple/cancel.ts delete mode 100644 packages/tui/src/prompts/select/read-selected/interactive/cancel.ts delete mode 100644 packages/tui/src/prompts/suggest/index.ts delete mode 100644 packages/tui/src/prompts/suggest/read-autocomplete/cancel.ts delete mode 100644 packages/tui/src/prompts/suggest/read-autocomplete/submission.ts delete mode 100644 packages/tui/src/prompts/suggest/read/cancel.ts delete mode 100644 packages/tui/src/status.ts delete mode 100644 packages/tui/src/status/task/logger.ts delete mode 100644 packages/tui/src/status/task/process-output/validators/writer.ts delete mode 100644 packages/tui/src/string-utils/ansi.ts delete mode 100644 packages/tui/src/strings.ts delete mode 100644 packages/tui/src/theme.ts delete mode 100644 packages/tui/src/typed-value.ts delete mode 100644 packages/tui/tsconfig.json create mode 100644 pkgs-go/go.mod create mode 100644 pkgs-go/package.json rename {packages/tui => pkgs-ts/console}/package.json (98%) rename {packages/tui => pkgs-ts/console}/src/concerns/choice-label.ts (65%) rename {packages/tui => pkgs-ts/console}/src/concerns/choice-match.ts (86%) rename {packages/tui => pkgs-ts/console}/src/concerns/choice-navigation.ts (88%) rename {packages/tui => pkgs-ts/console}/src/concerns/choice-normalize.ts (83%) rename {packages/tui => pkgs-ts/console}/src/concerns/choice-render.ts (85%) create mode 100644 pkgs-ts/console/src/concerns/choices.ts rename {packages/tui => pkgs-ts/console}/src/concerns/info.ts (85%) rename {packages/tui => pkgs-ts/console}/src/concerns/scrollbar.ts (85%) rename {packages/tui => pkgs-ts/console}/src/concerns/text-options.ts (64%) rename {packages/tui => pkgs-ts/console}/src/concerns/validators/choice-answer.ts (100%) rename {packages/tui => pkgs-ts/console}/src/concerns/validators/choice.ts (97%) rename {packages/tui => pkgs-ts/console}/src/concerns/validators/info.ts (82%) rename {packages/tui => pkgs-ts/console}/src/concerns/validators/scroll.ts (100%) rename {packages/tui => pkgs-ts/console}/src/concerns/validators/scrollbar.ts (100%) rename {packages/tui => pkgs-ts/console}/src/concerns/validators/text-options.ts (100%) rename {packages/tui => pkgs-ts/console}/src/contracts/base.ts (100%) rename {packages/tui => pkgs-ts/console}/src/contracts/choices.ts (100%) rename {packages/tui => pkgs-ts/console}/src/contracts/environment.ts (83%) rename {packages/tui => pkgs-ts/console}/src/contracts/options.ts (71%) rename {packages/tui => pkgs-ts/console}/src/contracts/output.ts (83%) rename {packages/tui => pkgs-ts/console}/src/contracts/prompts.ts (89%) rename {packages/tui => pkgs-ts/console}/src/contracts/status.ts (100%) create mode 100644 pkgs-ts/console/src/environment.ts rename {packages/tui => pkgs-ts/console}/src/environment/default-input.ts (82%) rename {packages/tui => pkgs-ts/console}/src/environment/memory-output.ts (71%) rename {packages/tui => pkgs-ts/console}/src/environment/raw-key.ts (73%) rename {packages/tui => pkgs-ts/console}/src/environment/raw-key/mode.ts (88%) rename {packages/tui => pkgs-ts/console}/src/environment/raw-key/normalize.ts (83%) rename {packages/tui => pkgs-ts/console}/src/environment/raw-key/session.ts (83%) rename {packages/tui => pkgs-ts/console}/src/environment/raw-key/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/environment/raw-key/validators/chunk.ts (100%) rename {packages/tui => pkgs-ts/console}/src/environment/runtime.ts (62%) rename {packages/tui => pkgs-ts/console}/src/environment/scope.ts (70%) rename {packages/tui => pkgs-ts/console}/src/environment/scope/merge.ts (67%) rename {packages/tui => pkgs-ts/console}/src/environment/scope/validators/patch.ts (93%) rename {packages/tui => pkgs-ts/console}/src/environment/scripted-input.ts (67%) rename {packages/tui => pkgs-ts/console}/src/environment/stream-output.ts (55%) rename {packages/tui => pkgs-ts/console}/src/environment/validators/output.ts (100%) rename {packages/tui => pkgs-ts/console}/src/environment/validators/scripted-input.ts (100%) rename {packages/tui => pkgs-ts/console}/src/environment/validators/stream-output.ts (88%) rename {packages/tui => pkgs-ts/console}/src/form.ts (67%) rename {packages/tui => pkgs-ts/console}/src/form/builder/conditions.ts (71%) rename {packages/tui => pkgs-ts/console}/src/form/builder/index.ts (81%) rename {packages/tui => pkgs-ts/console}/src/form/builder/methods.ts (81%) rename {packages/tui => pkgs-ts/console}/src/form/builder/output.ts (70%) rename {packages/tui => pkgs-ts/console}/src/form/builder/output/contracts.ts (95%) rename {packages/tui => pkgs-ts/console}/src/form/builder/output/data-table.ts (80%) rename {packages/tui => pkgs-ts/console}/src/form/builder/output/display.ts (94%) create mode 100644 pkgs-ts/console/src/form/builder/output/index.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/output/notification.ts (70%) rename {packages/tui => pkgs-ts/console}/src/form/builder/output/table.ts (86%) rename {packages/tui => pkgs-ts/console}/src/form/builder/output/terminal.ts (74%) rename {packages/tui => pkgs-ts/console}/src/form/builder/previous.ts (88%) create mode 100644 pkgs-ts/console/src/form/builder/prompts.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic.ts (55%) create mode 100644 pkgs-ts/console/src/form/builder/prompts/basic/index.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic/number.ts (83%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic/number/defaults.ts (66%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic/number/options.ts (80%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic/number/step.ts (60%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic/password.ts (74%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic/text.ts (75%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/basic/textarea.ts (76%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/autocomplete.ts (74%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/confirm.ts (76%) create mode 100644 pkgs-ts/console/src/form/builder/prompts/choice/index.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/multisearch.ts (79%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/multiselect.ts (78%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/pause.ts (62%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/search.ts (79%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/select.ts (77%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choice/suggest.ts (75%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/choices.ts (70%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/basic.ts (91%) create mode 100644 pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/autocomplete.ts (72%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/confirm.ts (76%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/multisearch.ts (81%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/multiselect.ts (86%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/pause.ts (65%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/search.ts (80%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/select.ts (86%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/contracts/choices/suggest.ts (72%) create mode 100644 pkgs-ts/console/src/form/builder/prompts/contracts/index.ts create mode 100644 pkgs-ts/console/src/form/builder/prompts/types.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/basic-label.ts (100%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/basic-number.ts (91%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/basic-text.ts (89%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/basic-textarea.ts (82%) create mode 100644 pkgs-ts/console/src/form/builder/prompts/validators/basic.ts create mode 100644 pkgs-ts/console/src/form/builder/prompts/validators/search.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/search/common.ts (85%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/search/multisearch.ts (88%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/search/search.ts (88%) create mode 100644 pkgs-ts/console/src/form/builder/prompts/validators/select.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/select/common.ts (89%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/select/confirm.ts (87%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/select/multiselect.ts (86%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/select/select.ts (86%) create mode 100644 pkgs-ts/console/src/form/builder/prompts/validators/suggest.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/suggest/autocomplete.ts (82%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/suggest/common.ts (90%) rename {packages/tui => pkgs-ts/console}/src/form/builder/prompts/validators/suggest/suggest.ts (82%) rename {packages/tui => pkgs-ts/console}/src/form/builder/responses.ts (75%) rename {packages/tui => pkgs-ts/console}/src/form/builder/revert.ts (76%) rename {packages/tui => pkgs-ts/console}/src/form/builder/status.ts (83%) create mode 100644 pkgs-ts/console/src/form/builder/status/index.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/status/progress.ts (77%) rename {packages/tui => pkgs-ts/console}/src/form/builder/status/spin.ts (76%) rename {packages/tui => pkgs-ts/console}/src/form/builder/status/stream.ts (77%) rename {packages/tui => pkgs-ts/console}/src/form/builder/status/task.ts (75%) rename {packages/tui => pkgs-ts/console}/src/form/builder/step.ts (76%) rename {packages/tui => pkgs-ts/console}/src/form/builder/submit.ts (73%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/conditions.ts (81%) create mode 100644 pkgs-ts/console/src/form/builder/validators/output.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/output/common.ts (100%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/output/data-table.ts (83%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/output/table.ts (79%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/previous.ts (100%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/revert.ts (78%) create mode 100644 pkgs-ts/console/src/form/builder/validators/status.ts rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/status/common.ts (90%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/status/progress.ts (79%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/status/spin.ts (88%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/status/stream.ts (83%) rename {packages/tui => pkgs-ts/console}/src/form/builder/validators/status/task.ts (72%) rename {packages/tui => pkgs-ts/console}/src/form/types.ts (88%) rename {packages/tui => pkgs-ts/console}/src/index.ts (55%) create mode 100644 pkgs-ts/console/src/key.ts rename {packages/tui => pkgs-ts/console}/src/key/constants.ts (100%) rename {packages/tui => pkgs-ts/console}/src/key/event.ts (76%) rename {packages/tui => pkgs-ts/console}/src/key/event/maps.ts (81%) rename {packages/tui => pkgs-ts/console}/src/key/event/value.ts (60%) rename {packages/tui => pkgs-ts/console}/src/key/match.ts (56%) rename {packages/tui => pkgs-ts/console}/src/key/types.ts (83%) rename {packages/tui => pkgs-ts/console}/src/key/validators/event.ts (87%) rename {packages/tui => pkgs-ts/console}/src/key/validators/match.ts (90%) rename {packages/tui => pkgs-ts/console}/src/key/validators/value.ts (89%) rename {packages/tui => pkgs-ts/console}/src/opentui.ts (100%) create mode 100644 pkgs-ts/console/src/output.ts rename {packages/tui => pkgs-ts/console}/src/output/data-table.ts (78%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/body/active.ts (67%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/body/cancelled.ts (65%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/body/headers.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/body/submitted.ts (62%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/body/types.ts (59%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/keys.ts (94%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/multiline.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/navigation.ts (88%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/options.ts (85%) create mode 100644 pkgs-ts/console/src/output/data-table/read.ts rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/cancel.ts (64%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/fallback.ts (61%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/interactive.ts (72%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/result.ts (81%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/session.ts (68%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/session/render.ts (64%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/state.ts (71%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/state/search.ts (86%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/state/selection.ts (62%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/reader/types.ts (60%) create mode 100644 pkgs-ts/console/src/output/data-table/render-body.ts rename {packages/tui => pkgs-ts/console}/src/output/data-table/render.ts (78%) create mode 100644 pkgs-ts/console/src/output/data-table/rows.ts rename {packages/tui => pkgs-ts/console}/src/output/data-table/rows/cells.ts (74%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/rows/fields.ts (85%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/rows/headers.ts (66%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/rows/visible.ts (67%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/run.ts (62%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/scrollbar.ts (80%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/search.ts (90%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/selection.ts (78%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/types.ts (83%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/validators/selection.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/visual-window.ts (85%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/widths.ts (59%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/widths/available.ts (89%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/widths/columns.ts (71%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/widths/natural.ts (79%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/widths/shrink.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/widths/truncate.ts (81%) rename {packages/tui => pkgs-ts/console}/src/output/data-table/widths/validators/dimensions.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/grid-output.ts (68%) rename {packages/tui => pkgs-ts/console}/src/output/grid.ts (62%) rename {packages/tui => pkgs-ts/console}/src/output/grid/layout.ts (92%) rename {packages/tui => pkgs-ts/console}/src/output/grid/lines.ts (88%) rename {packages/tui => pkgs-ts/console}/src/output/grid/validators/layout.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/notes.ts (71%) rename {packages/tui => pkgs-ts/console}/src/output/notes/render.ts (82%) rename {packages/tui => pkgs-ts/console}/src/output/notes/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/notes/validators/message.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/notify.ts (76%) rename {packages/tui => pkgs-ts/console}/src/output/notify/commands.ts (80%) rename {packages/tui => pkgs-ts/console}/src/output/notify/executor.ts (92%) rename {packages/tui => pkgs-ts/console}/src/output/notify/validators/command.ts (92%) rename {packages/tui => pkgs-ts/console}/src/output/notify/validators/options.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/notify/validators/platform.ts (100%) rename {packages/tui => pkgs-ts/console}/src/output/table-output.ts (62%) create mode 100644 pkgs-ts/console/src/output/table.ts rename {packages/tui => pkgs-ts/console}/src/output/terminal.ts (66%) rename {packages/tui => pkgs-ts/console}/src/output/validators/cells.ts (85%) rename {packages/tui => pkgs-ts/console}/src/output/validators/data-table.ts (58%) rename {packages/tui => pkgs-ts/console}/src/output/validators/data-table/options.ts (93%) rename {packages/tui => pkgs-ts/console}/src/output/validators/data-table/row-shape.ts (95%) rename {packages/tui => pkgs-ts/console}/src/output/validators/data-table/schemas.ts (85%) rename {packages/tui => pkgs-ts/console}/src/output/validators/table.ts (84%) rename {packages/tui => pkgs-ts/console}/src/output/validators/table/rows.ts (84%) rename {packages/tui => pkgs-ts/console}/src/output/validators/table/schemas.ts (74%) create mode 100644 pkgs-ts/console/src/prompt.ts rename {packages/tui => pkgs-ts/console}/src/prompt/active-frame.ts (87%) rename {packages/tui => pkgs-ts/console}/src/prompt/ask.ts (65%) rename {packages/tui => pkgs-ts/console}/src/prompt/cancel.ts (88%) rename {packages/tui => pkgs-ts/console}/src/prompt/error.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompt/fallback.ts (96%) rename {packages/tui => pkgs-ts/console}/src/prompt/lifecycle.ts (57%) rename {packages/tui => pkgs-ts/console}/src/prompt/lifecycle/interactive.ts (67%) rename {packages/tui => pkgs-ts/console}/src/prompt/lifecycle/non-interactive.ts (54%) rename {packages/tui => pkgs-ts/console}/src/prompt/lifecycle/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompt/lifecycle/validation.ts (63%) rename {packages/tui => pkgs-ts/console}/src/prompt/revert.ts (54%) rename {packages/tui => pkgs-ts/console}/src/prompt/submission.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompt/validate-using.ts (91%) rename {packages/tui => pkgs-ts/console}/src/prompt/validation.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompt/validators/cancel.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompt/validators/error.ts (80%) rename {packages/tui => pkgs-ts/console}/src/prompt/validators/fallback.ts (83%) rename {packages/tui => pkgs-ts/console}/src/prompt/validators/global-validation.ts (88%) rename {packages/tui => pkgs-ts/console}/src/prompt/validators/invalid.ts (100%) create mode 100644 pkgs-ts/console/src/prompts.ts create mode 100644 pkgs-ts/console/src/prompts/basic.ts create mode 100644 pkgs-ts/console/src/prompts/choices.ts rename {packages/tui => pkgs-ts/console}/src/prompts/number.ts (84%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/defaults.ts (82%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/fallback.ts (66%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/input.ts (50%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/interactive.ts (75%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/options.ts (81%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/render.ts (82%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/run.ts (75%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/session.ts (84%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/session/state.ts (79%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/step.ts (78%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/validators/overload.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/validators/step.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/number/validators/value.ts (95%) rename {packages/tui => pkgs-ts/console}/src/prompts/password.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/password/fallback.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompts/password/input.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompts/password/options.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/password/render.ts (80%) rename {packages/tui => pkgs-ts/console}/src/prompts/password/run.ts (70%) rename {packages/tui => pkgs-ts/console}/src/prompts/password/session.ts (83%) rename {packages/tui => pkgs-ts/console}/src/prompts/password/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/pause.ts (60%) rename {packages/tui => pkgs-ts/console}/src/prompts/pause/read.ts (73%) rename {packages/tui => pkgs-ts/console}/src/prompts/pause/render.ts (59%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/body/render.ts (70%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/body/rows.ts (80%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/choices.ts (72%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/defaults.ts (93%) create mode 100644 pkgs-ts/console/src/prompts/search/index.ts create mode 100644 pkgs-ts/console/src/prompts/search/keys.ts rename {packages/tui => pkgs-ts/console}/src/prompts/search/keys/highlight.ts (84%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/keys/navigation.ts (95%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/line-mode.ts (83%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/multi-options.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/multi-run.ts (65%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/multisearch.ts (82%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/navigation.ts (85%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/options.ts (67%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi.ts (63%) create mode 100644 pkgs-ts/console/src/prompts/search/read-multi/cancel.ts rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/choice-query.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/frame.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/keys.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/result.ts (69%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/session.ts (73%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/session/actions.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/state.ts (72%) create mode 100644 pkgs-ts/console/src/prompts/search/read-multi/state/context.ts rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/state/displayed.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/state/highlight.ts (72%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/state/input.ts (57%) create mode 100644 pkgs-ts/console/src/prompts/search/read-multi/state/labels.ts rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-multi/state/selection.ts (77%) create mode 100644 pkgs-ts/console/src/prompts/search/read-single.ts rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/choice-query.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/interactive.ts (73%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/interactive/cancel.ts (60%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/interactive/result.ts (85%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/result.ts (81%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/session.ts (73%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/session/actions.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/session/frame.ts (66%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/state.ts (72%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/state/highlight.ts (70%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/state/selection.ts (76%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/read-single/types.ts (76%) create mode 100644 pkgs-ts/console/src/prompts/search/render-body.ts rename {packages/tui => pkgs-ts/console}/src/prompts/search/render.ts (84%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/run.ts (70%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/search.ts (82%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/selection.ts (95%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/validators/defaults.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/validators/options.ts (83%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/validators/overload.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/search/validators/source.ts (90%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/confirm-options.ts (90%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/confirm-run.ts (63%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/confirm.ts (83%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/defaults.ts (93%) create mode 100644 pkgs-ts/console/src/prompts/select/index.ts rename {packages/tui => pkgs-ts/console}/src/prompts/select/keys.ts (85%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/multiple.ts (87%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/multiselect.ts (80%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/multiselect/options.ts (81%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/multiselect/run.ts (69%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/navigation.ts (87%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/options.ts (79%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-confirm.ts (61%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-confirm/keys.ts (93%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-confirm/line-mode.ts (80%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-confirm/session.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-confirm/types.ts (76%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple.ts (50%) create mode 100644 pkgs-ts/console/src/prompts/select/read-multiple/cancel.ts rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/interactive.ts (62%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/keys.ts (60%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/line-mode.ts (59%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/result.ts (82%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/session.ts (76%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/session/frame.ts (73%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/session/state.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-multiple/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-selected.ts (52%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-selected/interactive.ts (68%) create mode 100644 pkgs-ts/console/src/prompts/select/read-selected/interactive/cancel.ts rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-selected/interactive/result.ts (68%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-selected/line-mode.ts (67%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-selected/result.ts (86%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-selected/session.ts (67%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/read-selected/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/render-confirm.ts (87%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/render-rows.ts (87%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/render-rows/window.ts (73%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/render.ts (86%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/run.ts (67%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/select.ts (86%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/validators/defaults.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/validators/options.ts (83%) rename {packages/tui => pkgs-ts/console}/src/prompts/select/validators/overload.ts (89%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/autocomplete-prompt.ts (67%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/autocomplete.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/ghost-text.ts (79%) create mode 100644 pkgs-ts/console/src/prompts/suggest/index.ts rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/keys.ts (92%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/lifecycle.ts (75%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/navigation.ts (94%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/options.ts (84%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read-autocomplete.ts (64%) create mode 100644 pkgs-ts/console/src/prompts/suggest/read-autocomplete/cancel.ts rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read-autocomplete/frame.ts (69%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read-autocomplete/session.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read-autocomplete/state.ts (77%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read-autocomplete/state/highlight.ts (84%) create mode 100644 pkgs-ts/console/src/prompts/suggest/read-autocomplete/submission.ts rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read-result.ts (76%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read.ts (68%) create mode 100644 pkgs-ts/console/src/prompts/suggest/read/cancel.ts rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read/frame.ts (70%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read/session.ts (76%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read/state.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read/state/highlight.ts (76%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/read/submission.ts (67%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/render-autocomplete.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/render.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/render/body.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/render/rows.ts (74%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/resolve.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/state/query.ts (78%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/suggest.ts (71%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/validators/overload.ts (100%) rename {packages/tui => pkgs-ts/console}/src/prompts/suggest/validators/source.ts (92%) rename {packages/tui => pkgs-ts/console}/src/prompts/text-default.ts (82%) rename {packages/tui => pkgs-ts/console}/src/prompts/text.ts (79%) rename {packages/tui => pkgs-ts/console}/src/prompts/text/options.ts (78%) rename {packages/tui => pkgs-ts/console}/src/prompts/text/run.ts (70%) rename {packages/tui => pkgs-ts/console}/src/prompts/textarea.ts (80%) rename {packages/tui => pkgs-ts/console}/src/prompts/textarea/options.ts (86%) rename {packages/tui => pkgs-ts/console}/src/prompts/textarea/run.ts (72%) create mode 100644 pkgs-ts/console/src/status.ts rename {packages/tui => pkgs-ts/console}/src/status/frame.ts (85%) rename {packages/tui => pkgs-ts/console}/src/status/progress.ts (71%) rename {packages/tui => pkgs-ts/console}/src/status/progress/controller.ts (74%) rename {packages/tui => pkgs-ts/console}/src/status/progress/labels.ts (76%) rename {packages/tui => pkgs-ts/console}/src/status/progress/progress.ts (73%) rename {packages/tui => pkgs-ts/console}/src/status/progress/prompt.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/progress/readback.ts (78%) rename {packages/tui => pkgs-ts/console}/src/status/progress/render.ts (83%) rename {packages/tui => pkgs-ts/console}/src/status/progress/renderer.ts (52%) rename {packages/tui => pkgs-ts/console}/src/status/progress/run.ts (91%) rename {packages/tui => pkgs-ts/console}/src/status/progress/state.ts (70%) rename {packages/tui => pkgs-ts/console}/src/status/progress/state/snapshot.ts (81%) rename {packages/tui => pkgs-ts/console}/src/status/progress/state/value.ts (86%) rename {packages/tui => pkgs-ts/console}/src/status/progress/steps.ts (76%) rename {packages/tui => pkgs-ts/console}/src/status/progress/terminal.ts (71%) rename {packages/tui => pkgs-ts/console}/src/status/progress/terminal/signals.ts (82%) rename {packages/tui => pkgs-ts/console}/src/status/progress/validators/arguments.ts (94%) rename {packages/tui => pkgs-ts/console}/src/status/progress/validators/frame.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/signals.ts (85%) rename {packages/tui => pkgs-ts/console}/src/status/spinner.ts (70%) rename {packages/tui => pkgs-ts/console}/src/status/spinner/lifecycle.ts (61%) rename {packages/tui => pkgs-ts/console}/src/status/spinner/options.ts (82%) rename {packages/tui => pkgs-ts/console}/src/status/spinner/render.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/spinner/validators/options.ts (91%) rename {packages/tui => pkgs-ts/console}/src/status/stream.ts (74%) rename {packages/tui => pkgs-ts/console}/src/status/stream/buffer.ts (89%) rename {packages/tui => pkgs-ts/console}/src/status/stream/fade.ts (86%) rename {packages/tui => pkgs-ts/console}/src/status/stream/lifecycle.ts (83%) rename {packages/tui => pkgs-ts/console}/src/status/stream/output.ts (70%) rename {packages/tui => pkgs-ts/console}/src/status/stream/output/context.ts (59%) rename {packages/tui => pkgs-ts/console}/src/status/stream/output/errors.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/stream/output/pipe.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/stream/output/readback.ts (64%) rename {packages/tui => pkgs-ts/console}/src/status/stream/output/rendering.ts (83%) rename {packages/tui => pkgs-ts/console}/src/status/stream/render.ts (75%) rename {packages/tui => pkgs-ts/console}/src/status/stream/renderer.ts (66%) rename {packages/tui => pkgs-ts/console}/src/status/stream/scheduler.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/stream/validators/chunk.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/stream/validators/fade.ts (88%) rename {packages/tui => pkgs-ts/console}/src/status/task.ts (59%) rename {packages/tui => pkgs-ts/console}/src/status/task/definition.ts (86%) rename {packages/tui => pkgs-ts/console}/src/status/task/frame.ts (81%) rename {packages/tui => pkgs-ts/console}/src/status/task/lifecycle.ts (64%) rename {packages/tui => pkgs-ts/console}/src/status/task/lifecycle/rendering.ts (74%) create mode 100644 pkgs-ts/console/src/status/task/logger.ts rename {packages/tui => pkgs-ts/console}/src/status/task/logger/events.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/labels.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/limits.ts (78%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/lines.ts (84%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/logger.ts (72%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/methods.ts (66%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/output.ts (69%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/stable.ts (68%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/sync.ts (78%) rename {packages/tui => pkgs-ts/console}/src/status/task/logger/validators/message.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/task/messages.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/task/process-output.ts (74%) rename {packages/tui => pkgs-ts/console}/src/status/task/process-output/buffer.ts (76%) rename {packages/tui => pkgs-ts/console}/src/status/task/process-output/validators/chunk.ts (100%) create mode 100644 pkgs-ts/console/src/status/task/process-output/validators/writer.ts rename {packages/tui => pkgs-ts/console}/src/status/task/process-output/validators/writer/callback.ts (93%) rename {packages/tui => pkgs-ts/console}/src/status/task/process-output/validators/writer/chunk.ts (83%) rename {packages/tui => pkgs-ts/console}/src/status/task/process-output/validators/writer/stream.ts (93%) rename {packages/tui => pkgs-ts/console}/src/status/task/process-output/writer.ts (71%) rename {packages/tui => pkgs-ts/console}/src/status/task/render.ts (87%) rename {packages/tui => pkgs-ts/console}/src/status/task/sanitize.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/task/validators/definition.ts (84%) rename {packages/tui => pkgs-ts/console}/src/status/validators/limit.ts (100%) rename {packages/tui => pkgs-ts/console}/src/status/validators/progress.ts (95%) rename {packages/tui => pkgs-ts/console}/src/status/validators/signal-target.ts (91%) create mode 100644 pkgs-ts/console/src/string-utils/ansi.ts rename {packages/tui => pkgs-ts/console}/src/string-utils/ansi/codes.ts (100%) rename {packages/tui => pkgs-ts/console}/src/string-utils/ansi/segments.ts (98%) rename {packages/tui => pkgs-ts/console}/src/string-utils/truncate.ts (85%) rename {packages/tui => pkgs-ts/console}/src/string-utils/validators/width.ts (100%) rename {packages/tui => pkgs-ts/console}/src/string-utils/width.ts (100%) rename {packages/tui => pkgs-ts/console}/src/string-utils/wrap.ts (57%) rename {packages/tui => pkgs-ts/console}/src/string-utils/wrap/ansi.ts (89%) rename {packages/tui => pkgs-ts/console}/src/string-utils/wrap/plain.ts (91%) create mode 100644 pkgs-ts/console/src/strings.ts rename {packages/tui => pkgs-ts/console}/src/terminal.ts (83%) rename {packages/tui => pkgs-ts/console}/src/terminal/capabilities.ts (86%) rename {packages/tui => pkgs-ts/console}/src/terminal/validators/color.ts (84%) rename {packages/tui => pkgs-ts/console}/src/terminal/validators/size.ts (100%) rename {packages/tui => pkgs-ts/console}/src/terminal/validators/title.ts (100%) create mode 100644 pkgs-ts/console/src/theme.ts rename {packages/tui => pkgs-ts/console}/src/theme/box.ts (89%) rename {packages/tui => pkgs-ts/console}/src/theme/choice-disabled.ts (71%) rename {packages/tui => pkgs-ts/console}/src/theme/choices.ts (73%) rename {packages/tui => pkgs-ts/console}/src/theme/error.ts (51%) rename {packages/tui => pkgs-ts/console}/src/theme/question.ts (77%) rename {packages/tui => pkgs-ts/console}/src/theme/styles.ts (100%) rename {packages/tui => pkgs-ts/console}/src/theme/symbols.ts (100%) rename {packages/tui => pkgs-ts/console}/src/theme/table.ts (88%) rename {packages/tui => pkgs-ts/console}/src/theme/validators/box.ts (100%) rename {packages/tui => pkgs-ts/console}/src/theme/validators/disabled.ts (100%) rename {packages/tui => pkgs-ts/console}/src/theme/validators/table.ts (100%) create mode 100644 pkgs-ts/console/src/typed-value.ts rename {packages/tui => pkgs-ts/console}/src/typed-value/characters.ts (100%) rename {packages/tui => pkgs-ts/console}/src/typed-value/cursor.ts (74%) rename {packages/tui => pkgs-ts/console}/src/typed-value/delete.ts (85%) rename {packages/tui => pkgs-ts/console}/src/typed-value/edit.ts (68%) rename {packages/tui => pkgs-ts/console}/src/typed-value/edit/deletion.ts (84%) rename {packages/tui => pkgs-ts/console}/src/typed-value/edit/insertion.ts (78%) rename {packages/tui => pkgs-ts/console}/src/typed-value/edit/navigation.ts (88%) rename {packages/tui => pkgs-ts/console}/src/typed-value/edit/result.ts (71%) rename {packages/tui => pkgs-ts/console}/src/typed-value/line-ranges.ts (92%) rename {packages/tui => pkgs-ts/console}/src/typed-value/lines.ts (72%) rename {packages/tui => pkgs-ts/console}/src/typed-value/lines/text-window.ts (77%) rename {packages/tui => pkgs-ts/console}/src/typed-value/lines/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/typed-value/lines/window.ts (69%) rename {packages/tui => pkgs-ts/console}/src/typed-value/read.ts (66%) rename {packages/tui => pkgs-ts/console}/src/typed-value/read/cancel.ts (56%) rename {packages/tui => pkgs-ts/console}/src/typed-value/read/fallback.ts (60%) rename {packages/tui => pkgs-ts/console}/src/typed-value/render.ts (75%) rename {packages/tui => pkgs-ts/console}/src/typed-value/textarea-frame.ts (77%) rename {packages/tui => pkgs-ts/console}/src/typed-value/textarea.ts (100%) rename {packages/tui => pkgs-ts/console}/src/typed-value/types.ts (100%) rename {packages/tui => pkgs-ts/console}/src/typed-value/validators/cursor.ts (100%) rename {packages/tui => pkgs-ts/console}/src/typed-value/validators/rows.ts (100%) rename {packages/tui => pkgs-ts/console}/src/typed-value/validators/width.ts (100%) rename {packages/tui => pkgs-ts/console}/src/types.ts (56%) rename {packages/tui => pkgs-ts/console}/src/validators/default.ts (100%) rename {packages/tui => pkgs-ts/console}/src/validators/function.ts (100%) rename {packages/tui => pkgs-ts/console}/src/validators/iterable.ts (93%) rename {packages/tui => pkgs-ts/console}/src/validators/required.ts (100%) rename {packages/tui => pkgs-ts/console}/src/validators/result.ts (86%) rename {packages/tui => pkgs-ts/console}/tests/choices.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/environment.test.ts (96%) rename {packages/tui => pkgs-ts/console}/tests/form.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/key.test.ts (96%) rename {packages/tui => pkgs-ts/console}/tests/notify.test.ts (97%) rename {packages/tui => pkgs-ts/console}/tests/number.test.ts (98%) rename {packages/tui => pkgs-ts/console}/tests/output.test.ts (98%) rename {packages/tui => pkgs-ts/console}/tests/password.test.ts (98%) rename {packages/tui => pkgs-ts/console}/tests/pause.test.ts (97%) rename {packages/tui => pkgs-ts/console}/tests/progress.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/prompt.test.ts (92%) rename {packages/tui => pkgs-ts/console}/tests/search.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/spinner.test.ts (96%) rename {packages/tui => pkgs-ts/console}/tests/stream.test.ts (96%) rename {packages/tui => pkgs-ts/console}/tests/strings.test.ts (98%) rename {packages/tui => pkgs-ts/console}/tests/suggest.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/table.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/task.test.ts (98%) rename {packages/tui => pkgs-ts/console}/tests/terminal.test.ts (98%) rename {packages/tui => pkgs-ts/console}/tests/text.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/textarea.test.ts (99%) rename {packages/tui => pkgs-ts/console}/tests/typed-value.test.ts (97%) rename {packages/tui => pkgs-ts/console}/tsconfig.build.json (80%) create mode 100644 pkgs-ts/console/tsconfig.json rename {packages/tui => pkgs-ts/console}/vitest.config.ts (92%) rename {packages/acceptance => pkgs-ts/tests}/package.json (82%) rename {packages/acceptance/tests => pkgs-ts/tests/tests/distribution}/package.test.ts (91%) create mode 100644 pkgs-ts/tests/tests/forms/form-builder.test.ts create mode 100644 pkgs-ts/tests/tests/output/messages.test.ts create mode 100644 pkgs-ts/tests/tests/output/status.test.ts create mode 100644 pkgs-ts/tests/tests/prompts/prompts.test.ts rename {packages/acceptance/tests => pkgs-ts/tests/tests/rendering}/opentui.test.ts (95%) create mode 100644 pkgs-ts/tests/tests/support/scripted.ts create mode 100644 pkgs-ts/tests/tsconfig.json rename {packages/acceptance => pkgs-ts/tests}/vitest.config.ts (73%) diff --git a/.gitignore b/.gitignore index b9b7998b..1ea40b92 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,11 @@ infra/.cache/ .idea/ coverage/ *.tsbuildinfo -packages/tui/dist/ -packages/docs/src/.vitepress/ -packages/docs/src/api/ +pkgs-ts/console/dist/ +apps/docs/src/.vitepress/ +apps/docs/src/api/ + +# Go +pkgs-go/bin/ +*.test +*.out diff --git a/README.md b/README.md index 5e0fa2ae..b6c4c832 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# `@ollin/tui` +# `@ollin/console` An idiomatic TypeScript/OpenTUI prompt toolkit. @@ -7,14 +7,14 @@ This repository targets behavioral parity with reference prompt toolkit release ## Status -The current codebase is a TypeScript ESM package with the public `@ollin/tui` +The current codebase is a TypeScript ESM package with the public `@ollin/console` 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 +consumption through `pkgs-ts/tests`. The docs package builds a VitePress guide plus generated API reference. Reference parity and the completion audit are tracked in `UPSTREAM.md`. diff --git a/UPSTREAM.md b/UPSTREAM.md index f387620b..05a554bf 100644 --- a/UPSTREAM.md +++ b/UPSTREAM.md @@ -11,214 +11,214 @@ TypeScript and OpenTUI internals. | Reference area | TypeScript area | | --- | --- | -| 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 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 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` | -| 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/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/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/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/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/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/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/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/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/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/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` | -| 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/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/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/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 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/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/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` | -| 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, 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` | +| Helper functions | `pkgs-ts/console/src/index.ts` | +| Prompt lifecycle and fallback behavior | `pkgs-ts/console/src/prompt.ts`, `pkgs-ts/console/src/environment.ts`, `pkgs-ts/console/src/environment/*` | +| Prompt fallback reset, predicate condition validation, scoped lifecycle, and predicate condition lifecycle | `pkgs-ts/console/src/prompt/fallback.ts`, `pkgs-ts/console/src/prompt/validators/fallback.ts`, `pkgs-ts/console/src/environment/scope.ts`, `pkgs-ts/console/src/prompt.ts`, `pkgs-ts/console/src/index.ts` | +| Prompt cancellation callback scoped lifecycle | `pkgs-ts/console/src/prompt/cancel.ts`, `pkgs-ts/console/src/environment/scope.ts`, `pkgs-ts/console/tests/prompt.test.ts` | +| Prompt revert rejection lifecycle | `pkgs-ts/console/src/prompt/revert.ts`, `pkgs-ts/console/src/form/builder/revert.ts`, `pkgs-ts/console/src/prompts/select/read-confirm.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Prompt validation retry default lifecycle and parser-error submitted-value preservation | `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/src/prompt/lifecycle/*`, `pkgs-ts/console/src/prompt/error.ts`, `pkgs-ts/console/tests/text.test.ts` | +| Prompt post-validation submitted-frame lifecycle | `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/src/prompt/lifecycle/*`, `pkgs-ts/console/src/prompts/text.ts`, `pkgs-ts/console/src/prompts/text/*`, `pkgs-ts/console/src/prompts/number.ts`, `pkgs-ts/console/tests/text.test.ts`, `pkgs-ts/console/tests/number.test.ts` | +| Prompt invalid-attempt active-frame cleanup lifecycle | `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/src/prompt/lifecycle/*`, `pkgs-ts/console/src/prompt/active-frame.ts`, `pkgs-ts/console/src/prompts/*`, `pkgs-ts/console/src/output/data-table.ts` | +| Prompt non-interactive raw-default validation lifecycle | `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/src/prompt/lifecycle/*` | +| Prompt validation error styling | `pkgs-ts/console/src/theme.ts`, `pkgs-ts/console/tests/prompt.test.ts` | +| Prompt validation warning line styling | `pkgs-ts/console/src/theme.ts`, `pkgs-ts/console/src/prompt/lifecycle.ts` | +| Prompt local and scoped global validation composition | `pkgs-ts/console/src/prompt/validation.ts`, `pkgs-ts/console/src/prompt/validate-using.ts`, `pkgs-ts/console/src/environment/scope.ts` | +| Key constants, value validation, and event mapping | `pkgs-ts/console/src/key.ts`, `pkgs-ts/console/src/key/*` | +| Terminal helpers | `pkgs-ts/console/src/terminal.ts` | +| Text input | `pkgs-ts/console/src/prompts/text.ts`, `pkgs-ts/console/src/typed-value.ts` | +| Text input defaults, transforms, validation, editing keys, non-interactive behavior, and failed reads | `pkgs-ts/console/src/prompts/text.ts`, `pkgs-ts/console/src/prompts/text/*`, `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/src/typed-value.ts`, `pkgs-ts/console/src/typed-value/read/*`, `pkgs-ts/console/tests/text.test.ts` | +| Text active, submitted, cancelled, placeholder, and validation-safe rendering | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/text.ts`, `pkgs-ts/console/src/prompts/text/*`, `pkgs-ts/console/src/typed-value.ts`, `pkgs-ts/console/src/typed-value/read/*`, `pkgs-ts/console/src/typed-value/render.ts`, `pkgs-ts/console/tests/text.test.ts` | +| Text active-frame redraw and submitted-frame replacement | `pkgs-ts/console/src/typed-value.ts`, `pkgs-ts/console/src/typed-value/render.ts`, `pkgs-ts/console/src/prompts/text.ts`, `pkgs-ts/console/src/prompts/text/*` | +| Text transformed fallback value, invalid retry default preservation, overload validation, and plain placeholder rendering | `pkgs-ts/console/src/prompts/text.ts`, `pkgs-ts/console/src/prompts/text/*`, `pkgs-ts/console/src/prompts/text-default.ts`, `pkgs-ts/console/src/concerns/validators/text-options.ts`, `pkgs-ts/console/src/typed-value/render.ts` | +| Textarea input | `pkgs-ts/console/src/prompts/textarea.ts`, `pkgs-ts/console/src/typed-value.ts` | +| Textarea defaults, transforms, validation, editing keys, line navigation, and non-interactive behavior | `pkgs-ts/console/src/prompts/textarea.ts`, `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/src/typed-value.ts`, `pkgs-ts/console/src/typed-value/read/*`, `pkgs-ts/console/tests/textarea.test.ts` | +| Textarea active, submitted, cancelled, scrollbar, placeholder, and validation-safe rendering | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/textarea.ts`, `pkgs-ts/console/src/typed-value.ts`, `pkgs-ts/console/src/typed-value/read/*`, `pkgs-ts/console/src/typed-value/textarea-frame.ts`, `pkgs-ts/console/tests/textarea.test.ts` | +| Textarea active-frame redraw and cursor-aware visible window rendering | `pkgs-ts/console/src/typed-value.ts`, `pkgs-ts/console/src/typed-value/lines.ts`, `pkgs-ts/console/src/typed-value/lines/*`, `pkgs-ts/console/src/typed-value/line-ranges.ts`, `pkgs-ts/console/src/typed-value/textarea-frame.ts`, `pkgs-ts/console/src/prompts/textarea.ts` | +| Textarea transformed fallback value, invalid retry default preservation, overload validation, and plain placeholder rendering | `pkgs-ts/console/src/prompts/textarea.ts`, `pkgs-ts/console/src/prompts/text-default.ts`, `pkgs-ts/console/src/concerns/validators/text-options.ts`, `pkgs-ts/console/src/typed-value/textarea-frame.ts` | +| Textarea control-key line navigation and empty-line movement | `pkgs-ts/console/src/typed-value/edit/navigation.ts`, `pkgs-ts/console/tests/textarea.test.ts` | +| Textarea boxed renderer and placeholder styling | `pkgs-ts/console/src/typed-value/textarea-frame.ts`, `pkgs-ts/console/tests/textarea.test.ts` | +| Textarea scrollbar rendering | `pkgs-ts/console/src/typed-value/textarea-frame.ts`, `pkgs-ts/console/src/typed-value/lines.ts`, `pkgs-ts/console/src/typed-value/lines/*`, `pkgs-ts/console/src/typed-value/line-ranges.ts`, `pkgs-ts/console/tests/textarea.test.ts` | +| Textarea wrapped frame line windows | `pkgs-ts/console/src/typed-value/textarea-frame.ts`, `pkgs-ts/console/src/typed-value/lines.ts`, `pkgs-ts/console/src/typed-value/lines/*`, `pkgs-ts/console/src/typed-value/line-ranges.ts`, `pkgs-ts/console/tests/textarea.test.ts`, `pkgs-ts/console/tests/typed-value.test.ts` | +| Textarea wrapped-line cursor navigation | `pkgs-ts/console/src/typed-value.ts`, `pkgs-ts/console/src/typed-value/edit.ts`, `pkgs-ts/console/src/typed-value/edit/navigation.ts`, `pkgs-ts/console/src/typed-value/lines.ts`, `pkgs-ts/console/src/typed-value/lines/*`, `pkgs-ts/console/src/typed-value/line-ranges.ts`, `pkgs-ts/console/tests/textarea.test.ts`, `pkgs-ts/console/tests/typed-value.test.ts` | +| Password input | `pkgs-ts/console/src/prompts/password.ts`, `pkgs-ts/console/src/typed-value.ts` | +| Password input transforms, validation retry, editing keys, cancellation, masking, and non-interactive behavior | `pkgs-ts/console/src/prompts/password.ts`, `pkgs-ts/console/src/prompts/password/options.ts`, `pkgs-ts/console/src/prompts/password/run.ts`, `pkgs-ts/console/src/prompts/password/input.ts`, `pkgs-ts/console/src/prompts/password/fallback.ts`, `pkgs-ts/console/src/prompts/password/session.ts`, `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/tests/password.test.ts` | +| Password active, submitted, cancelled, placeholder, masked, and validation-safe rendering | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/password.ts`, `pkgs-ts/console/src/prompts/password/run.ts`, `pkgs-ts/console/src/prompts/password/input.ts`, `pkgs-ts/console/src/prompts/password/session.ts`, `pkgs-ts/console/src/prompts/password/render.ts`, `pkgs-ts/console/tests/password.test.ts` | +| Password active-frame redraw and masked cursor rendering | `pkgs-ts/console/src/prompts/password.ts`, `pkgs-ts/console/src/prompts/password/run.ts`, `pkgs-ts/console/src/prompts/password/input.ts`, `pkgs-ts/console/src/prompts/password/session.ts`, `pkgs-ts/console/src/prompts/password/render.ts` | +| Password transformed fallback value, invalid retry default preservation, overload validation, and plain placeholder rendering | `pkgs-ts/console/src/prompts/password.ts`, `pkgs-ts/console/src/prompts/password/options.ts`, `pkgs-ts/console/src/prompts/password/run.ts`, `pkgs-ts/console/src/prompts/text-default.ts`, `pkgs-ts/console/src/concerns/validators/text-options.ts`, `pkgs-ts/console/src/prompts/password/render.ts` | +| Number input | `pkgs-ts/console/src/prompts/number.ts`, `pkgs-ts/console/src/typed-value.ts` | +| Number active, submitted, cancelled, arrow, placeholder, default, and validation-safe rendering | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/number.ts`, `pkgs-ts/console/src/prompts/number/input.ts`, `pkgs-ts/console/src/prompts/number/interactive.ts`, `pkgs-ts/console/src/prompts/number/session.ts`, `pkgs-ts/console/src/prompts/number/session/*`, `pkgs-ts/console/src/prompts/number/render.ts`, `pkgs-ts/console/tests/number.test.ts` | +| Number default renderer inline arrow controls | `pkgs-ts/console/src/prompts/number/render.ts` | +| Number active-frame redraw and cursor rendering | `pkgs-ts/console/src/prompts/number.ts`, `pkgs-ts/console/src/prompts/number/input.ts`, `pkgs-ts/console/src/prompts/number/interactive.ts`, `pkgs-ts/console/src/prompts/number/session.ts`, `pkgs-ts/console/src/prompts/number/session/*`, `pkgs-ts/console/src/prompts/number/render.ts` | +| Number explicit-default lifecycle, invalid retry default preservation, parser-error retry preservation, overload validation, and transformed fallback value | `pkgs-ts/console/src/prompts/number.ts`, `pkgs-ts/console/src/prompts/number/defaults.ts`, `pkgs-ts/console/src/prompts/number/input.ts`, `pkgs-ts/console/src/prompts/number/fallback.ts`, `pkgs-ts/console/src/prompts/number/validators/overload.ts`, `pkgs-ts/console/src/validators/default.ts` | +| Confirm, select, multiselect | `pkgs-ts/console/src/prompts/select/*` | +| Confirm active, submitted, cancelled, custom-label, fallback, and non-interactive behavior | `pkgs-ts/console/src/prompts/select/read-confirm.ts`, `pkgs-ts/console/src/prompts/select/read-confirm/*`, `pkgs-ts/console/src/prompts/select/render-confirm.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Confirm submitted frame renders only after validation passes | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/select/confirm.ts`, `pkgs-ts/console/src/prompts/select/confirm-run.ts`, `pkgs-ts/console/src/prompts/select/read-confirm.ts`, `pkgs-ts/console/src/prompts/select/read-confirm/*`, `pkgs-ts/console/tests/choices.test.ts` | +| Confirm explicit-default lifecycle, invalid retry default preservation, overload validation, and transformed fallback value | `pkgs-ts/console/src/prompts/select/confirm.ts`, `pkgs-ts/console/src/prompts/select/confirm-options.ts`, `pkgs-ts/console/src/prompts/select/confirm-run.ts`, `pkgs-ts/console/src/prompts/select/read-confirm.ts`, `pkgs-ts/console/src/prompts/select/read-confirm/*`, `pkgs-ts/console/src/prompts/select/validators/overload.ts`, `pkgs-ts/console/src/validators/default.ts` | +| Confirm active-frame redraw and submitted-frame replacement | `pkgs-ts/console/src/prompts/select/confirm.ts`, `pkgs-ts/console/src/prompts/select/confirm-run.ts`, `pkgs-ts/console/src/prompts/select/read-confirm.ts`, `pkgs-ts/console/src/prompts/select/read-confirm/*`, `pkgs-ts/console/src/prompts/select/render-confirm.ts` | +| Confirm active and cancelled body styling | `pkgs-ts/console/src/prompts/select/render-confirm.ts` | +| Select active boxed layout and row styling | `pkgs-ts/console/src/concerns/choice-label.ts`, `pkgs-ts/console/src/theme/choice-disabled.ts`, `pkgs-ts/console/src/theme/validators/disabled.ts`, `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/render-rows.ts`, `pkgs-ts/console/src/prompts/select/render-rows/*`, `pkgs-ts/console/tests/choices.test.ts` | +| Select and multi-select label-first helper argument surface with info | `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Select required-option validation | `pkgs-ts/console/src/prompts/select/validators/options.ts`, `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/select.ts`, `pkgs-ts/console/src/prompts/select/options.ts`, `pkgs-ts/console/src/prompts/select/run.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Select non-interactive default validation | `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/select.ts`, `pkgs-ts/console/src/prompts/select/options.ts`, `pkgs-ts/console/src/prompts/select/run.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Select explicit-default lifecycle, invalid retry default preservation, overload validation, and transformed fallback value | `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/select.ts`, `pkgs-ts/console/src/prompts/select/defaults.ts`, `pkgs-ts/console/src/prompts/select/read-selected.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive.ts`, `pkgs-ts/console/src/prompts/select/read-selected/result.ts`, `pkgs-ts/console/src/prompts/select/validators/overload.ts`, `pkgs-ts/console/src/concerns/choices.ts`, `pkgs-ts/console/src/concerns/choice-match.ts`, `pkgs-ts/console/src/validators/default.ts` | +| Select line-mode and exhausted-input default fallback with validation retry | `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/select.ts`, `pkgs-ts/console/src/prompts/select/read-selected.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive.ts`, `pkgs-ts/console/src/prompts/select/read-selected/result.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Select submitted final frame | `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/read-selected.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive/*`, `pkgs-ts/console/tests/choices.test.ts` | +| Select submitted frame renders only after validation passes | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/select.ts`, `pkgs-ts/console/src/prompts/select/run.ts`, `pkgs-ts/console/src/prompts/select/read-selected.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive/*`, `pkgs-ts/console/src/prompts/select/read-selected/result.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Select active-frame redraw and submitted-frame replacement | `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/select.ts`, `pkgs-ts/console/src/prompts/select/run.ts`, `pkgs-ts/console/src/prompts/select/read-selected.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive/*`, `pkgs-ts/console/src/prompts/select/render.ts` | +| Select cancel final frame | `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/read-selected.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive.ts`, `pkgs-ts/console/src/prompts/select/read-selected/interactive/*`, `pkgs-ts/console/tests/choices.test.ts` | +| Select cancelled frame row styling | `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/render-rows.ts`, `pkgs-ts/console/src/prompts/select/render-rows/*` | +| Multi-select active boxed layout and row styling | `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/render-rows.ts`, `pkgs-ts/console/src/prompts/select/render-rows/*`, `pkgs-ts/console/tests/choices.test.ts` | +| Multi-select transformed fallback value and invalid retry default preservation | `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/multiselect.ts`, `pkgs-ts/console/src/prompts/select/multiselect/*`, `pkgs-ts/console/src/prompts/select/defaults.ts`, `pkgs-ts/console/src/prompts/select/validators/overload.ts` | +| Multi-select submitted final frame | `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/read-multiple.ts`, `pkgs-ts/console/src/prompts/select/read-multiple/*`, `pkgs-ts/console/src/prompts/select/read-multiple/session/*`, `pkgs-ts/console/src/prompts/select/read-multiple/result.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Multi-select empty submitted final frame | `pkgs-ts/console/src/prompts/select/render.ts` | +| Multi-select submitted frame renders only after validation passes | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/multiselect.ts`, `pkgs-ts/console/src/prompts/select/multiselect/*`, `pkgs-ts/console/src/prompts/select/read-multiple.ts`, `pkgs-ts/console/src/prompts/select/read-multiple/*`, `pkgs-ts/console/src/prompts/select/read-multiple/session/*`, `pkgs-ts/console/src/prompts/select/read-multiple/result.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Multi-select active-frame redraw and submitted-frame replacement | `pkgs-ts/console/src/prompts/select/index.ts`, `pkgs-ts/console/src/prompts/select/multiselect.ts`, `pkgs-ts/console/src/prompts/select/multiselect/*`, `pkgs-ts/console/src/prompts/select/read-multiple.ts`, `pkgs-ts/console/src/prompts/select/read-multiple/*`, `pkgs-ts/console/src/prompts/select/read-multiple/session/*`, `pkgs-ts/console/src/prompts/select/render.ts` | +| Multi-select cancel final frame | `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/read-multiple.ts`, `pkgs-ts/console/src/prompts/select/read-multiple/*`, `pkgs-ts/console/src/prompts/select/read-multiple/session/*`, `pkgs-ts/console/src/prompts/select/read-multiple/result.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Multi-select cancelled frame row styling | `pkgs-ts/console/src/prompts/select/render.ts`, `pkgs-ts/console/src/prompts/select/render-rows.ts`, `pkgs-ts/console/src/prompts/select/render-rows/*` | +| Suggest, autocomplete | `pkgs-ts/console/src/prompts/suggest/*` | +| Suggest active, submitted, cancelled, placeholder, info, scrolling, and validation-safe rendering | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/suggest/suggest.ts`, `pkgs-ts/console/src/prompts/suggest/lifecycle.ts`, `pkgs-ts/console/src/prompts/suggest/read.ts`, `pkgs-ts/console/src/prompts/suggest/read/*`, `pkgs-ts/console/src/prompts/suggest/read/state/*`, `pkgs-ts/console/src/prompts/suggest/state/*`, `pkgs-ts/console/src/prompts/suggest/read-result.ts`, `pkgs-ts/console/src/prompts/suggest/render.ts`, `pkgs-ts/console/src/prompts/suggest/render/*`, `pkgs-ts/console/tests/suggest.test.ts` | +| Suggest active-frame redraw and cursor rendering | `pkgs-ts/console/src/prompts/suggest/suggest.ts`, `pkgs-ts/console/src/prompts/suggest/read.ts`, `pkgs-ts/console/src/prompts/suggest/read/*`, `pkgs-ts/console/src/prompts/suggest/read/state/*`, `pkgs-ts/console/src/prompts/suggest/state/*`, `pkgs-ts/console/src/prompts/suggest/read-result.ts`, `pkgs-ts/console/src/prompts/suggest/render.ts`, `pkgs-ts/console/src/prompts/suggest/render/*` | +| Suggest empty-result rendering for empty and typed queries | `pkgs-ts/console/src/prompts/suggest/render.ts`, `pkgs-ts/console/src/prompts/suggest/render/*` | +| Suggest and autocomplete transformed fallback value, invalid retry default preservation, source validation, and overload validation | `pkgs-ts/console/src/prompts/suggest/suggest.ts`, `pkgs-ts/console/src/prompts/suggest/autocomplete-prompt.ts`, `pkgs-ts/console/src/prompts/suggest/lifecycle.ts`, `pkgs-ts/console/src/prompts/suggest/validators/overload.ts`, `pkgs-ts/console/src/prompts/suggest/validators/source.ts`, `pkgs-ts/console/src/prompts/text-default.ts` | +| Suggest and autocomplete plain placeholder rendering | `pkgs-ts/console/src/prompts/suggest/render.ts`, `pkgs-ts/console/src/prompts/suggest/render-autocomplete.ts` | +| Suggest and autocomplete label-first info rendering | `pkgs-ts/console/src/prompts/suggest/suggest.ts`, `pkgs-ts/console/src/prompts/suggest/autocomplete-prompt.ts`, `pkgs-ts/console/src/prompts/suggest/options.ts`, `pkgs-ts/console/src/prompts/suggest/read-autocomplete.ts`, `pkgs-ts/console/src/prompts/suggest/read-result.ts`, `pkgs-ts/console/src/prompts/suggest/render-autocomplete.ts`, `pkgs-ts/console/tests/suggest.test.ts` | +| Autocomplete styled cursor-aware ghost text and Unicode-safe completion acceptance | `pkgs-ts/console/src/prompts/suggest/ghost-text.ts`, `pkgs-ts/console/src/prompts/suggest/autocomplete.ts`, `pkgs-ts/console/src/theme/styles.ts`, `pkgs-ts/console/tests/suggest.test.ts` | +| Autocomplete active, submitted, cancelled, placeholder, ghost-text, and validation-safe rendering | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/suggest/autocomplete-prompt.ts`, `pkgs-ts/console/src/prompts/suggest/lifecycle.ts`, `pkgs-ts/console/src/prompts/suggest/read-autocomplete.ts`, `pkgs-ts/console/src/prompts/suggest/read-autocomplete/*`, `pkgs-ts/console/src/prompts/suggest/read-autocomplete/state/*`, `pkgs-ts/console/src/prompts/suggest/state/*`, `pkgs-ts/console/src/prompts/suggest/read-result.ts`, `pkgs-ts/console/src/prompts/suggest/render-autocomplete.ts`, `pkgs-ts/console/tests/suggest.test.ts` | +| Autocomplete active-frame redraw and cursor fallback rendering | `pkgs-ts/console/src/prompts/suggest/autocomplete-prompt.ts`, `pkgs-ts/console/src/prompts/suggest/read-autocomplete.ts`, `pkgs-ts/console/src/prompts/suggest/read-autocomplete/*`, `pkgs-ts/console/src/prompts/suggest/read-autocomplete/state/*`, `pkgs-ts/console/src/prompts/suggest/state/*`, `pkgs-ts/console/src/prompts/suggest/read-result.ts`, `pkgs-ts/console/src/prompts/suggest/render-autocomplete.ts`, `pkgs-ts/console/src/prompts/suggest/ghost-text.ts` | +| Search, multisearch | `pkgs-ts/console/src/prompts/search/*` | +| Search and multi-search label-first helper argument surface with info | `pkgs-ts/console/src/prompts/search/index.ts`, `pkgs-ts/console/tests/search.test.ts` | +| Search active boxed layout and row styling | `pkgs-ts/console/src/concerns/choice-label.ts`, `pkgs-ts/console/src/theme/choice-disabled.ts`, `pkgs-ts/console/src/theme/validators/disabled.ts`, `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/render-body.ts`, `pkgs-ts/console/src/prompts/search/body/*`, `pkgs-ts/console/tests/search.test.ts` | +| Search active-frame redraw and cursor rendering | `pkgs-ts/console/src/prompts/search/index.ts`, `pkgs-ts/console/src/prompts/search/search.ts`, `pkgs-ts/console/src/prompts/search/run.ts`, `pkgs-ts/console/src/prompts/search/keys.ts`, `pkgs-ts/console/src/prompts/search/keys/*`, `pkgs-ts/console/src/prompts/search/read-single.ts`, `pkgs-ts/console/src/prompts/search/read-single/*`, `pkgs-ts/console/src/prompts/search/read-single/interactive/*`, `pkgs-ts/console/src/prompts/search/read-single/session/*`, `pkgs-ts/console/src/prompts/search/render.ts` | +| Search retry initial highlight lifecycle | `pkgs-ts/console/src/prompts/search/read-single.ts`, `pkgs-ts/console/src/prompts/search/read-single/*`, `pkgs-ts/console/src/prompts/search/read-single/state/*`, `pkgs-ts/console/src/prompts/search/navigation.ts` | +| Search and multisearch empty-result rendering | `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/render-body.ts`, `pkgs-ts/console/src/prompts/search/body/*`, `pkgs-ts/console/tests/search.test.ts` | +| Search highlighted-result row styling | `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/render-body.ts`, `pkgs-ts/console/src/prompts/search/body/*`, `pkgs-ts/console/src/theme/styles.ts`, `pkgs-ts/console/tests/search.test.ts` | +| Search explicit-default lifecycle, invalid retry default preservation, source validation, overload validation, and transformed fallback value | `pkgs-ts/console/src/prompts/search/index.ts`, `pkgs-ts/console/src/prompts/search/search.ts`, `pkgs-ts/console/src/prompts/search/options.ts`, `pkgs-ts/console/src/prompts/search/run.ts`, `pkgs-ts/console/src/prompts/search/defaults.ts`, `pkgs-ts/console/src/prompts/search/read-single.ts`, `pkgs-ts/console/src/prompts/search/read-single/*`, `pkgs-ts/console/src/prompts/search/read-single/state/*`, `pkgs-ts/console/src/prompts/search/read-single/result.ts`, `pkgs-ts/console/src/prompts/search/line-mode.ts`, `pkgs-ts/console/src/prompts/search/validators/overload.ts`, `pkgs-ts/console/src/prompts/search/validators/source.ts`, `pkgs-ts/console/src/concerns/choices.ts`, `pkgs-ts/console/src/concerns/choice-match.ts`, `pkgs-ts/console/src/validators/default.ts` | +| Search submitted final frame | `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/read-single.ts`, `pkgs-ts/console/src/prompts/search/read-single/*`, `pkgs-ts/console/src/prompts/search/read-single/interactive/*`, `pkgs-ts/console/tests/search.test.ts` | +| Search submitted frame renders only after validation passes | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/search/index.ts`, `pkgs-ts/console/src/prompts/search/search.ts`, `pkgs-ts/console/src/prompts/search/run.ts`, `pkgs-ts/console/src/prompts/search/read-single.ts`, `pkgs-ts/console/src/prompts/search/read-single/*`, `pkgs-ts/console/src/prompts/search/read-single/interactive/*`, `pkgs-ts/console/src/prompts/search/read-single/result.ts`, `pkgs-ts/console/tests/search.test.ts` | +| Search cancel final frame | `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/read-single.ts`, `pkgs-ts/console/src/prompts/search/read-single/interactive/*`, `pkgs-ts/console/tests/search.test.ts` | +| Multi-search active boxed layout and selected-count footer | `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/render-body.ts`, `pkgs-ts/console/src/prompts/search/body/*`, `pkgs-ts/console/src/prompts/search/read-multi/state/*`, `pkgs-ts/console/tests/search.test.ts` | +| Multi-search transformed fallback value and invalid retry default preservation | `pkgs-ts/console/src/prompts/search/index.ts`, `pkgs-ts/console/src/prompts/search/multisearch.ts`, `pkgs-ts/console/src/prompts/search/multi-options.ts`, `pkgs-ts/console/src/prompts/search/multi-run.ts`, `pkgs-ts/console/src/prompts/search/defaults.ts`, `pkgs-ts/console/src/prompts/search/validators/overload.ts` | +| Multi-search submitted final frame | `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/multi-run.ts`, `pkgs-ts/console/src/prompts/search/read-multi.ts`, `pkgs-ts/console/src/prompts/search/read-multi/*`, `pkgs-ts/console/src/prompts/search/read-multi/state/*`, `pkgs-ts/console/tests/search.test.ts` | +| Multi-search empty submitted final frame | `pkgs-ts/console/src/prompts/search/render.ts` | +| Multi-search submitted frame renders only after validation passes | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/prompts/search/index.ts`, `pkgs-ts/console/src/prompts/search/multisearch.ts`, `pkgs-ts/console/src/prompts/search/multi-run.ts`, `pkgs-ts/console/src/prompts/search/read-multi.ts`, `pkgs-ts/console/src/prompts/search/read-multi/*`, `pkgs-ts/console/src/prompts/search/read-multi/state/*`, `pkgs-ts/console/src/prompts/search/read-multi/result.ts`, `pkgs-ts/console/tests/search.test.ts` | +| Multi-search active-frame redraw and cursor rendering | `pkgs-ts/console/src/prompts/search/index.ts`, `pkgs-ts/console/src/prompts/search/multisearch.ts`, `pkgs-ts/console/src/prompts/search/multi-run.ts`, `pkgs-ts/console/src/prompts/search/keys.ts`, `pkgs-ts/console/src/prompts/search/keys/*`, `pkgs-ts/console/src/prompts/search/read-multi.ts`, `pkgs-ts/console/src/prompts/search/read-multi/*`, `pkgs-ts/console/src/prompts/search/read-multi/state/*`, `pkgs-ts/console/src/prompts/search/render.ts` | +| Multi-search cancel final frame | `pkgs-ts/console/src/prompts/search/render.ts`, `pkgs-ts/console/src/prompts/search/read-multi.ts`, `pkgs-ts/console/src/prompts/search/read-multi/*`, `pkgs-ts/console/src/prompts/search/read-multi/state/*`, `pkgs-ts/console/tests/search.test.ts` | +| Pause | `pkgs-ts/console/src/prompts/pause.ts`, `pkgs-ts/console/src/prompts/pause/*` | +| Pause themed key-driven frame | `pkgs-ts/console/src/prompts/pause.ts`, `pkgs-ts/console/src/prompts/pause/read.ts`, `pkgs-ts/console/src/prompts/pause/render.ts`, `pkgs-ts/console/tests/pause.test.ts` | +| Pause non-interactive no-render behavior | `pkgs-ts/console/src/prompts/pause.ts`, `pkgs-ts/console/src/prompts/pause/read.ts`, `pkgs-ts/console/tests/pause.test.ts` | +| Choice normalization, matching, navigation, and list rendering concerns | `pkgs-ts/console/src/concerns/choices.ts`, `pkgs-ts/console/src/concerns/choice-normalize.ts`, `pkgs-ts/console/src/concerns/choice-match.ts`, `pkgs-ts/console/src/concerns/choice-navigation.ts`, `pkgs-ts/console/src/concerns/choice-render.ts` | +| Choice and search scrollbar rendering | `pkgs-ts/console/src/concerns/scrollbar.ts`, `pkgs-ts/console/src/concerns/choice-navigation.ts`, `pkgs-ts/console/src/concerns/choice-render.ts`, `pkgs-ts/console/src/prompts/search/render.ts` | +| Form builder | `pkgs-ts/console/src/form.ts`, `pkgs-ts/console/src/form/builder/*`, `pkgs-ts/console/src/form/builder/responses.ts` | +| Form builder nested prompt revert short-circuiting | `pkgs-ts/console/src/form/builder/revert.ts`, `pkgs-ts/console/src/form/builder/submit.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder first-step and conditional revert feature coverage | `pkgs-ts/console/src/form/builder/conditions.ts`, `pkgs-ts/console/src/form/builder/submit.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder asynchronous condition lifecycle | `pkgs-ts/console/src/form/builder/conditions.ts`, `pkgs-ts/console/src/form/builder/submit.ts`, `pkgs-ts/console/src/form/types.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder side-effect step surface and revert skipping | `pkgs-ts/console/src/form/builder/index.ts`, `pkgs-ts/console/src/form/builder/methods.ts`, `pkgs-ts/console/src/form/builder/step.ts`, `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/status.ts` | +| Notes and alert-style output | `pkgs-ts/console/src/output/notes.ts`, `pkgs-ts/console/src/output/notes/*` | +| Note multiline and typed theme rendering | `pkgs-ts/console/src/output/notes.ts`, `pkgs-ts/console/src/output/notes/render.ts`, `pkgs-ts/console/src/theme/styles.ts`, `pkgs-ts/console/tests/output.test.ts` | +| Note intro/outro visible-width padding | `pkgs-ts/console/src/output/notes.ts`, `pkgs-ts/console/src/output/notes/render.ts`, `pkgs-ts/console/tests/output.test.ts` | +| Native notifications | `pkgs-ts/console/src/output/notify.ts` | +| Notification command construction, executable discovery, and process result reporting | `pkgs-ts/console/src/output/notify.ts`, `pkgs-ts/console/src/output/notify/*` | +| Tables, data tables, and grids | `pkgs-ts/console/src/output/table.ts`, `pkgs-ts/console/src/output/table-output.ts`, `pkgs-ts/console/src/output/grid-output.ts`, `pkgs-ts/console/src/output/data-table.ts` | +| Data table label-first helper argument surface | `pkgs-ts/console/src/output/data-table.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table transform callback lifecycle | `pkgs-ts/console/src/contracts/output.ts`, `pkgs-ts/console/src/output/data-table.ts`, `pkgs-ts/console/src/output/data-table/run.ts`, `pkgs-ts/console/src/output/data-table/options.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table interactive default selection | `pkgs-ts/console/src/output/data-table/read.ts`, `pkgs-ts/console/src/output/data-table/reader/result.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table exhausted-input default selection | `pkgs-ts/console/src/output/data-table/read.ts`, `pkgs-ts/console/src/output/data-table/reader/result.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table line-input fallback filtering | `pkgs-ts/console/src/output/data-table/read.ts`, `pkgs-ts/console/src/output/data-table/reader/fallback.ts`, `pkgs-ts/console/src/prompt/ask.ts` | +| Data table no-results search rendering | `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/tests/table.test.ts` | +| Data table viewing-info rendering | `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/tests/table.test.ts` | +| Data table submitted and cancelled final frames | `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/src/output/data-table/read.ts`, `pkgs-ts/console/src/output/data-table/reader/interactive.ts`, `pkgs-ts/console/src/output/data-table/reader/cancel.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table submitted frame renders only after validation passes | `pkgs-ts/console/src/prompt/submission.ts`, `pkgs-ts/console/src/output/data-table.ts`, `pkgs-ts/console/src/output/data-table/run.ts`, `pkgs-ts/console/src/output/data-table/read.ts`, `pkgs-ts/console/src/output/data-table/reader/interactive.ts`, `pkgs-ts/console/src/output/data-table/reader/result.ts`, `pkgs-ts/console/src/output/data-table/types.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table active-frame redraw and cursor-aware search rendering | `pkgs-ts/console/src/output/data-table.ts`, `pkgs-ts/console/src/output/data-table/run.ts`, `pkgs-ts/console/src/output/data-table/read.ts`, `pkgs-ts/console/src/output/data-table/reader/interactive.ts`, `pkgs-ts/console/src/output/data-table/reader/session.ts`, `pkgs-ts/console/src/output/data-table/reader/session/*`, `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/types.ts` | +| Data table explicit-default lifecycle, invalid retry default preservation, and transformed fallback value | `pkgs-ts/console/src/output/data-table.ts`, `pkgs-ts/console/src/output/data-table/options.ts`, `pkgs-ts/console/src/output/data-table/read.ts`, `pkgs-ts/console/src/output/data-table/reader/result.ts`, `pkgs-ts/console/src/validators/default.ts` | +| Data table themed cancellation warning | `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/src/output/data-table/reader/cancel.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table multiline cell rendering | `pkgs-ts/console/src/output/data-table/multiline.ts`, `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/tests/table.test.ts` | +| Data table scrollbar rendering | `pkgs-ts/console/src/output/data-table/scrollbar.ts`, `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/tests/table.test.ts` | +| Data table no-header and blank-cell rendering | `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/src/output/data-table/rows.ts`, `pkgs-ts/console/src/output/data-table/rows/*`, `pkgs-ts/console/tests/table.test.ts` | +| Data table row-shape validation and normalization | `pkgs-ts/console/src/output/validators/cells.ts`, `pkgs-ts/console/src/output/validators/data-table.ts`, `pkgs-ts/console/src/output/data-table/rows.ts`, `pkgs-ts/console/src/output/data-table/rows/*`, `pkgs-ts/console/tests/table.test.ts` | +| Static table row-shape validation and header inference | `pkgs-ts/console/src/output/validators/cells.ts`, `pkgs-ts/console/src/output/validators/table.ts`, `pkgs-ts/console/src/output/validators/table/*`, `pkgs-ts/console/tests/table.test.ts` | +| Data table fixed visual height | `pkgs-ts/console/src/output/data-table/visual-window.ts`, `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/tests/table.test.ts` | +| Data table comfortable width and outlier truncation | `pkgs-ts/console/src/output/data-table/widths.ts`, `pkgs-ts/console/src/output/data-table/widths/*`, `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/render-body.ts`, `pkgs-ts/console/src/output/data-table/body/*`, `pkgs-ts/console/tests/table.test.ts` | +| Boxed balanced grid rendering | `pkgs-ts/console/src/output/grid.ts`, `pkgs-ts/console/src/output/grid/*`, `pkgs-ts/console/tests/output.test.ts` | +| Terminal title and clear output | `pkgs-ts/console/src/output/terminal.ts` | +| Spinner, progress, task, stream | `pkgs-ts/console/src/status/*`, `pkgs-ts/console/src/status.ts` | +| Form builder label-first search and multisearch methods | `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder label-first choice and search info rendering | `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder previous-response defaults | `pkgs-ts/console/src/form/builder/previous.ts`, `pkgs-ts/console/src/form/builder/validators/previous.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder basic prompt object-option method surface with validator-backed names | `pkgs-ts/console/src/form/builder/prompts/basic.ts`, `pkgs-ts/console/src/form/builder/prompts/basic/*`, `pkgs-ts/console/src/form/builder/prompts/contracts/basic.ts`, `pkgs-ts/console/src/form/builder/prompts/validators/basic.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder choice prompt object-option method surface with validator-backed overload parsing | `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/validators/select.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder suggest and autocomplete placeholder/default arguments | `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder suggest and autocomplete object-option method surface with validator-backed overload parsing | `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/validators/suggest.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder suggest and autocomplete label-first info rendering | `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder number transform argument surface | `pkgs-ts/console/src/form/builder/prompts/basic.ts`, `pkgs-ts/console/src/form/builder/prompts/basic/*`, `pkgs-ts/console/src/form/builder/prompts/basic/number/*`, `pkgs-ts/console/src/form/builder/prompts/contracts/basic.ts`, `pkgs-ts/console/src/prompts/number.ts`, `pkgs-ts/console/src/prompts/number/defaults.ts`, `pkgs-ts/console/tests/form.test.ts`, `pkgs-ts/console/tests/number.test.ts` | +| Form builder password previous-response defaults | `pkgs-ts/console/src/form/builder/prompts/basic.ts`, `pkgs-ts/console/src/form/builder/prompts/basic/*`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder search and multisearch previous-response defaults | `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder named prompt defaults after skipped conditional responses | `pkgs-ts/console/src/form/builder/previous.ts`, `pkgs-ts/console/src/form/builder/prompts/choices.ts`, `pkgs-ts/console/src/form/builder/prompts/choice/*`, `pkgs-ts/console/src/form/builder/validators/previous.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder label-first data table method surface | `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/output/*`, `pkgs-ts/console/src/form/builder/output/contracts.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder label-first data table previous-response defaults | `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/output/*`, `pkgs-ts/console/src/form/builder/output/contracts.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder interactive data table object-option method surface | `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/output/*`, `pkgs-ts/console/src/form/builder/output/contracts.ts`, `pkgs-ts/console/src/output/validators/data-table.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder output overload and row validator layer | `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/output/*`, `pkgs-ts/console/src/form/builder/output/contracts.ts`, `pkgs-ts/console/src/form/builder/validators/output.ts` | +| Form builder object-option table output method surface | `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/output/*`, `pkgs-ts/console/src/form/builder/output/contracts.ts`, `pkgs-ts/console/src/output/validators/table.ts`, `pkgs-ts/console/src/output/validators/table/*`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder output method surface for grid, display data table, terminal helpers, and notifications | `pkgs-ts/console/src/form/builder/index.ts`, `pkgs-ts/console/src/form/builder/methods.ts`, `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/output/*`, `pkgs-ts/console/tests/form.test.ts` | +| Display-only output helper return values and form responses | `pkgs-ts/console/src/output/notes.ts`, `pkgs-ts/console/src/output/table.ts`, `pkgs-ts/console/src/form/builder/output.ts`, `pkgs-ts/console/src/form/builder/output/*`, `pkgs-ts/console/tests/output.test.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Progress boxed frame rendering, clamped fill rendering, and formatted fractions | `pkgs-ts/console/src/status/progress/render.ts`, `pkgs-ts/console/src/status/progress/state/*`, `pkgs-ts/console/src/theme/box.ts` | +| Spinner static and deterministic animated frame rendering | `pkgs-ts/console/src/status/spinner.ts`, `pkgs-ts/console/src/status/spinner/lifecycle.ts`, `pkgs-ts/console/src/status/spinner/render.ts` | +| Spinner empty default message | `pkgs-ts/console/src/status/spinner.ts`, `pkgs-ts/console/src/status/spinner/options.ts`, `pkgs-ts/console/src/status/spinner/validators/*`, `pkgs-ts/console/src/form/builder/status.ts`, `pkgs-ts/console/src/form/builder/status/*`, `pkgs-ts/console/tests/spinner.test.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Task static and deterministic animated frame rendering, active redraw, bounded logs, and stable summary symbols | `pkgs-ts/console/src/status/task.ts`, `pkgs-ts/console/src/status/task/definition.ts`, `pkgs-ts/console/src/status/task/validators/*`, `pkgs-ts/console/src/status/task/lifecycle.ts`, `pkgs-ts/console/src/status/task/lifecycle/*`, `pkgs-ts/console/src/status/task/frame.ts`, `pkgs-ts/console/src/status/task/*` | +| Task non-positive log limit defaulting | `pkgs-ts/console/src/status/validators/limit.ts`, `pkgs-ts/console/src/status/task/logger.ts`, `pkgs-ts/console/src/status/task/logger/*`, `pkgs-ts/console/tests/task.test.ts` | +| Form builder root-aligned spinner and task overloads with validator-backed parsing | `pkgs-ts/console/src/form/builder/status.ts`, `pkgs-ts/console/src/form/builder/status/*`, `pkgs-ts/console/src/form/builder/validators/status.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Form builder root-aligned manual progress side-effect lifecycle and validator-backed overloads | `pkgs-ts/console/src/form/builder/status.ts`, `pkgs-ts/console/src/form/builder/status/*`, `pkgs-ts/console/src/form/builder/validators/status.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Task process output capture, writer validation, and restore-before-flush lifecycle | `pkgs-ts/console/src/status/task/process-output.ts`, `pkgs-ts/console/src/status/task/process-output/*`, `pkgs-ts/console/tests/task.test.ts` | +| Stream frame rendering, active redraw, wrapping, fade styles, chunk validation, lifecycle cleanup, burst coalescing, and close flushing | `pkgs-ts/console/src/status/stream.ts`, `pkgs-ts/console/src/status/stream/output.ts`, `pkgs-ts/console/src/status/stream/output/*`, `pkgs-ts/console/src/status/stream/lifecycle.ts`, `pkgs-ts/console/src/status/stream/renderer.ts`, `pkgs-ts/console/src/status/stream/scheduler.ts`, `pkgs-ts/console/src/status/stream/validators/*`, `pkgs-ts/console/src/status/stream/*` | +| Form builder root-aligned manual stream named-response overload | `pkgs-ts/console/src/form/builder/status.ts`, `pkgs-ts/console/src/form/builder/status/*`, `pkgs-ts/console/src/form/builder/validators/status.ts`, `pkgs-ts/console/src/validators/iterable.ts`, `pkgs-ts/console/tests/form.test.ts` | +| Status cursor visibility cleanup | `pkgs-ts/console/src/status/spinner.ts`, `pkgs-ts/console/src/status/stream.ts`, `pkgs-ts/console/src/status/task.ts` | +| Status signal cleanup for cursor and rendered-frame restoration | `pkgs-ts/console/src/status/signals.ts`, `pkgs-ts/console/src/status/spinner.ts`, `pkgs-ts/console/src/status/stream.ts`, `pkgs-ts/console/src/status/task.ts` | +| Status rendered-frame cleanup | `pkgs-ts/console/src/status/frame.ts`, `pkgs-ts/console/src/status/spinner.ts`, `pkgs-ts/console/src/status/task.ts` | +| Progress cursor visibility and rendered-frame redraw cleanup | `pkgs-ts/console/src/status/progress/progress.ts`, `pkgs-ts/console/src/status/progress/controller.ts`, `pkgs-ts/console/src/status/progress/renderer.ts`, `pkgs-ts/console/src/status/progress/state.ts`, `pkgs-ts/console/src/status/progress/state/*`, `pkgs-ts/console/src/status/progress/terminal.ts`, `pkgs-ts/console/src/status/frame.ts` | +| Progress signal cleanup | `pkgs-ts/console/src/status/progress/progress.ts`, `pkgs-ts/console/src/status/progress/terminal.ts`, `pkgs-ts/console/src/status/progress/terminal/*`, `pkgs-ts/console/tests/progress.test.ts` | +| Progress prompt-disable and manual advance semantics | `pkgs-ts/console/src/status/progress.ts`, `pkgs-ts/console/src/status/progress/progress.ts`, `pkgs-ts/console/src/status/progress/prompt.ts`, `pkgs-ts/console/src/status/progress/controller.ts`, `pkgs-ts/console/src/status/progress/validators/*`, `pkgs-ts/console/src/validators/iterable.ts` | +| Progress integer step parsing and clamped manual advance range | `pkgs-ts/console/src/status/progress.ts`, `pkgs-ts/console/src/status/progress/progress.ts`, `pkgs-ts/console/src/status/progress/state.ts`, `pkgs-ts/console/src/status/progress/state/*`, `pkgs-ts/console/src/status/progress/validators/*`, `pkgs-ts/console/src/status/validators/progress.ts` | +| Terminal clear/title, cursor visibility, true-color detection, default colors, and raw input restoration | `pkgs-ts/console/src/terminal.ts`, `pkgs-ts/console/src/terminal/*`, `pkgs-ts/console/src/environment/raw-key.ts`, `pkgs-ts/console/src/environment/raw-key/mode.ts`, `pkgs-ts/console/src/environment/raw-key/types.ts` | +| Terminal clear/title and notification helper return values | `pkgs-ts/console/src/output/terminal.ts`, `pkgs-ts/console/src/output/notify.ts`, `pkgs-ts/console/tests/terminal.test.ts`, `pkgs-ts/console/tests/notify.test.ts` | +| Terminal raw key alias normalization | `pkgs-ts/console/src/environment/raw-key/normalize.ts`, `pkgs-ts/console/tests/environment.test.ts` | +| Terminal split escape-sequence buffering | `pkgs-ts/console/src/environment/raw-key.ts`, `pkgs-ts/console/src/environment/raw-key/session.ts`, `pkgs-ts/console/src/environment/raw-key/normalize.ts`, `pkgs-ts/console/tests/environment.test.ts` | +| Red, strikethrough, and border-styled frames | `pkgs-ts/console/src/theme/styles.ts`, `pkgs-ts/console/src/theme/box.ts` | +| Default box renderer terminal-width cap | `pkgs-ts/console/src/theme/box.ts` | +| ANSI segment parsing, ANSI-aware wrapping, truncation, Unicode width | `pkgs-ts/console/src/strings.ts`, `pkgs-ts/console/src/string-utils/*`, `pkgs-ts/console/src/string-utils/ansi/*`, `pkgs-ts/console/tests/strings.test.ts` | +| ANSI truncation style cleanup and visible-width markers | `pkgs-ts/console/src/string-utils/truncate.ts`, `pkgs-ts/console/src/string-utils/width.ts`, `pkgs-ts/console/tests/strings.test.ts` | +| Key-mode search default submission | `pkgs-ts/console/src/prompts/search/read-single.ts`, `pkgs-ts/console/src/prompts/search/read-single/state/*`, `pkgs-ts/console/src/prompts/search/read-single/result.ts`, `pkgs-ts/console/tests/search.test.ts` | +| OpenTUI adapter | `pkgs-ts/console/src/opentui.ts` | +| Type contracts | `pkgs-ts/console/src/types.ts`, `pkgs-ts/console/src/contracts/*` | +| Public ESM package runtime, type-consumption surface, and domain subpath exports | `pkgs-ts/console/package.json`, `pkgs-ts/console/src/index.ts`, `pkgs-ts/console/src/prompts.ts`, `pkgs-ts/console/src/prompts/*`, `pkgs-ts/console/src/form/builder/index.ts`, `pkgs-ts/console/src/output.ts`, `pkgs-ts/console/src/output/*`, `pkgs-ts/console/src/status.ts`, `pkgs-ts/console/src/status/*`, `pkgs-ts/console/src/output/notify.ts`, `pkgs-ts/console/src/output/notify/*`, `pkgs-ts/tests/tests/package.test.ts` | | Infra workspace and tool cache isolation | `infra`, `infra/.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/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/*` | +| Data table prompt argument validation layer | `pkgs-ts/console/src/output/validators/data-table.ts`, `pkgs-ts/console/src/output/data-table.ts`, `pkgs-ts/console/src/output/data-table/reader/types.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Data table filter callback lifecycle | `pkgs-ts/console/src/contracts/output.ts`, `pkgs-ts/console/src/output/data-table/rows.ts`, `pkgs-ts/console/src/output/data-table/rows/*`, `pkgs-ts/console/src/output/data-table/reader/state.ts`, `pkgs-ts/console/src/output/data-table/reader/state/*`, `pkgs-ts/console/src/output/data-table.ts` | +| Data table search title and non-empty query filter lifecycle | `pkgs-ts/console/src/output/data-table/render.ts`, `pkgs-ts/console/src/output/data-table/rows.ts`, `pkgs-ts/console/src/output/data-table/rows/*`, `pkgs-ts/console/src/output/data-table/reader/state.ts`, `pkgs-ts/console/src/output/data-table/reader/state/*`, `pkgs-ts/console/src/output/data-table/reader/session.ts`, `pkgs-ts/console/src/output/data-table/reader/session/*`, `pkgs-ts/console/tests/form.test.ts` | +| Table row cell normalization validation layer | `pkgs-ts/console/src/output/validators/table.ts`, `pkgs-ts/console/src/output/validators/table/*`, `pkgs-ts/console/src/output/table.ts`, `pkgs-ts/console/tests/table.test.ts` | +| Choice option shape validation layer | `pkgs-ts/console/src/concerns/validators/choice.ts`, `pkgs-ts/console/src/concerns/choice-normalize.ts`, `pkgs-ts/console/src/concerns/choices.ts`, `pkgs-ts/console/tests/choices.test.ts` | +| Required value and message validation layer | `pkgs-ts/console/src/validators/required.ts`, `pkgs-ts/console/tests/prompt.test.ts` | +| Keyboard event normalization and key aliases | `pkgs-ts/console/src/key/event.ts`, `pkgs-ts/console/src/key/event/*`, `pkgs-ts/console/tests/key.test.ts` | +| Key match validation layer | `pkgs-ts/console/src/key/validators/match.ts`, `pkgs-ts/console/src/key/match.ts`, `pkgs-ts/console/tests/key.test.ts` | +| Form builder number empty-default lifecycle | `pkgs-ts/console/src/form/builder/prompts/basic.ts`, `pkgs-ts/console/src/form/builder/prompts/basic/*`, `pkgs-ts/console/src/form/builder/prompts/basic/number/*`, `pkgs-ts/console/tests/form.test.ts` | +| Prompt fallback and global validation lifecycle hooks | `pkgs-ts/console/src/prompt/fallback.ts`, `pkgs-ts/console/src/prompt/validate-using.ts`, `pkgs-ts/console/src/prompt/lifecycle.ts`, `pkgs-ts/console/src/prompts/*`, `pkgs-ts/console/src/output/data-table.ts` | +| Pipe-style default table rendering | `pkgs-ts/console/src/theme.ts`, `pkgs-ts/console/src/theme/*`, `pkgs-ts/console/src/output/table.ts`, `pkgs-ts/console/src/output/data-table/render.ts` | +| Default theme symbol, prompt, validation, choice, and table rendering concerns | `pkgs-ts/console/src/theme.ts`, `pkgs-ts/console/src/theme/*` | ## Completion Audit Current implementation evidence: -- Public runtime helpers are exported from `packages/tui/src/index.ts` and - verified by `packages/acceptance/tests/package.test.ts`. +- Public runtime helpers are exported from `pkgs-ts/console/src/index.ts` and + verified by `pkgs-ts/tests/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`. + `pkgs-ts/console/tests` and `pkgs-ts/tests/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/*` + `pkgs-ts/console/src/form/builder/*` with validator layers under + `pkgs-ts/console/src/form/builder/**/validators/*`. +- Prompt implementations are split by concern under `pkgs-ts/console/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 +- The package is ESM-only through `pkgs-ts/console/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. diff --git a/packages/docs/components.json b/apps/docs/components.json similarity index 100% rename from packages/docs/components.json rename to apps/docs/components.json diff --git a/packages/docs/examples/basic-prompts.ts b/apps/docs/examples/basic-prompts.ts similarity index 93% rename from packages/docs/examples/basic-prompts.ts rename to apps/docs/examples/basic-prompts.ts index 9a659750..db046f80 100644 --- a/packages/docs/examples/basic-prompts.ts +++ b/apps/docs/examples/basic-prompts.ts @@ -1,4 +1,4 @@ -import { number, password, text, textarea } from '@ollin/tui'; +import { number, password, text, textarea } from '@ollin/console'; export async function basicPromptExamples(): Promise { const name = await text({ diff --git a/packages/docs/examples/choice-prompts.ts b/apps/docs/examples/choice-prompts.ts similarity index 98% rename from packages/docs/examples/choice-prompts.ts rename to apps/docs/examples/choice-prompts.ts index f8a01cec..790c0a7a 100644 --- a/packages/docs/examples/choice-prompts.ts +++ b/apps/docs/examples/choice-prompts.ts @@ -1,4 +1,4 @@ -import { autocomplete, confirm, multiselect, select, suggest } from '@ollin/tui'; +import { autocomplete, confirm, multiselect, select, suggest } from '@ollin/console'; const roles = { member: 'Member', diff --git a/packages/docs/examples/forms.ts b/apps/docs/examples/forms.ts similarity index 95% rename from packages/docs/examples/forms.ts rename to apps/docs/examples/forms.ts index fb0ecab4..f3c0f692 100644 --- a/packages/docs/examples/forms.ts +++ b/apps/docs/examples/forms.ts @@ -1,4 +1,4 @@ -import { form } from '@ollin/tui'; +import { form } from '@ollin/console'; export async function formExample(): Promise { const responses = await form() diff --git a/packages/docs/examples/output.ts b/apps/docs/examples/output.ts similarity index 92% rename from packages/docs/examples/output.ts rename to apps/docs/examples/output.ts index d1421886..b5b39abe 100644 --- a/packages/docs/examples/output.ts +++ b/apps/docs/examples/output.ts @@ -1,4 +1,4 @@ -import { alert, clear, dataTable, error, grid, info, intro, note, outro, table, title, warning } from '@ollin/tui'; +import { alert, clear, dataTable, error, grid, info, intro, note, outro, table, title, warning } from '@ollin/console'; export function outputExamples(): void { intro('Deployment'); diff --git a/packages/docs/examples/search-prompts.ts b/apps/docs/examples/search-prompts.ts similarity index 93% rename from packages/docs/examples/search-prompts.ts rename to apps/docs/examples/search-prompts.ts index bcdc20de..6efee0cc 100644 --- a/packages/docs/examples/search-prompts.ts +++ b/apps/docs/examples/search-prompts.ts @@ -1,4 +1,4 @@ -import { multisearch, search } from '@ollin/tui'; +import { multisearch, search } from '@ollin/console'; const users = new Map([ [1, 'Lin Chen'], diff --git a/packages/docs/examples/status.ts b/apps/docs/examples/status.ts similarity index 90% rename from packages/docs/examples/status.ts rename to apps/docs/examples/status.ts index 4b49da2a..d33e4ade 100644 --- a/packages/docs/examples/status.ts +++ b/apps/docs/examples/status.ts @@ -1,4 +1,4 @@ -import { progress, spin, stream, task } from '@ollin/tui'; +import { progress, spin, stream, task } from '@ollin/console'; export async function statusExamples(): Promise { await spin('Installing dependencies', async () => 'installed'); diff --git a/packages/docs/examples/testing.ts b/apps/docs/examples/testing.ts similarity index 89% rename from packages/docs/examples/testing.ts rename to apps/docs/examples/testing.ts index 9c1fb8c4..18554629 100644 --- a/packages/docs/examples/testing.ts +++ b/apps/docs/examples/testing.ts @@ -1,4 +1,4 @@ -import { Key, createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/tui'; +import { Key, createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/console'; export async function testingExample(): Promise { const output = createMemoryOutput(); diff --git a/packages/docs/package.json b/apps/docs/package.json similarity index 96% rename from packages/docs/package.json rename to apps/docs/package.json index b449467d..d7d8ed50 100644 --- a/packages/docs/package.json +++ b/apps/docs/package.json @@ -14,13 +14,13 @@ "dependencies": { "@fontsource/geist-mono": "^5.2.8", "@fontsource/geist-sans": "^5.2.5", - "@ollin/tui": "workspace:*", + "@ollin/console": "workspace:*", "@vueuse/core": "^14.3.0", "@xterm/xterm": "^6.0.0", "reka-ui": "^2.9.10" }, "devDependencies": { - "@ollin/infra": "workspace:*", + "@ollin/console-infra": "workspace:*", "@tailwindcss/vite": "^4.3.0", "@types/node": "^25.6.2", "class-variance-authority": "^0.7.1", diff --git a/packages/docs/src/guide/autocomplete.md b/apps/docs/src/guide/autocomplete.md similarity index 88% rename from packages/docs/src/guide/autocomplete.md rename to apps/docs/src/guide/autocomplete.md index 54b475df..dfeee18a 100644 --- a/packages/docs/src/guide/autocomplete.md +++ b/apps/docs/src/guide/autocomplete.md @@ -3,7 +3,7 @@ The `autocomplete` helper completes the current input from known options. ```ts -import { autocomplete } from '@ollin/tui'; +import { autocomplete } from '@ollin/console'; const runtime = await autocomplete({ message: 'Runtime', @@ -19,7 +19,7 @@ Use `suggest` instead when arbitrary values are common and suggestions are only ## Complete Usage ```ts -import { autocomplete } from '@ollin/tui'; +import { autocomplete } from '@ollin/console'; const runtime = await autocomplete({ message: 'Runtime', @@ -39,7 +39,7 @@ void [runtime, packageManager]; ## Consumer Call And Output ```ts -import { autocomplete } from '@ollin/tui'; +import { autocomplete } from '@ollin/console'; const runtime = await autocomplete({ message: 'Runtime', diff --git a/packages/docs/src/guide/available-prompts.md b/apps/docs/src/guide/available-prompts.md similarity index 92% rename from packages/docs/src/guide/available-prompts.md rename to apps/docs/src/guide/available-prompts.md index 5929217b..3ebb6b57 100644 --- a/packages/docs/src/guide/available-prompts.md +++ b/apps/docs/src/guide/available-prompts.md @@ -1,6 +1,6 @@ # Available Prompts -`@ollin/tui` provides prompt helpers for text input, choice selection, search flows, confirmation, pausing, and autocomplete. +`@ollin/console` provides prompt helpers for text input, choice selection, search flows, confirmation, pausing, and autocomplete. | Helper | Purpose | | --- | --- | @@ -22,7 +22,7 @@ Object options use `message` as the visible prompt text. Label-first overloads a ## Complete Prompt Tour ```ts -import { autocomplete, confirm, multiselect, multisearch, number, password, pause, search, select, suggest, text, textarea } from '@ollin/tui'; +import { autocomplete, confirm, multiselect, multisearch, number, password, pause, search, select, suggest, text, textarea } from '@ollin/console'; const name = await text({ message: 'Name', required: true }); const description = await textarea({ message: 'Description', rows: 4 }); @@ -44,7 +44,7 @@ void [name, description, copies, secret, accepted, role, permissions, author, ru ## Consumer Call And Output ```ts -import { confirm, select, text } from '@ollin/tui'; +import { confirm, select, text } from '@ollin/console'; const name = await text({ message: 'Name', required: true }); const template = await select({ message: 'Template', options: ['cli', 'library', 'docs'] }); diff --git a/packages/docs/src/guide/clearing-terminal.md b/apps/docs/src/guide/clearing-terminal.md similarity index 87% rename from packages/docs/src/guide/clearing-terminal.md rename to apps/docs/src/guide/clearing-terminal.md index 9ca67804..232442b6 100644 --- a/packages/docs/src/guide/clearing-terminal.md +++ b/apps/docs/src/guide/clearing-terminal.md @@ -3,7 +3,7 @@ Use `clear` to clear the configured prompt output. ```ts -import { clear } from '@ollin/tui'; +import { clear } from '@ollin/console'; clear(); ``` @@ -11,7 +11,7 @@ clear(); The package also exports lower-level helpers such as `clearTerminal`, `eraseLine`, and `erasePreviousLines` for direct terminal behaviour. ```ts -import { clearTerminal } from '@ollin/tui'; +import { clearTerminal } from '@ollin/console'; clearTerminal(); ``` @@ -23,7 +23,7 @@ Use `clear` sparingly for full-screen command flows where previous output would ## Complete Usage ```ts -import { clear, clearTerminal, eraseLine, erasePreviousLines, form } from '@ollin/tui'; +import { clear, clearTerminal, eraseLine, erasePreviousLines, form } from '@ollin/console'; clear(); clearTerminal(); @@ -42,7 +42,7 @@ void responses; ## Consumer Call And Output ```ts -import { clear, info } from '@ollin/tui'; +import { clear, info } from '@ollin/console'; clear(); info('Fresh screen ready.'); diff --git a/packages/docs/src/guide/confirm.md b/apps/docs/src/guide/confirm.md similarity index 88% rename from packages/docs/src/guide/confirm.md rename to apps/docs/src/guide/confirm.md index 1ecf8512..51f8723c 100644 --- a/packages/docs/src/guide/confirm.md +++ b/apps/docs/src/guide/confirm.md @@ -3,7 +3,7 @@ The `confirm` helper asks for a boolean response. ```ts -import { confirm } from '@ollin/tui'; +import { confirm } from '@ollin/console'; const accepted = await confirm({ message: 'Do you accept the terms?', @@ -19,7 +19,7 @@ const accepted = await confirm({ ## Complete Usage ```ts -import { confirm } from '@ollin/tui'; +import { confirm } from '@ollin/console'; const accepted = await confirm({ message: 'Do you accept the terms?', @@ -39,7 +39,7 @@ void [accepted, overwrite]; ## Consumer Call And Output ```ts -import { confirm } from '@ollin/tui'; +import { confirm } from '@ollin/console'; const publish = await confirm({ message: 'Publish release?', diff --git a/packages/docs/src/guide/fallbacks.md b/apps/docs/src/guide/fallbacks.md similarity index 85% rename from packages/docs/src/guide/fallbacks.md rename to apps/docs/src/guide/fallbacks.md index ff932c2e..b96fdb86 100644 --- a/packages/docs/src/guide/fallbacks.md +++ b/apps/docs/src/guide/fallbacks.md @@ -1,11 +1,11 @@ # Custom Environments -`@ollin/tui` uses `PromptEnvironment` as the boundary for input, output, and interactivity. +`@ollin/console` uses `PromptEnvironment` as the boundary for input, output, and interactivity. Use `withPromptEnvironment` when a command needs custom streams or deterministic input. ```ts -import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/tui'; +import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/console'; const output = createMemoryOutput(); const input = createScriptedInput(['Ada']); @@ -23,7 +23,7 @@ Keep environment-specific behaviour near the command entrypoint so prompt code c ## Complete Usage ```ts -import { createMemoryOutput, createScriptedInput, select, text, withPromptEnvironment } from '@ollin/tui'; +import { createMemoryOutput, createScriptedInput, select, text, withPromptEnvironment } from '@ollin/console'; const output = createMemoryOutput(); const input = createScriptedInput(['Ada', 'Member']); @@ -50,7 +50,7 @@ void [result, output.text()]; ## Consumer Call And Output ```ts -import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/tui'; +import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/console'; const output = createMemoryOutput(); const input = createScriptedInput(['Ada']); diff --git a/packages/docs/src/guide/forms.md b/apps/docs/src/guide/forms.md similarity index 92% rename from packages/docs/src/guide/forms.md rename to apps/docs/src/guide/forms.md index 174dbc6e..9a4cec15 100644 --- a/packages/docs/src/guide/forms.md +++ b/apps/docs/src/guide/forms.md @@ -3,7 +3,7 @@ The `form` helper composes prompt, output, and status steps into one submission flow. ```ts -import { form } from '@ollin/tui'; +import { form } from '@ollin/console'; const responses = await form() .intro('Create an account') @@ -16,7 +16,7 @@ const responses = await form() Named steps are written into the response object. The builder also supports conditional steps with `addIf`. ```ts -import { form } from '@ollin/tui'; +import { form } from '@ollin/console'; await form() .confirm({ message: 'Enable notifications?', default: true }, 'notifications') @@ -33,7 +33,7 @@ You can also pass an async callback to `form` and submit from inside the callbac ## Complete Usage ```ts -import { form } from '@ollin/tui'; +import { form } from '@ollin/console'; const responses = await form(async (builder) => builder @@ -72,7 +72,7 @@ void responses; ## Consumer Call And Output ```ts -import { form } from '@ollin/tui'; +import { form } from '@ollin/console'; const responses = await form() .text({ message: 'Project name', required: true }, 'project') diff --git a/packages/docs/src/guide/informational-messages.md b/apps/docs/src/guide/informational-messages.md similarity index 92% rename from packages/docs/src/guide/informational-messages.md rename to apps/docs/src/guide/informational-messages.md index 3e73bf2d..0d3ee68d 100644 --- a/packages/docs/src/guide/informational-messages.md +++ b/apps/docs/src/guide/informational-messages.md @@ -3,7 +3,7 @@ Use informational helpers for durable terminal messages that are not prompts. ```ts -import { alert, error, info, intro, note, outro, warning } from '@ollin/tui'; +import { alert, error, info, intro, note, outro, warning } from '@ollin/console'; intro('Deployment'); info('Preparing release artefacts.'); @@ -19,7 +19,7 @@ These helpers write to the configured prompt output. In tests, configure a memor ## Complete Usage ```ts -import { alert, error, form, info, intro, note, outro, warning } from '@ollin/tui'; +import { alert, error, form, info, intro, note, outro, warning } from '@ollin/console'; intro('Deployment'); info('Preparing release artefacts.'); @@ -39,7 +39,7 @@ await form() ## Consumer Call And Output ```ts -import { info, intro, outro, warning } from '@ollin/tui'; +import { info, intro, outro, warning } from '@ollin/console'; intro('Release'); info('Preparing release artefacts.'); diff --git a/packages/docs/src/guide/installation.md b/apps/docs/src/guide/installation.md similarity index 83% rename from packages/docs/src/guide/installation.md rename to apps/docs/src/guide/installation.md index 664f391f..cf7a1404 100644 --- a/packages/docs/src/guide/installation.md +++ b/apps/docs/src/guide/installation.md @@ -1,15 +1,15 @@ # Installation -Install the package from the workspace or package registry that contains `@ollin/tui`. +Install the package from the workspace or package registry that contains `@ollin/console`. ```sh -pnpm add @ollin/tui +pnpm add @ollin/console ``` Then import helpers from the public package entrypoint. ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const name = await text({ message: 'What is your name?', @@ -21,7 +21,7 @@ The package is ESM-first. The workspace acceptance tests verify that the built r ## Local Workspace -Inside this repository, `@ollin/tui` is a workspace package. The docs package depends on it with `workspace:*`, so examples compile against the package source. +Inside this repository, `@ollin/console` is a workspace package. The docs package depends on it with `workspace:*`, so examples compile against the package source. ## Common Imports @@ -42,7 +42,7 @@ import { task, text, withPromptEnvironment, -} from '@ollin/tui'; +} from '@ollin/console'; const project = await text({ message: 'Project name', required: true }); const runtime = await select({ message: 'Runtime', options: ['Node.js', 'Bun', 'Deno'] }); @@ -65,7 +65,7 @@ await withPromptEnvironment({ input, output }, () => search({ message: 'Owner', ## Consumer Call And Output ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const project = await text({ message: 'Project name', required: true }); ``` diff --git a/packages/docs/src/guide/introduction.md b/apps/docs/src/guide/introduction.md similarity index 73% rename from packages/docs/src/guide/introduction.md rename to apps/docs/src/guide/introduction.md index 61b69e75..339f23a0 100644 --- a/packages/docs/src/guide/introduction.md +++ b/apps/docs/src/guide/introduction.md @@ -1,8 +1,8 @@ # Introduction -`@ollin/tui` is a prompt toolkit for command-line applications. It exposes prompt helpers, form composition, terminal output helpers, status indicators, and a testable prompt environment from the public `@ollin/tui` entrypoint. +`@ollin/console` is a prompt toolkit for command-line applications. It exposes prompt helpers, form composition, terminal output helpers, status indicators, and a testable prompt environment from the public `@ollin/console` entrypoint. -This guide documents the current `@ollin/tui` package surface with examples you can adapt directly in commands. +This guide documents the current `@ollin/console` package surface with examples you can adapt directly in commands. ## What Is Included @@ -12,16 +12,16 @@ It also exports `form`, output helpers such as `info`, `warning`, `table`, and ` ## Package Overview -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 package is implemented as TypeScript-first ESM and exposes its supported runtime surface through the public `@ollin/console` 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 -This is a complete workflow using prompts, forms, output, and status helpers from `@ollin/tui`. +This is a complete workflow using prompts, forms, output, and status helpers from `@ollin/console`. ```ts -import { form, progress, table, task } from '@ollin/tui'; +import { form, progress, table, task } from '@ollin/console'; const responses = await form() .intro('Create a release') @@ -65,7 +65,7 @@ The same helpers can be used one at a time, chained in `form()`, or wrapped with ## Consumer Call And Output ```ts -import { confirm, text } from '@ollin/tui'; +import { confirm, text } from '@ollin/console'; const release = await text({ message: 'Release name', required: true }); const publish = await confirm({ message: 'Publish now?', default: false }); diff --git a/packages/docs/src/guide/multisearch.md b/apps/docs/src/guide/multisearch.md similarity index 90% rename from packages/docs/src/guide/multisearch.md rename to apps/docs/src/guide/multisearch.md index c2e796ec..66d96657 100644 --- a/packages/docs/src/guide/multisearch.md +++ b/apps/docs/src/guide/multisearch.md @@ -3,7 +3,7 @@ The `multisearch` helper combines search input with multiple selected results. ```ts -import { multisearch } from '@ollin/tui'; +import { multisearch } from '@ollin/console'; const userIds = await multisearch({ message: 'Search for users receiving the email.', @@ -22,7 +22,7 @@ Use this helper when the option set is too large for `multiselect` and should be ## Complete Usage ```ts -import { multisearch } from '@ollin/tui'; +import { multisearch } from '@ollin/console'; const users = { 1: 'Lin Chen', @@ -51,7 +51,7 @@ void [reviewers, labels]; ## Consumer Call And Output ```ts -import { multisearch } from '@ollin/tui'; +import { multisearch } from '@ollin/console'; const reviewers = await multisearch({ message: 'Reviewers', diff --git a/packages/docs/src/guide/multiselect.md b/apps/docs/src/guide/multiselect.md similarity index 91% rename from packages/docs/src/guide/multiselect.md rename to apps/docs/src/guide/multiselect.md index 6801cc26..c4303cb7 100644 --- a/packages/docs/src/guide/multiselect.md +++ b/apps/docs/src/guide/multiselect.md @@ -3,7 +3,7 @@ The `multiselect` helper asks the user to choose multiple values. ```ts -import { multiselect } from '@ollin/tui'; +import { multiselect } from '@ollin/console'; const permissions = await multiselect({ message: 'What permissions should be assigned?', @@ -24,7 +24,7 @@ By default, multiple-selection prompts can return an empty array. Use `required` ## Complete Usage ```ts -import { multiselect } from '@ollin/tui'; +import { multiselect } from '@ollin/console'; const permissions = await multiselect({ message: 'What permissions should be assigned?', @@ -49,7 +49,7 @@ void [permissions, checks]; ## Consumer Call And Output ```ts -import { multiselect } from '@ollin/tui'; +import { multiselect } from '@ollin/console'; const checks = await multiselect({ message: 'Checks to run', diff --git a/packages/docs/src/guide/number.md b/apps/docs/src/guide/number.md similarity index 86% rename from packages/docs/src/guide/number.md rename to apps/docs/src/guide/number.md index b197d9a4..b1ea36e3 100644 --- a/packages/docs/src/guide/number.md +++ b/apps/docs/src/guide/number.md @@ -3,7 +3,7 @@ The `number` helper reads numeric input and supports numeric constraints. ```ts -import { number } from '@ollin/tui'; +import { number } from '@ollin/console'; const copies = await number({ message: 'How many copies?', @@ -19,7 +19,7 @@ const copies = await number({ Use `min`, `max`, and `integer` for common numeric rules. Use `validate` when the rule depends on application state. ```ts -import { number } from '@ollin/tui'; +import { number } from '@ollin/console'; const amount = await number({ message: 'How many seats?', @@ -30,7 +30,7 @@ const amount = await number({ ## Complete Usage ```ts -import { number } from '@ollin/tui'; +import { number } from '@ollin/console'; const seats = await number({ message: 'How many seats?', @@ -51,7 +51,7 @@ void [seats, retries]; ## Consumer Call And Output ```ts -import { number } from '@ollin/tui'; +import { number } from '@ollin/console'; const seats = await number({ message: 'Seats', diff --git a/packages/docs/src/guide/password.md b/apps/docs/src/guide/password.md similarity index 86% rename from packages/docs/src/guide/password.md rename to apps/docs/src/guide/password.md index 4cb8bf94..0e5bbdd5 100644 --- a/packages/docs/src/guide/password.md +++ b/apps/docs/src/guide/password.md @@ -3,7 +3,7 @@ The `password` helper reads masked text input for sensitive values. ```ts -import { password } from '@ollin/tui'; +import { password } from '@ollin/console'; const token = await password({ message: 'Enter your API token.', @@ -15,7 +15,7 @@ const token = await password({ `password` shares the text prompt validation model. Use a typed callback for length, format, or application-specific checks. ```ts -import { password } from '@ollin/tui'; +import { password } from '@ollin/console'; const secret = await password({ message: 'Secret', @@ -26,7 +26,7 @@ const secret = await password({ ## Complete Usage ```ts -import { password } from '@ollin/tui'; +import { password } from '@ollin/console'; const token = await password({ message: 'API token', @@ -45,7 +45,7 @@ void [token, confirmation]; ## Consumer Call And Output ```ts -import { password } from '@ollin/tui'; +import { password } from '@ollin/console'; const token = await password({ message: 'API token', diff --git a/packages/docs/src/guide/pause.md b/apps/docs/src/guide/pause.md similarity index 86% rename from packages/docs/src/guide/pause.md rename to apps/docs/src/guide/pause.md index 53d602e4..84caa0bc 100644 --- a/packages/docs/src/guide/pause.md +++ b/apps/docs/src/guide/pause.md @@ -3,7 +3,7 @@ The `pause` helper waits for the user to continue. ```ts -import { pause } from '@ollin/tui'; +import { pause } from '@ollin/console'; await pause('Press enter to continue.'); ``` @@ -13,7 +13,7 @@ Use `pause` between groups of prompts or before a destructive step that should b `pause` is also available on `form()`. ```ts -import { form } from '@ollin/tui'; +import { form } from '@ollin/console'; await form().pause('Review the summary before continuing.').submit(); ``` @@ -25,7 +25,7 @@ await form().pause('Review the summary before continuing.').submit(); ## Complete Usage ```ts -import { form, pause } from '@ollin/tui'; +import { form, pause } from '@ollin/console'; const continued = await pause('Press enter to continue.'); @@ -41,7 +41,7 @@ void [continued, responses]; ## Consumer Call And Output ```ts -import { pause } from '@ollin/tui'; +import { pause } from '@ollin/console'; await pause('Review the summary, then press enter.'); ``` diff --git a/packages/docs/src/guide/progress.md b/apps/docs/src/guide/progress.md similarity index 87% rename from packages/docs/src/guide/progress.md rename to apps/docs/src/guide/progress.md index 43341b65..b02bc5e2 100644 --- a/packages/docs/src/guide/progress.md +++ b/apps/docs/src/guide/progress.md @@ -3,7 +3,7 @@ The `progress` helper supports iterable work and manual progress control. ```ts -import { progress } from '@ollin/tui'; +import { progress } from '@ollin/console'; await progress('Processing files', ['one.ts', 'two.ts'], async (file) => file.toUpperCase()); ``` @@ -11,7 +11,7 @@ await progress('Processing files', ['one.ts', 'two.ts'], async (file) => file.to For manual control, create a `Progress` instance and call `start`, `advance`, and `finish`. ```ts -import { progress } from '@ollin/tui'; +import { progress } from '@ollin/console'; const bar = progress(3, 'Manual steps'); @@ -23,7 +23,7 @@ bar.finish(); ## Complete Usage ```ts -import { form, progress } from '@ollin/tui'; +import { form, progress } from '@ollin/console'; const files = await progress('Processing files', ['one.ts', 'two.ts'], async (file, bar) => { bar.hint(`Current file: ${String(file)}`); @@ -47,7 +47,7 @@ void [files, responses]; ## Consumer Call And Output ```ts -import { progress } from '@ollin/tui'; +import { progress } from '@ollin/console'; await progress('Building packages', ['tui', 'docs'], async (pkg) => String(pkg)); ``` diff --git a/packages/docs/src/guide/search.md b/apps/docs/src/guide/search.md similarity index 91% rename from packages/docs/src/guide/search.md rename to apps/docs/src/guide/search.md index 9360c246..1734cae5 100644 --- a/packages/docs/src/guide/search.md +++ b/apps/docs/src/guide/search.md @@ -3,7 +3,7 @@ The `search` helper filters options as the user types and returns one selected value. ```ts -import { search } from '@ollin/tui'; +import { search } from '@ollin/console'; const userId = await search({ message: 'Search for the user receiving the email.', @@ -23,7 +23,7 @@ When `options` returns an object, the selected key is returned. When it returns ## Complete Usage ```ts -import { search } from '@ollin/tui'; +import { search } from '@ollin/console'; const users = new Map([ [1, 'Lin Chen'], @@ -49,7 +49,7 @@ void [userId, userName]; ## Consumer Call And Output ```ts -import { search } from '@ollin/tui'; +import { search } from '@ollin/console'; const reviewer = await search({ message: 'Reviewer', diff --git a/packages/docs/src/guide/select.md b/apps/docs/src/guide/select.md similarity index 90% rename from packages/docs/src/guide/select.md rename to apps/docs/src/guide/select.md index 204da382..c0e766ae 100644 --- a/packages/docs/src/guide/select.md +++ b/apps/docs/src/guide/select.md @@ -3,7 +3,7 @@ The `select` helper asks the user to choose one item. ```ts -import { select } from '@ollin/tui'; +import { select } from '@ollin/console'; const role = await select({ message: 'What role should the user have?', @@ -24,7 +24,7 @@ Associative options return the selected key. Array options return the selected v `select` always returns one value. Use `validate` if a visible option may be unavailable. ```ts -import { select } from '@ollin/tui'; +import { select } from '@ollin/console'; const role = await select({ message: 'Role', @@ -36,7 +36,7 @@ const role = await select({ ## Complete Usage ```ts -import { select } from '@ollin/tui'; +import { select } from '@ollin/console'; const role = await select({ message: 'What role should the user have?', @@ -60,7 +60,7 @@ void [role, channel]; ## Consumer Call And Output ```ts -import { select } from '@ollin/tui'; +import { select } from '@ollin/console'; const channel = await select({ message: 'Release channel', diff --git a/packages/docs/src/guide/spin.md b/apps/docs/src/guide/spin.md similarity index 91% rename from packages/docs/src/guide/spin.md rename to apps/docs/src/guide/spin.md index 786805b0..60a0efa0 100644 --- a/packages/docs/src/guide/spin.md +++ b/apps/docs/src/guide/spin.md @@ -3,7 +3,7 @@ The `spin` helper runs async work while rendering a spinner. ```ts -import { spin } from '@ollin/tui'; +import { spin } from '@ollin/console'; const result = await spin('Installing dependencies', async () => 'installed'); ``` @@ -17,7 +17,7 @@ Use `spin` for one async operation where users only need to know that work is in ## Complete Usage ```ts -import { form, spin } from '@ollin/tui'; +import { form, spin } from '@ollin/console'; const result = await spin('Installing dependencies', async () => { return 'installed'; @@ -38,7 +38,7 @@ The callback return value is preserved, so `spin` can wrap existing application ## Consumer Call And Output ```ts -import { spin } from '@ollin/tui'; +import { spin } from '@ollin/console'; const result = await spin('Installing dependencies', async () => 'installed'); ``` diff --git a/packages/docs/src/guide/stream.md b/apps/docs/src/guide/stream.md similarity index 84% rename from packages/docs/src/guide/stream.md rename to apps/docs/src/guide/stream.md index c354f11e..4edbfe6d 100644 --- a/packages/docs/src/guide/stream.md +++ b/apps/docs/src/guide/stream.md @@ -3,7 +3,7 @@ The `stream` helper renders streaming text from an iterable or async iterable. ```ts -import { stream } from '@ollin/tui'; +import { stream } from '@ollin/console'; await stream(['Preparing release\n', 'Release ready\n']); ``` @@ -11,7 +11,7 @@ await stream(['Preparing release\n', 'Release ready\n']); Calling `stream()` without a source returns a `Stream` instance for manual writes. ```ts -import { stream } from '@ollin/tui'; +import { stream } from '@ollin/console'; const output = stream(); @@ -22,7 +22,7 @@ output.close(); ## Complete Usage ```ts -import { form, stream } from '@ollin/tui'; +import { form, stream } from '@ollin/console'; await stream(['Preparing release\n', 'Release ready\n']); @@ -40,7 +40,7 @@ void responses; ## Consumer Call And Output ```ts -import { stream } from '@ollin/tui'; +import { stream } from '@ollin/console'; await stream(['Preparing release\n', 'Release ready\n']); ``` diff --git a/packages/docs/src/guide/suggest.md b/apps/docs/src/guide/suggest.md similarity index 90% rename from packages/docs/src/guide/suggest.md rename to apps/docs/src/guide/suggest.md index f8a5800f..bd5b57a7 100644 --- a/packages/docs/src/guide/suggest.md +++ b/apps/docs/src/guide/suggest.md @@ -3,7 +3,7 @@ The `suggest` helper offers completions while still allowing any typed value. ```ts -import { suggest } from '@ollin/tui'; +import { suggest } from '@ollin/console'; const author = await suggest({ message: 'Author name', @@ -19,7 +19,7 @@ Use `required`, `validate`, and `transform` the same way you would on `text`. ## Complete Usage ```ts -import { suggest } from '@ollin/tui'; +import { suggest } from '@ollin/console'; const names = ['Ada', 'Grace', 'Lin', 'Katherine']; @@ -42,7 +42,7 @@ void [author, reviewer]; ## Consumer Call And Output ```ts -import { suggest } from '@ollin/tui'; +import { suggest } from '@ollin/console'; const maintainer = await suggest({ message: 'Maintainer', diff --git a/packages/docs/src/guide/tables.md b/apps/docs/src/guide/tables.md similarity index 78% rename from packages/docs/src/guide/tables.md rename to apps/docs/src/guide/tables.md index 3d4ea08d..ebe41956 100644 --- a/packages/docs/src/guide/tables.md +++ b/apps/docs/src/guide/tables.md @@ -3,7 +3,7 @@ Use `table` or `dataTable` to render tabular output. ```ts -import { dataTable, table } from '@ollin/tui'; +import { dataTable, table } from '@ollin/console'; table(['Name', 'Runtime'], [ ['Prompts', 'TypeScript'], @@ -22,7 +22,7 @@ dataTable({ `dataTable` is a display alias for `table`. For an interactive selectable table, use `datatable`. ```ts -import { datatable } from '@ollin/tui'; +import { datatable } from '@ollin/console'; const selected = await datatable({ message: 'Select a user', @@ -38,12 +38,12 @@ const selected = await datatable({ ## Complete Usage ```ts -import { dataTable, datatable, form, grid, table } from '@ollin/tui'; +import { dataTable, datatable, form, grid, table } from '@ollin/console'; table({ headers: ['Package', 'Purpose'], rows: [ - { Package: '@ollin/tui', Purpose: 'Runtime prompts' }, + { Package: '@ollin/console', Purpose: 'Runtime prompts' }, { Package: 'docs', Purpose: 'Documentation site' }, ], }); @@ -59,7 +59,7 @@ const selected = await datatable({ message: 'Select a package', headers: ['Package', 'Purpose'], rows: [ - ['@ollin/tui', 'Runtime prompts'], + ['@ollin/console', 'Runtime prompts'], ['docs', 'Documentation site'], ], required: true, @@ -76,12 +76,12 @@ void [selected, responses]; ## Consumer Call And Output ```ts -import { table } from '@ollin/tui'; +import { table } from '@ollin/console'; table(['Package', 'Purpose'], [ - ['@ollin/tui', 'Prompts'], + ['@ollin/console', 'Prompts'], ['docs', 'Documentation'], ]); ``` - + diff --git a/packages/docs/src/guide/task.md b/apps/docs/src/guide/task.md similarity index 89% rename from packages/docs/src/guide/task.md rename to apps/docs/src/guide/task.md index 4d53f390..2710bee9 100644 --- a/packages/docs/src/guide/task.md +++ b/apps/docs/src/guide/task.md @@ -3,7 +3,7 @@ The `task` helper runs work with structured task logging. ```ts -import { task } from '@ollin/tui'; +import { task } from '@ollin/console'; const result = await task('Publishing', async (logger) => { logger.info('Uploading assets'); @@ -18,7 +18,7 @@ Use `logger.info`, `logger.line`, `logger.success`, `logger.warning`, and `logge ## Complete Usage ```ts -import { form, task } from '@ollin/tui'; +import { form, task } from '@ollin/console'; const result = await task('Publishing', async (logger) => { logger.info('Uploading assets'); @@ -43,7 +43,7 @@ void [result, responses]; ## Consumer Call And Output ```ts -import { task } from '@ollin/tui'; +import { task } from '@ollin/console'; await task('Publishing package', async (logger) => { logger.info('Uploading files'); diff --git a/packages/docs/src/guide/terminal-considerations.md b/apps/docs/src/guide/terminal-considerations.md similarity index 78% rename from packages/docs/src/guide/terminal-considerations.md rename to apps/docs/src/guide/terminal-considerations.md index 5bf6576a..6c188253 100644 --- a/packages/docs/src/guide/terminal-considerations.md +++ b/apps/docs/src/guide/terminal-considerations.md @@ -1,9 +1,9 @@ # Terminal Considerations -`@ollin/tui` represents terminal IO through `PromptEnvironment`. The default environment reads from the process input and writes to process output. Tests and non-standard runtimes can replace those streams. +`@ollin/console` represents terminal IO through `PromptEnvironment`. The default environment reads from the process input and writes to process output. Tests and non-standard runtimes can replace those streams. ```ts -import { promptEnvironment, terminalSize } from '@ollin/tui'; +import { promptEnvironment, terminalSize } from '@ollin/console'; const environment = promptEnvironment(); const size = terminalSize(); @@ -20,7 +20,7 @@ Terminal helpers restore cursor state around status renderers such as `spin`, `p ## Complete Usage ```ts -import { createMemoryOutput, createScriptedInput, promptEnvironment, terminalSize, text, withPromptEnvironment } from '@ollin/tui'; +import { createMemoryOutput, createScriptedInput, promptEnvironment, terminalSize, text, withPromptEnvironment } from '@ollin/console'; const current = promptEnvironment(); const size = terminalSize(); @@ -45,7 +45,7 @@ Keep process-specific assumptions near your application entrypoint. Library code ## Consumer Call And Output ```ts -import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/tui'; +import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/console'; const output = createMemoryOutput(); const input = createScriptedInput(['Ada']); diff --git a/packages/docs/src/guide/terminal-title.md b/apps/docs/src/guide/terminal-title.md similarity index 83% rename from packages/docs/src/guide/terminal-title.md rename to apps/docs/src/guide/terminal-title.md index 3753952f..3082cad4 100644 --- a/packages/docs/src/guide/terminal-title.md +++ b/apps/docs/src/guide/terminal-title.md @@ -3,7 +3,7 @@ Use `title` to set the terminal title through the configured prompt output. ```ts -import { title } from '@ollin/tui'; +import { title } from '@ollin/console'; title('Ollin TUI'); ``` @@ -11,7 +11,7 @@ title('Ollin TUI'); The lower-level terminal helper `setTerminalTitle` is also exported for direct terminal control. ```ts -import { setTerminalTitle } from '@ollin/tui'; +import { setTerminalTitle } from '@ollin/console'; setTerminalTitle('Ollin TUI'); ``` @@ -23,7 +23,7 @@ Use `title` when you want the same output boundary as the rest of the prompt hel ## Complete Usage ```ts -import { form, setTerminalTitle, title } from '@ollin/tui'; +import { form, setTerminalTitle, title } from '@ollin/console'; title('Ollin TUI'); setTerminalTitle('Ollin TUI: Build'); @@ -40,7 +40,7 @@ Terminal title support depends on the terminal emulator. Terminals that ignore t ## Consumer Call And Output ```ts -import { title } from '@ollin/tui'; +import { title } from '@ollin/console'; title('Ollin TUI: Release'); ``` diff --git a/packages/docs/src/guide/testing.md b/apps/docs/src/guide/testing.md similarity index 91% rename from packages/docs/src/guide/testing.md rename to apps/docs/src/guide/testing.md index 76a86ed2..b646c7a5 100644 --- a/packages/docs/src/guide/testing.md +++ b/apps/docs/src/guide/testing.md @@ -3,7 +3,7 @@ Use prompt environment helpers to exercise prompt flows without process input. ```ts -import { Key, createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/tui'; +import { Key, createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/console'; const output = createMemoryOutput(); const input = createScriptedInput(['Ada', Key.enter]); @@ -23,7 +23,7 @@ This uses the same exported helpers as application code. The scripted input supp ## Complete Usage ```ts -import { Key, confirm, createMemoryOutput, createScriptedInput, select, text, withPromptEnvironment } from '@ollin/tui'; +import { Key, confirm, createMemoryOutput, createScriptedInput, select, text, withPromptEnvironment } from '@ollin/console'; const output = createMemoryOutput(); const input = createScriptedInput(['Ada', Key.enter, Key.down, Key.enter, 'y']); @@ -56,7 +56,7 @@ void [result, rendered]; ## Consumer Call And Output ```ts -import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/tui'; +import { createMemoryOutput, createScriptedInput, text, withPromptEnvironment } from '@ollin/console'; const output = createMemoryOutput(); const input = createScriptedInput(['Ada']); diff --git a/packages/docs/src/guide/text.md b/apps/docs/src/guide/text.md similarity index 89% rename from packages/docs/src/guide/text.md rename to apps/docs/src/guide/text.md index 7eee9dc7..38bd598c 100644 --- a/packages/docs/src/guide/text.md +++ b/apps/docs/src/guide/text.md @@ -3,7 +3,7 @@ The `text` helper reads a single-line string. ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const name = await text({ message: 'What is your name?', @@ -22,7 +22,7 @@ The `validate` callback returns a string error message or `null`. Use callbacks ## Label-First Form ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const name = await text('What is your name?', 'Ada Lovelace', '', true); ``` @@ -30,7 +30,7 @@ const name = await text('What is your name?', 'Ada Lovelace', '', true); ## Complete Usage ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const project = await text({ message: 'Project name', @@ -50,7 +50,7 @@ void [project, owner]; ## Consumer Call And Output ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const project = await text({ message: 'Project name', diff --git a/packages/docs/src/guide/textarea.md b/apps/docs/src/guide/textarea.md similarity index 89% rename from packages/docs/src/guide/textarea.md rename to apps/docs/src/guide/textarea.md index a25b73f5..7cac4205 100644 --- a/packages/docs/src/guide/textarea.md +++ b/apps/docs/src/guide/textarea.md @@ -3,7 +3,7 @@ The `textarea` helper reads multi-line input. ```ts -import { textarea } from '@ollin/tui'; +import { textarea } from '@ollin/console'; const biography = await textarea({ message: 'Tell us about your project.', @@ -22,7 +22,7 @@ Use `validate` for custom checks and `transform` to normalise the submitted stri ## Complete Usage ```ts -import { textarea } from '@ollin/tui'; +import { textarea } from '@ollin/console'; const summary = await textarea({ message: 'Release notes', @@ -42,7 +42,7 @@ void [summary, supportMessage]; ## Consumer Call And Output ```ts -import { textarea } from '@ollin/tui'; +import { textarea } from '@ollin/console'; const notes = await textarea({ message: 'Release notes', diff --git a/packages/docs/src/guide/transforms.md b/apps/docs/src/guide/transforms.md similarity index 91% rename from packages/docs/src/guide/transforms.md rename to apps/docs/src/guide/transforms.md index f6a477c9..962e08b9 100644 --- a/packages/docs/src/guide/transforms.md +++ b/apps/docs/src/guide/transforms.md @@ -3,7 +3,7 @@ Prompt options can include `transform`. The transform runs on the submitted value before validation completes. ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const slug = await text({ message: 'Project slug', @@ -19,7 +19,7 @@ Use callbacks for `validate` and `transform`. ## Complete Usage ```ts -import { confirm, multiselect, number, text } from '@ollin/tui'; +import { confirm, multiselect, number, text } from '@ollin/console'; const slug = await text({ message: 'Project slug', @@ -50,7 +50,7 @@ void [slug, seats, permissions, publish]; ## Consumer Call And Output ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const slug = await text({ message: 'Project slug', diff --git a/packages/docs/src/index.md b/apps/docs/src/index.md similarity index 82% rename from packages/docs/src/index.md rename to apps/docs/src/index.md index d76ef722..261b32c2 100644 --- a/packages/docs/src/index.md +++ b/apps/docs/src/index.md @@ -1,4 +1,4 @@ -# @ollin/tui +# @ollin/console Prompt and terminal helpers for command-line applications. @@ -8,14 +8,14 @@ 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. +`@ollin/console` 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 -import { form, table, task } from '@ollin/tui'; +import { form, table, task } from '@ollin/console'; const answers = await form() .text({ message: 'Package name', required: true }, 'name') @@ -45,7 +45,7 @@ table(['Field', 'Value'], [ ## Consumer Call And Output ```ts -import { text } from '@ollin/tui'; +import { text } from '@ollin/console'; const name = await text({ message: 'Package name', default: 'cli-tools' }); ``` diff --git a/packages/docs/tests/docs.test.ts b/apps/docs/tests/docs.test.ts similarity index 100% rename from packages/docs/tests/docs.test.ts rename to apps/docs/tests/docs.test.ts diff --git a/packages/docs/tsconfig.json b/apps/docs/tsconfig.json similarity index 62% rename from packages/docs/tsconfig.json rename to apps/docs/tsconfig.json index c03fb7e2..0327742e 100644 --- a/packages/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@ollin/infra/tsconfig/base.json", + "extends": "@ollin/console-infra/tsconfig/base.json", "compilerOptions": { "baseUrl": ".", "paths": { @@ -10,11 +10,11 @@ "@docs-tests/*": ["tests/*"], "@docs-theme/*": ["vitepress/theme/*"], "@docs-ui/*": ["vitepress/theme/components/ui/*"], - "@ollin/tui": ["../tui/src/index.ts"], - "#tui/*": ["../tui/src/*"], - "#tui/prompts/*": ["../tui/src/prompts/*"] + "@ollin/console": ["../../pkgs-ts/console/src/index.ts"], + "#console/*": ["../../pkgs-ts/console/src/*"], + "#console/prompts/*": ["../../pkgs-ts/console/src/prompts/*"] }, "tsBuildInfoFile": "../../infra/.cache/tsbuild/docs.tsbuildinfo" }, - "include": ["examples/**/*.ts", "tests/**/*.ts", "vitepress/**/*.ts", "vitest.config.ts", "../tui/src/**/*.ts"] + "include": ["examples/**/*.ts", "tests/**/*.ts", "vitepress/**/*.ts", "vitest.config.ts", "../../pkgs-ts/console/src/**/*.ts"] } diff --git a/packages/docs/typedoc.json b/apps/docs/typedoc.json similarity index 66% rename from packages/docs/typedoc.json rename to apps/docs/typedoc.json index c163a56f..852e1e8b 100644 --- a/packages/docs/typedoc.json +++ b/apps/docs/typedoc.json @@ -1,5 +1,5 @@ { - "entryPoints": ["../tui/src/index.ts"], + "entryPoints": ["../../pkgs-ts/console/src/index.ts"], "excludeInternal": true, "excludePrivate": true, "excludeProtected": true, @@ -8,5 +8,5 @@ "out": "src/api", "plugin": ["typedoc-plugin-markdown"], "readme": "none", - "tsconfig": "../tui/tsconfig.json" + "tsconfig": "../../pkgs-ts/console/tsconfig.json" } diff --git a/packages/docs/vitepress/config.ts b/apps/docs/vitepress/config.ts similarity index 94% rename from packages/docs/vitepress/config.ts rename to apps/docs/vitepress/config.ts index e7885be8..62967256 100644 --- a/packages/docs/vitepress/config.ts +++ b/apps/docs/vitepress/config.ts @@ -42,8 +42,8 @@ export const guideSections = [ ] as const; export default defineConfig({ - title: '@ollin/tui', - description: 'Documentation for the Ollin TUI prompt toolkit.', + title: '@ollin/console', + description: 'Documentation for the Ollin Console prompt toolkit.', cleanUrls: true, lastUpdated: true, vite: { @@ -78,7 +78,7 @@ export default defineConfig({ }, ], footer: { - message: 'Documentation for the @ollin/tui TypeScript package.', + message: 'Documentation for the @ollin/console TypeScript package.', }, }, }); diff --git a/packages/docs/vitepress/theme/components/TerminalOutput.vue b/apps/docs/vitepress/theme/components/TerminalOutput.vue similarity index 100% rename from packages/docs/vitepress/theme/components/TerminalOutput.vue rename to apps/docs/vitepress/theme/components/TerminalOutput.vue diff --git a/packages/docs/vitepress/theme/components/ui/badge/Badge.vue b/apps/docs/vitepress/theme/components/ui/badge/Badge.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/badge/Badge.vue rename to apps/docs/vitepress/theme/components/ui/badge/Badge.vue diff --git a/packages/docs/vitepress/theme/components/ui/badge/index.ts b/apps/docs/vitepress/theme/components/ui/badge/index.ts similarity index 100% rename from packages/docs/vitepress/theme/components/ui/badge/index.ts rename to apps/docs/vitepress/theme/components/ui/badge/index.ts diff --git a/packages/docs/vitepress/theme/components/ui/badge/variants.ts b/apps/docs/vitepress/theme/components/ui/badge/variants.ts similarity index 100% rename from packages/docs/vitepress/theme/components/ui/badge/variants.ts rename to apps/docs/vitepress/theme/components/ui/badge/variants.ts diff --git a/packages/docs/vitepress/theme/components/ui/card/Card.vue b/apps/docs/vitepress/theme/components/ui/card/Card.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/Card.vue rename to apps/docs/vitepress/theme/components/ui/card/Card.vue diff --git a/packages/docs/vitepress/theme/components/ui/card/CardAction.vue b/apps/docs/vitepress/theme/components/ui/card/CardAction.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/CardAction.vue rename to apps/docs/vitepress/theme/components/ui/card/CardAction.vue diff --git a/packages/docs/vitepress/theme/components/ui/card/CardContent.vue b/apps/docs/vitepress/theme/components/ui/card/CardContent.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/CardContent.vue rename to apps/docs/vitepress/theme/components/ui/card/CardContent.vue diff --git a/packages/docs/vitepress/theme/components/ui/card/CardDescription.vue b/apps/docs/vitepress/theme/components/ui/card/CardDescription.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/CardDescription.vue rename to apps/docs/vitepress/theme/components/ui/card/CardDescription.vue diff --git a/packages/docs/vitepress/theme/components/ui/card/CardFooter.vue b/apps/docs/vitepress/theme/components/ui/card/CardFooter.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/CardFooter.vue rename to apps/docs/vitepress/theme/components/ui/card/CardFooter.vue diff --git a/packages/docs/vitepress/theme/components/ui/card/CardHeader.vue b/apps/docs/vitepress/theme/components/ui/card/CardHeader.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/CardHeader.vue rename to apps/docs/vitepress/theme/components/ui/card/CardHeader.vue diff --git a/packages/docs/vitepress/theme/components/ui/card/CardTitle.vue b/apps/docs/vitepress/theme/components/ui/card/CardTitle.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/CardTitle.vue rename to apps/docs/vitepress/theme/components/ui/card/CardTitle.vue diff --git a/packages/docs/vitepress/theme/components/ui/card/index.ts b/apps/docs/vitepress/theme/components/ui/card/index.ts similarity index 100% rename from packages/docs/vitepress/theme/components/ui/card/index.ts rename to apps/docs/vitepress/theme/components/ui/card/index.ts diff --git a/packages/docs/vitepress/theme/components/ui/separator/Separator.vue b/apps/docs/vitepress/theme/components/ui/separator/Separator.vue similarity index 100% rename from packages/docs/vitepress/theme/components/ui/separator/Separator.vue rename to apps/docs/vitepress/theme/components/ui/separator/Separator.vue diff --git a/packages/docs/vitepress/theme/components/ui/separator/index.ts b/apps/docs/vitepress/theme/components/ui/separator/index.ts similarity index 100% rename from packages/docs/vitepress/theme/components/ui/separator/index.ts rename to apps/docs/vitepress/theme/components/ui/separator/index.ts diff --git a/packages/docs/vitepress/theme/index.ts b/apps/docs/vitepress/theme/index.ts similarity index 100% rename from packages/docs/vitepress/theme/index.ts rename to apps/docs/vitepress/theme/index.ts diff --git a/packages/docs/vitepress/theme/lib/utils.ts b/apps/docs/vitepress/theme/lib/utils.ts similarity index 100% rename from packages/docs/vitepress/theme/lib/utils.ts rename to apps/docs/vitepress/theme/lib/utils.ts diff --git a/packages/docs/vitepress/theme/styles.css b/apps/docs/vitepress/theme/styles.css similarity index 100% rename from packages/docs/vitepress/theme/styles.css rename to apps/docs/vitepress/theme/styles.css diff --git a/packages/docs/vitepress/vue.d.ts b/apps/docs/vitepress/vue.d.ts similarity index 100% rename from packages/docs/vitepress/vue.d.ts rename to apps/docs/vitepress/vue.d.ts diff --git a/packages/docs/vitest.config.ts b/apps/docs/vitest.config.ts similarity index 84% rename from packages/docs/vitest.config.ts rename to apps/docs/vitest.config.ts index 8fc6fa91..ae1e3912 100644 --- a/packages/docs/vitest.config.ts +++ b/apps/docs/vitest.config.ts @@ -10,8 +10,8 @@ const docsVitepressPath = join(packagePath, 'vitepress'); const docsThemePath = join(docsVitepressPath, 'theme'); const docsComponentsPath = join(docsThemePath, 'components'); const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'docs'); -const tuiSourcePath = join(packagesPath, 'tui', 'src', 'index.ts'); -const internalSourcePath = join(packagesPath, 'tui', 'src', '$1'); +const consoleSourcePath = join(workspacePath, 'pkgs-ts', 'console', 'src', 'index.ts'); +const internalSourcePath = join(workspacePath, 'pkgs-ts', 'console', 'src', '$1'); const docsConfigPath = join(docsVitepressPath, 'config.ts'); const docsLibPath = join(docsThemePath, 'lib'); const docsTestsPath = join(packagePath, 'tests'); @@ -50,11 +50,11 @@ export default defineConfig({ replacement: docsUiPath, }, { - find: '@ollin/tui', - replacement: tuiSourcePath, + find: '@ollin/console', + replacement: consoleSourcePath, }, { - find: /^#tui\/(.+)$/u, + find: /^#console\/(.+)$/u, replacement: internalSourcePath, }, ], diff --git a/infra/.gitignore b/infra/.gitignore deleted file mode 100644 index ceddaa37..00000000 --- a/infra/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.cache/ diff --git a/infra/README.md b/infra/README.md index 027210b3..71af227c 100644 --- a/infra/README.md +++ b/infra/README.md @@ -1,13 +1,13 @@ # Infra Workspace -The `infra` workspace (`@ollin/infra`) owns project tooling that is not part of +The `infra` workspace (`@ollin/console-infra`) owns project tooling that is not part of the public package runtime: - `src` exposes shared TypeScript path helpers (`infraRoot`, `cacheDir`, `workspacePath`, …) for the tool cache. - `tsconfig` holds the centralized TypeScript configs every package extends - (`base.json`, `tui.json`, `acceptance.json`), published via the - `@ollin/infra/tsconfig/*.json` exports. + (`base.json`, `console.json`, `acceptance.json`), published via the + `@ollin/console-infra/tsconfig/*.json` exports. - `make` holds the modular Makefile. The repo-root `Makefile` is a transparent forwarder into `infra/make/Makefile`. - `.cache` is the only mutable tool-cache root for workspace commands. diff --git a/infra/make/fresh.mk b/infra/make/fresh.mk index 86d8aa1c..48ea53d9 100644 --- a/infra/make/fresh.mk +++ b/infra/make/fresh.mk @@ -6,13 +6,15 @@ fresh: ## Clean generated state, reinstall dependencies, then build @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)"/pkgs-ts/*/node_modules \ + "$(ROOT_PATH)"/apps/*/node_modules \ + "$(ROOT_PATH)/pkgs-go/node_modules" \ "$(ROOT_PATH)/infra/node_modules" \ "$(ROOT_PATH)/infra/.cache" \ - "$(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" + "$(ROOT_PATH)/apps/docs/src/.vitepress/cache" \ + "$(ROOT_PATH)/apps/docs/src/.vitepress/dist" \ + "$(ROOT_PATH)/apps/docs/src/api" \ + "$(ROOT_PATH)/pkgs-ts/console/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)/infra/.cache" -prune -o -type d -name '.cache' -prune -exec rm -rf {} + diff --git a/infra/package.json b/infra/package.json index 1c0c7714..6e45f8fa 100644 --- a/infra/package.json +++ b/infra/package.json @@ -1,5 +1,5 @@ { - "name": "@ollin/infra", + "name": "@ollin/console-infra", "version": "0.1.0", "private": true, "type": "module", diff --git a/infra/src/index.ts b/infra/src/index.ts index 8e4007cf..b2f2b353 100644 --- a/infra/src/index.ts +++ b/infra/src/index.ts @@ -10,7 +10,7 @@ export const repoRoot = resolve(infraRoot, '..'); export const repoPath = (...segments: string[]): string => resolve(repoRoot, ...segments); -export const workspacePath = (...segments: string[]): string => repoPath('packages', ...segments); +export const workspacePath = (...segments: string[]): string => repoPath('pkgs-ts', ...segments); export const cacheDir = (...segments: string[]): string => resolve(cacheRoot, ...segments); diff --git a/infra/tsconfig/console.json b/infra/tsconfig/console.json new file mode 100644 index 00000000..57d7b495 --- /dev/null +++ b/infra/tsconfig/console.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "../.cache/tsbuild/console.tsbuildinfo" + } +} diff --git a/infra/tsconfig/tui.json b/infra/tsconfig/tui.json deleted file mode 100644 index 70bc18e1..00000000 --- a/infra/tsconfig/tui.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "../.cache/tsbuild/tui.tsbuildinfo" - } -} diff --git a/package.json b/package.json index f1677855..f0c55e02 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "typecheck": "XDG_CACHE_HOME=infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=infra/.cache/playwright turbo run typecheck --cache-dir infra/.cache/turbo --log-file infra/.cache/turbo/logs/typecheck.json --output-logs=none" }, "devDependencies": { - "@ollin/infra": "workspace:*", + "@ollin/console-infra": "workspace:*", "@types/node": "^25.6.2", "turbo": "^2.9.12", "typescript": "^6.0.3", diff --git a/packages/acceptance/tests/helpers.test.ts b/packages/acceptance/tests/helpers.test.ts deleted file mode 100644 index 9b7bd211..00000000 --- a/packages/acceptance/tests/helpers.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { - confirm, - createMemoryOutput, - createScriptedInput, - form, - multiselect, - note, - error, - info, - intro, - outro, - number, - progress, - select, - spin, - stream, - table, - text, - title, - withPromptEnvironment, -} from '@ollin/tui'; - -const scripted = async (lines: string[], callback: () => Promise): Promise<{ output: string; result: T }> => { - const output = createMemoryOutput(); - - const result = await withPromptEnvironment( - { - input: createScriptedInput(lines), - output, - error: output, - interactive: true, - }, - callback, - ); - - return { output: output.text(), result }; -}; - -describe('prompt helpers', () => { - it('reads text and number prompts', async () => { - await expect(scripted(['A', 'd', 'a', '\n'], () => text('Name'))).resolves.toMatchObject({ result: 'Ada' }); - - await expect(scripted(['4', '2', '\n'], () => number({ message: 'Age', integer: true }))).resolves.toMatchObject({ result: 42 }); - }); - - it('reads confirm and choice prompts', async () => { - await expect(scripted(['n'], () => confirm('Continue'))).resolves.toMatchObject({ result: false }); - - await expect( - scripted(['2'], () => - select({ - message: 'Framework', - options: ['Ollin', 'Vue'], - }), - ), - ).resolves.toMatchObject({ result: 'Vue' }); - - await expect( - scripted(['1,2'], () => - multiselect({ - message: 'Tools', - options: ['Prompts', 'OpenTUI'], - }), - ), - ).resolves.toMatchObject({ result: ['Prompts', 'OpenTUI'] }); - }); - - it('runs form builders', async () => { - const response = await scripted(['A', 'd', 'a', '\n', 'y'], () => - form().text('Name', '', '', false, undefined, '', 'name').confirm('Active', true, 'Yes', 'No', false, undefined, '', 'active').submit(), - ); - - expect(response.result.name).toBe('Ada'); - expect(response.result.active).toBe(true); - }); - - it('writes output helpers', async () => { - const output = createMemoryOutput(); - - await withPromptEnvironment({ output, error: output }, async () => { - note('Hello'); - error('Nope'); - info('Facts'); - intro('Start'); - outro('Done'); - table({ headers: ['Name'], rows: [['Ollin']] }); - title('Demo'); - }); - - expect(output.text()).toContain('Hello'); - expect(output.text()).toContain('Nope'); - expect(output.text()).toContain('Facts'); - expect(output.text()).toContain('Start'); - expect(output.text()).toContain('Done'); - expect(output.text()).toContain('| Name'); - expect(output.text()).toContain('\u001B]0;Demo\u0007'); - }); - - it('runs status helpers', async () => { - const output = createMemoryOutput(); - - await withPromptEnvironment({ output, error: output }, async () => { - await spin(async () => 'done', { message: 'Working' }); - - const bar = progress(2, 'Files'); - - bar.advance(); - bar.advance(); - bar.finish(); - - await stream(['a', 'b']); - }); - - expect(output.text()).toContain('Working'); - expect(output.text()).toContain('┌ Files '); - expect(output.text()).toContain('2 / 2'); - expect(output.text()).toContain('ab'); - }); -}); diff --git a/packages/acceptance/tsconfig.json b/packages/acceptance/tsconfig.json deleted file mode 100644 index af5e9ab8..00000000 --- a/packages/acceptance/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": ["@ollin/infra/tsconfig/base.json", "@ollin/infra/tsconfig/acceptance.json"], - "compilerOptions": { - "baseUrl": "..", - "paths": { - "@ollin/tui": ["tui/src/index.ts"], - "#tui/*": ["tui/src/*"], - "#tui/prompts/*": ["tui/src/prompts/*"] - } - }, - "include": ["tests/**/*.ts", "vitest.config.ts", "../tui/src/**/*.ts"] -} diff --git a/packages/tui/src/concerns/choices.ts b/packages/tui/src/concerns/choices.ts deleted file mode 100644 index 3d7b060f..00000000 --- a/packages/tui/src/concerns/choices.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { choiceByValue, choiceValueEquals, findChoice } from '#tui/concerns/choice-match'; -export { choiceWindow, firstEnabledIndex, nextEnabledIndex } from '#tui/concerns/choice-navigation'; -export { normalizeChoices, normalizeSearchChoices } from '#tui/concerns/choice-normalize'; -export { renderInteractiveChoices, renderInteractiveChecklist } from '#tui/concerns/choice-render'; diff --git a/packages/tui/src/environment.ts b/packages/tui/src/environment.ts deleted file mode 100644 index c625150d..00000000 --- a/packages/tui/src/environment.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { configurePrompts, promptEnvironment, withPromptEnvironment } from '#tui/environment/scope'; -export { createMemoryOutput } from '#tui/environment/memory-output'; -export { createScriptedInput } from '#tui/environment/scripted-input'; -export type { MemoryOutput } from '#tui/environment/memory-output'; -export type { RawKeyInput } from '#tui/environment/raw-key'; diff --git a/packages/tui/src/form/builder/output/index.ts b/packages/tui/src/form/builder/output/index.ts deleted file mode 100644 index 18f28855..00000000 --- a/packages/tui/src/form/builder/output/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { datatableFormStep } from '#tui/form/builder/output/data-table'; -export { alertFormStep, errorFormStep, gridFormStep, infoFormStep, introFormStep, noteFormStep, outroFormStep, warningFormStep } from '#tui/form/builder/output/display'; -export { notifyFormStep } from '#tui/form/builder/output/notification'; -export { clearFormStep, titleFormStep } from '#tui/form/builder/output/terminal'; -export { dataTableFormStep, tableFormStep } from '#tui/form/builder/output/table'; diff --git a/packages/tui/src/form/builder/prompts.ts b/packages/tui/src/form/builder/prompts.ts deleted file mode 100644 index 31c017af..00000000 --- a/packages/tui/src/form/builder/prompts.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { basicPromptBuilderMethods } from '#tui/form/builder/prompts/basic'; -import { choicePromptBuilderMethods } from '#tui/form/builder/prompts/choices'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { PromptBuilderMethods } from '#tui/form/builder/prompts/types'; - -export type { PromptBuilderMethods }; - -export const promptBuilderMethods: PromptBuilderMethods & ThisType = { - ...basicPromptBuilderMethods, - ...choicePromptBuilderMethods, -}; diff --git a/packages/tui/src/form/builder/prompts/basic/index.ts b/packages/tui/src/form/builder/prompts/basic/index.ts deleted file mode 100644 index 3d2ef7bc..00000000 --- a/packages/tui/src/form/builder/prompts/basic/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { numberFormStep } from '#tui/form/builder/prompts/basic/number'; -export { passwordFormStep } from '#tui/form/builder/prompts/basic/password'; -export { textFormStep } from '#tui/form/builder/prompts/basic/text'; -export { textareaFormStep } from '#tui/form/builder/prompts/basic/textarea'; diff --git a/packages/tui/src/form/builder/prompts/choice/index.ts b/packages/tui/src/form/builder/prompts/choice/index.ts deleted file mode 100644 index c3394d13..00000000 --- a/packages/tui/src/form/builder/prompts/choice/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -export { autocompleteFormStep } from '#tui/form/builder/prompts/choice/autocomplete'; -export { confirmFormStep } from '#tui/form/builder/prompts/choice/confirm'; -export { multisearchFormStep } from '#tui/form/builder/prompts/choice/multisearch'; -export { multiselectFormStep } from '#tui/form/builder/prompts/choice/multiselect'; -export { pauseFormStep } from '#tui/form/builder/prompts/choice/pause'; -export { searchFormStep } from '#tui/form/builder/prompts/choice/search'; -export { selectFormStep } from '#tui/form/builder/prompts/choice/select'; -export { suggestFormStep } from '#tui/form/builder/prompts/choice/suggest'; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices.ts b/packages/tui/src/form/builder/prompts/contracts/choices.ts deleted file mode 100644 index 3901ccc1..00000000 --- a/packages/tui/src/form/builder/prompts/contracts/choices.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { AutocompletePromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/autocomplete'; -import type { ConfirmPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/confirm'; -import type { MultiSearchPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/multisearch'; -import type { MultiSelectPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/multiselect'; -import type { PausePromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/pause'; -import type { SearchPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/search'; -import type { SelectPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/select'; -import type { SuggestPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices/suggest'; - -export type ChoicePromptBuilderMethods = AutocompletePromptBuilderMethods & - ConfirmPromptBuilderMethods & - MultiSearchPromptBuilderMethods & - MultiSelectPromptBuilderMethods & - PausePromptBuilderMethods & - SearchPromptBuilderMethods & - SelectPromptBuilderMethods & - SuggestPromptBuilderMethods; diff --git a/packages/tui/src/form/builder/prompts/contracts/index.ts b/packages/tui/src/form/builder/prompts/contracts/index.ts deleted file mode 100644 index 3edc9899..00000000 --- a/packages/tui/src/form/builder/prompts/contracts/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import type { BasicPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/basic'; -import type { ChoicePromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices'; - -export type PromptBuilderMethods = BasicPromptBuilderMethods & ChoicePromptBuilderMethods; diff --git a/packages/tui/src/form/builder/prompts/types.ts b/packages/tui/src/form/builder/prompts/types.ts deleted file mode 100644 index cc3b5efa..00000000 --- a/packages/tui/src/form/builder/prompts/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type { BasicPromptBuilderMethods } from '#tui/form/builder/prompts/contracts/basic'; -export type { ChoicePromptBuilderMethods } from '#tui/form/builder/prompts/contracts/choices'; -export type { PromptBuilderMethods } from '#tui/form/builder/prompts/contracts/index'; diff --git a/packages/tui/src/form/builder/prompts/validators/basic.ts b/packages/tui/src/form/builder/prompts/validators/basic.ts deleted file mode 100644 index c5b8597c..00000000 --- a/packages/tui/src/form/builder/prompts/validators/basic.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { isBasicPromptLabel, isBasicPromptOptions, parseBasicStepName } from '#tui/form/builder/prompts/validators/basic-label'; -export { resolveNumberFormArguments } from '#tui/form/builder/prompts/validators/basic-number'; -export type { ResolvedNumberFormArguments } from '#tui/form/builder/prompts/validators/basic-number'; -export { resolvePasswordFormArguments, resolveTextFormArguments } from '#tui/form/builder/prompts/validators/basic-text'; -export type { ResolvedTextFormArguments } from '#tui/form/builder/prompts/validators/basic-text'; -export { resolveTextareaFormArguments } from '#tui/form/builder/prompts/validators/basic-textarea'; -export type { ResolvedTextareaFormArguments } from '#tui/form/builder/prompts/validators/basic-textarea'; diff --git a/packages/tui/src/form/builder/prompts/validators/search.ts b/packages/tui/src/form/builder/prompts/validators/search.ts deleted file mode 100644 index f6d3e632..00000000 --- a/packages/tui/src/form/builder/prompts/validators/search.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { isSearchPromptLabel, isSearchPromptOptions, parseSearchChoiceSource, parseSearchStepName } from '#tui/form/builder/prompts/validators/search/common'; -export type { SearchChoiceSourceCallback } from '#tui/form/builder/prompts/validators/search/common'; -export { resolveMultiSearchFormArguments } from '#tui/form/builder/prompts/validators/search/multisearch'; -export type { ResolvedMultiSearchFormArguments } from '#tui/form/builder/prompts/validators/search/multisearch'; -export { resolveSearchFormArguments } from '#tui/form/builder/prompts/validators/search/search'; -export type { ResolvedSearchFormArguments } from '#tui/form/builder/prompts/validators/search/search'; diff --git a/packages/tui/src/form/builder/prompts/validators/select.ts b/packages/tui/src/form/builder/prompts/validators/select.ts deleted file mode 100644 index 66fafe55..00000000 --- a/packages/tui/src/form/builder/prompts/validators/select.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { isSelectPromptLabel, isSelectPromptOptions, parseConfirmDefault, parseSelectChoiceOptions, parseSelectStepName } from '#tui/form/builder/prompts/validators/select/common'; -export { resolveConfirmFormArguments } from '#tui/form/builder/prompts/validators/select/confirm'; -export type { ResolvedConfirmFormArguments } from '#tui/form/builder/prompts/validators/select/confirm'; -export { resolveMultiSelectFormArguments } from '#tui/form/builder/prompts/validators/select/multiselect'; -export type { ResolvedMultiSelectFormArguments } from '#tui/form/builder/prompts/validators/select/multiselect'; -export { resolveSelectFormArguments } from '#tui/form/builder/prompts/validators/select/select'; -export type { ResolvedSelectFormArguments } from '#tui/form/builder/prompts/validators/select/select'; diff --git a/packages/tui/src/form/builder/prompts/validators/suggest.ts b/packages/tui/src/form/builder/prompts/validators/suggest.ts deleted file mode 100644 index c18d51ad..00000000 --- a/packages/tui/src/form/builder/prompts/validators/suggest.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { resolveAutocompleteFormArguments } from '#tui/form/builder/prompts/validators/suggest/autocomplete'; -export type { ResolvedAutocompleteFormArguments } from '#tui/form/builder/prompts/validators/suggest/autocomplete'; -export { isSuggestPromptLabel, isSuggestPromptOptions, parseSuggestSource, parseSuggestStepName } from '#tui/form/builder/prompts/validators/suggest/common'; -export type { SuggestSourceCallback } from '#tui/form/builder/prompts/validators/suggest/common'; -export { resolveSuggestFormArguments } from '#tui/form/builder/prompts/validators/suggest/suggest'; -export type { ResolvedSuggestFormArguments } from '#tui/form/builder/prompts/validators/suggest/suggest'; diff --git a/packages/tui/src/form/builder/status/index.ts b/packages/tui/src/form/builder/status/index.ts deleted file mode 100644 index e51471b9..00000000 --- a/packages/tui/src/form/builder/status/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { progressFormStep } from '#tui/form/builder/status/progress'; -export { spinFormStep } from '#tui/form/builder/status/spin'; -export { streamFormStep } from '#tui/form/builder/status/stream'; -export { taskFormStep } from '#tui/form/builder/status/task'; diff --git a/packages/tui/src/form/builder/validators/output.ts b/packages/tui/src/form/builder/validators/output.ts deleted file mode 100644 index 4a1b32c5..00000000 --- a/packages/tui/src/form/builder/validators/output.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { isNullOutputRows, parseOutputScroll, parseOutputStepName } from '#tui/form/builder/validators/output/common'; -export { parseOutputDataTableRows, resolveDataTableFormArguments } from '#tui/form/builder/validators/output/data-table'; -export type { ResolvedDataTableFormArguments } from '#tui/form/builder/validators/output/data-table'; -export { parseOutputTableRows, resolveTableFormArguments } from '#tui/form/builder/validators/output/table'; -export type { ResolvedTableFormArguments } from '#tui/form/builder/validators/output/table'; diff --git a/packages/tui/src/form/builder/validators/status.ts b/packages/tui/src/form/builder/validators/status.ts deleted file mode 100644 index dc672f82..00000000 --- a/packages/tui/src/form/builder/validators/status.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { isProgressTotal, isStatusLabel, parseProgressCallback, parseStatusCallback, parseStatusLabel } from '#tui/form/builder/validators/status/common'; -export { resolveProgressFormArguments } from '#tui/form/builder/validators/status/progress'; -export type { ResolvedProgressFormArguments } from '#tui/form/builder/validators/status/progress'; -export { resolveSpinFormArguments } from '#tui/form/builder/validators/status/spin'; -export type { ResolvedSpinFormArguments } from '#tui/form/builder/validators/status/spin'; -export { isStreamSource, resolveStreamFormArguments } from '#tui/form/builder/validators/status/stream'; -export type { ResolvedStreamFormArguments } from '#tui/form/builder/validators/status/stream'; -export { resolveTaskFormArguments } from '#tui/form/builder/validators/status/task'; -export type { ResolvedTaskFormArguments } from '#tui/form/builder/validators/status/task'; diff --git a/packages/tui/src/key.ts b/packages/tui/src/key.ts deleted file mode 100644 index 44382ce1..00000000 --- a/packages/tui/src/key.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { Key } from '#tui/key/constants'; -export { keyFromEvent } from '#tui/key/event'; -export { oneOf } from '#tui/key/match'; -export type { KeyboardEventLike, KeyName, KeyValue } from '#tui/key/types'; diff --git a/packages/tui/src/output.ts b/packages/tui/src/output.ts deleted file mode 100644 index db10a4f6..00000000 --- a/packages/tui/src/output.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { alert, error, info, intro, note, outro, warning } from '#tui/output/notes'; -export type { NoteType } from '#tui/output/notes'; -export { commandExists, executeNotificationCommand, notificationCommand, notificationCommands, notify, notifyForPlatform } from '#tui/output/notify'; -export type { NotificationCommand, NotificationOptions, NotificationPlatform, NotificationRuntime } from '#tui/output/notify'; -export { datatable } from '#tui/output/data-table'; -export { dataTable, grid, table } from '#tui/output/table'; -export { clear, title } from '#tui/output/terminal'; diff --git a/packages/tui/src/output/data-table/read.ts b/packages/tui/src/output/data-table/read.ts deleted file mode 100644 index 347fc08b..00000000 --- a/packages/tui/src/output/data-table/read.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { promptEnvironment } from '#tui/environment'; -import { readDataTableFallbackSelection } from '#tui/output/data-table/reader/fallback'; -import { readDataTableSelectionInteractive } from '#tui/output/data-table/reader/interactive'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; -import type { DataTableSelectionReadResult } from '#tui/output/data-table/types'; - -export const readDataTableSelection = async (options: DataTableReadOptions, headers: string[]): Promise> => { - const environment = promptEnvironment(); - - if (!environment.input.readKey) { - return readDataTableFallbackSelection(options, headers); - } - - return readDataTableSelectionInteractive(environment.input.readKey, options, headers); -}; diff --git a/packages/tui/src/output/data-table/render-body.ts b/packages/tui/src/output/data-table/render-body.ts deleted file mode 100644 index ebd11d9f..00000000 --- a/packages/tui/src/output/data-table/render-body.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { renderDataTableBody } from '#tui/output/data-table/body/active'; -export { renderCancelledDataTableRows } from '#tui/output/data-table/body/cancelled'; -export { renderDataTableHeaders } from '#tui/output/data-table/body/headers'; -export { renderSubmittedDataTableRow } from '#tui/output/data-table/body/submitted'; -export type { DataTableBodyOptions } from '#tui/output/data-table/body/types'; diff --git a/packages/tui/src/output/data-table/rows.ts b/packages/tui/src/output/data-table/rows.ts deleted file mode 100644 index 5e263843..00000000 --- a/packages/tui/src/output/data-table/rows.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { stringifyDataTableCell } from '#tui/output/data-table/rows/cells'; -export { dataTableRowCells, dataTableRowFields, dataTableRowLabel, dataTableRowValue } from '#tui/output/data-table/rows/fields'; -export { deriveDataTableHeaders } from '#tui/output/data-table/rows/headers'; -export { visibleDataTableRows } from '#tui/output/data-table/rows/visible'; diff --git a/packages/tui/src/output/table.ts b/packages/tui/src/output/table.ts deleted file mode 100644 index 531dee3c..00000000 --- a/packages/tui/src/output/table.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { grid } from '#tui/output/grid-output'; -export { dataTable, table } from '#tui/output/table-output'; diff --git a/packages/tui/src/prompt.ts b/packages/tui/src/prompt.ts deleted file mode 100644 index 04338177..00000000 --- a/packages/tui/src/prompt.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { ask } from '#tui/prompt/ask'; -export { cancelPrompt, cancelUsing } from '#tui/prompt/cancel'; -export type { PromptCancelHandler } from '#tui/prompt/cancel'; -export { PromptValidationError } from '#tui/prompt/error'; -export { fallbackUsing, fallbackWhen, promptWithFallback, shouldFallback } from '#tui/prompt/fallback'; -export type { PromptFallbackCondition, PromptFallbackHandler, PromptFallbackKind } from '#tui/prompt/fallback'; -export { promptUntilValid } from '#tui/prompt/lifecycle'; -export { validateUsing } from '#tui/prompt/validate-using'; -export type { PromptGlobalValidator } from '#tui/prompt/validate-using'; -export { ensureRequired, validationMessage } from '#tui/prompt/validation'; diff --git a/packages/tui/src/prompts.ts b/packages/tui/src/prompts.ts deleted file mode 100644 index b8d4e569..00000000 --- a/packages/tui/src/prompts.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { number, password, text, textarea } from '#tui/prompts/basic'; -export { autocomplete, confirm, multisearch, multiselect, pause, search, select, suggest } from '#tui/prompts/choices'; -export type { SuggestOptions } from '#tui/prompts/choices'; diff --git a/packages/tui/src/prompts/basic.ts b/packages/tui/src/prompts/basic.ts deleted file mode 100644 index 5bf4ecef..00000000 --- a/packages/tui/src/prompts/basic.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { text } from '#tui/prompts/text'; -export { textarea } from '#tui/prompts/textarea'; -export { password } from '#tui/prompts/password'; -export { number } from '#tui/prompts/number'; diff --git a/packages/tui/src/prompts/choices.ts b/packages/tui/src/prompts/choices.ts deleted file mode 100644 index 34ae33b4..00000000 --- a/packages/tui/src/prompts/choices.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { confirm, multiselect, select } from '#tui/prompts/select/index'; -export { autocomplete, suggest } from '#tui/prompts/suggest/index'; -export { multisearch, search } from '#tui/prompts/search/index'; -export { pause } from '#tui/prompts/pause'; -export type { SuggestOptions } from '#tui/prompts/suggest/index'; diff --git a/packages/tui/src/prompts/search/index.ts b/packages/tui/src/prompts/search/index.ts deleted file mode 100644 index 9012ff36..00000000 --- a/packages/tui/src/prompts/search/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { multisearch } from '#tui/prompts/search/multisearch'; -export { search } from '#tui/prompts/search/search'; diff --git a/packages/tui/src/prompts/search/keys.ts b/packages/tui/src/prompts/search/keys.ts deleted file mode 100644 index 63e3999a..00000000 --- a/packages/tui/src/prompts/search/keys.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { clearsSearchHighlight, moveSearchHighlight } from '#tui/prompts/search/keys/highlight'; -export type { MoveSearchHighlightOptions } from '#tui/prompts/search/keys/highlight'; -export { searchNavigationAction } from '#tui/prompts/search/keys/navigation'; -export type { SearchNavigationAction, SearchNavigationOptions } from '#tui/prompts/search/keys/navigation'; diff --git a/packages/tui/src/prompts/search/read-multi/cancel.ts b/packages/tui/src/prompts/search/read-multi/cancel.ts deleted file mode 100644 index ab4c19d9..00000000 --- a/packages/tui/src/prompts/search/read-multi/cancel.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { cancelPrompt } from '#tui/prompt'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderCancelledSearch } from '#tui/prompts/search/render'; -import { selectedSearchValues } from '#tui/prompts/search/read-multi/result'; -import type { MultiSearchChoicesReadResult } from '#tui/prompts/search/read-multi/result'; -import type { MultiSearchReaderSession } from '#tui/prompts/search/read-multi/session'; -import type { MultiSearchPromptOptions } from '#tui/types'; - -export const cancelMultiSearchChoices = async (options: MultiSearchPromptOptions, session: MultiSearchReaderSession): Promise> => { - eraseRenderedFrame(session.frame()); - renderCancelledSearch(options.message, session.query().value, options.placeholder); - - const value = selectedSearchValues(session.selected()); - - return { - cancelled: true, - submitted: false, - submittedLabels: session.selectedLabels(), - value: await cancelPrompt(value), - }; -}; diff --git a/packages/tui/src/prompts/search/read-multi/state/context.ts b/packages/tui/src/prompts/search/read-multi/state/context.ts deleted file mode 100644 index 39961a34..00000000 --- a/packages/tui/src/prompts/search/read-multi/state/context.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { resolveSearchChoices } from '#tui/prompts/search/choices'; -import { createMultiSearchChoiceQuery } from '#tui/prompts/search/read-multi/choice-query'; -import { createMultiSearchHighlightState } from '#tui/prompts/search/read-multi/state/highlight'; -import { createMultiSearchSelection } from '#tui/prompts/search/read-multi/state/selection'; -import type { MultiSearchChoiceQuery } from '#tui/prompts/search/read-multi/choice-query'; -import type { MultiSearchHighlightState } from '#tui/prompts/search/read-multi/state/highlight'; -import type { SearchSelection } from '#tui/prompts/search/selection'; -import type { MultiSearchPromptOptions } from '#tui/types'; - -export type MultiSearchReaderStateContext = { - highlighted: MultiSearchHighlightState; - query: MultiSearchChoiceQuery; - selected: SearchSelection; -}; - -export const createMultiSearchReaderStateContext = async (options: MultiSearchPromptOptions): Promise> => { - const initialChoices = await resolveSearchChoices(options.options, ''); - - const selected = createMultiSearchSelection(initialChoices, options.default); - - return { - highlighted: createMultiSearchHighlightState(options.scroll), - query: createMultiSearchChoiceQuery(options, selected, initialChoices), - selected, - }; -}; diff --git a/packages/tui/src/prompts/search/read-multi/state/labels.ts b/packages/tui/src/prompts/search/read-multi/state/labels.ts deleted file mode 100644 index ae45f121..00000000 --- a/packages/tui/src/prompts/search/read-multi/state/labels.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { multiSearchSelectedLabels } from '#tui/prompts/search/read-multi/state/selection'; -import type { SearchSelection } from '#tui/prompts/search/selection'; - -export const selectedMultiSearchLabels = (selected: SearchSelection): string[] => { - return multiSearchSelectedLabels(selected); -}; diff --git a/packages/tui/src/prompts/search/read-single.ts b/packages/tui/src/prompts/search/read-single.ts deleted file mode 100644 index a21857af..00000000 --- a/packages/tui/src/prompts/search/read-single.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { promptEnvironment } from '#tui/environment'; -import { readSearchChoiceInteractive } from '#tui/prompts/search/read-single/interactive'; -import { lineSearchValue } from '#tui/prompts/search/read-single/result'; -import type { SearchChoiceReadResult } from '#tui/prompts/search/read-single/result'; -import type { SearchReadOptions } from '#tui/prompts/search/read-single/types'; - -export const readSearchChoice = async (options: SearchReadOptions, attempt = 0): Promise> => { - const environment = promptEnvironment(); - - if (!environment.input.readKey) { - return { cancelled: false, submitted: false, submittedLabel: '', value: await lineSearchValue(options) }; - } - - return readSearchChoiceInteractive(environment.input.readKey, options, attempt); -}; diff --git a/packages/tui/src/prompts/search/render-body.ts b/packages/tui/src/prompts/search/render-body.ts deleted file mode 100644 index 71f70664..00000000 --- a/packages/tui/src/prompts/search/render-body.ts +++ /dev/null @@ -1 +0,0 @@ -export { renderSearchBody } from '#tui/prompts/search/body/render'; diff --git a/packages/tui/src/prompts/select/index.ts b/packages/tui/src/prompts/select/index.ts deleted file mode 100644 index 9166d706..00000000 --- a/packages/tui/src/prompts/select/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { confirm } from '#tui/prompts/select/confirm'; -export { multiselect } from '#tui/prompts/select/multiselect'; -export { select } from '#tui/prompts/select/select'; diff --git a/packages/tui/src/prompts/select/read-multiple/cancel.ts b/packages/tui/src/prompts/select/read-multiple/cancel.ts deleted file mode 100644 index d4b480e3..00000000 --- a/packages/tui/src/prompts/select/read-multiple/cancel.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { cancelPrompt } from '#tui/prompt'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { markedChoiceValues } from '#tui/prompts/select/multiple'; -import { cancelledMultipleChoicesResult } from '#tui/prompts/select/read-multiple/result'; -import type { MultipleChoicesReaderSession } from '#tui/prompts/select/read-multiple/session'; -import type { MultipleChoicesReadResult } from '#tui/prompts/select/read-multiple/types'; -import { renderCancelledChoices } from '#tui/prompts/select/render'; -import type { Choice } from '#tui/types'; - -export const cancelMultipleChoices = async (message: string, choices: Array>, session: MultipleChoicesReaderSession, scroll?: number): Promise> => { - eraseRenderedFrame(session.frame()); - renderCancelledChoices(message, choices, session.selected(), session.marked(), scroll); - - const value = markedChoiceValues(choices, session.marked()); - - return cancelledMultipleChoicesResult(choices, session.marked(), await cancelPrompt(value)); -}; diff --git a/packages/tui/src/prompts/select/read-selected/interactive/cancel.ts b/packages/tui/src/prompts/select/read-selected/interactive/cancel.ts deleted file mode 100644 index b0cb7cb4..00000000 --- a/packages/tui/src/prompts/select/read-selected/interactive/cancel.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { cancelPrompt } from '#tui/prompt'; -import { parseChoiceValue } from '#tui/concerns/validators/choice'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { cancelledSelectedChoiceResult } from '#tui/prompts/select/read-selected/result'; -import { renderCancelledChoice } from '#tui/prompts/select/render'; -import type { SelectedChoiceReaderSession } from '#tui/prompts/select/read-selected/session'; -import type { SelectedChoiceReadResult } from '#tui/prompts/select/read-selected/types'; -import type { Choice } from '#tui/types'; - -export const cancelSelectedChoice = async ( - message: string, - choices: Array>, - session: SelectedChoiceReaderSession, - defaultValue?: T, - scroll?: number, -): Promise> => { - eraseRenderedFrame(session.frame()); - renderCancelledChoice(message, choices, session.selected(), scroll); - - const choice = choices[session.selected()]; - const fallback = choice?.value ?? defaultValue; - - const value = parseChoiceValue(await cancelPrompt(fallback)); - - return cancelledSelectedChoiceResult(choice, value); -}; diff --git a/packages/tui/src/prompts/suggest/index.ts b/packages/tui/src/prompts/suggest/index.ts deleted file mode 100644 index 6b291309..00000000 --- a/packages/tui/src/prompts/suggest/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { autocomplete } from '#tui/prompts/suggest/autocomplete-prompt'; -export { suggest } from '#tui/prompts/suggest/suggest'; -export type { SuggestOptions } from '#tui/prompts/suggest/options'; diff --git a/packages/tui/src/prompts/suggest/read-autocomplete/cancel.ts b/packages/tui/src/prompts/suggest/read-autocomplete/cancel.ts deleted file mode 100644 index a965c900..00000000 --- a/packages/tui/src/prompts/suggest/read-autocomplete/cancel.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { cancelPrompt } from '#tui/prompt'; -import { renderCancelledAutocomplete } from '#tui/prompts/suggest/render-autocomplete'; -import { suggestionReadResult } from '#tui/prompts/suggest/read-result'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import type { AutocompleteReaderSession } from '#tui/prompts/suggest/read-autocomplete/session'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TextSuggestionReadResult } from '#tui/prompts/suggest/read-result'; - -export const cancelAutocompleteValue = async (options: SuggestOptions, session: AutocompleteReaderSession): Promise => { - const value = session.state().value; - - eraseRenderedFrame(session.frame()); - renderCancelledAutocomplete(options.message, value, options.placeholder); - - return suggestionReadResult(await cancelPrompt(value), true, true); -}; diff --git a/packages/tui/src/prompts/suggest/read-autocomplete/submission.ts b/packages/tui/src/prompts/suggest/read-autocomplete/submission.ts deleted file mode 100644 index a574284c..00000000 --- a/packages/tui/src/prompts/suggest/read-autocomplete/submission.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { suggestionReadResult } from '#tui/prompts/suggest/read-result'; -import type { AutocompleteReaderSession } from '#tui/prompts/suggest/read-autocomplete/session'; -import type { TextSuggestionReadResult } from '#tui/prompts/suggest/read-result'; - -export const currentAutocompleteValue = (session: AutocompleteReaderSession): TextSuggestionReadResult => { - return suggestionReadResult(session.state().value, true, false, session.frame()); -}; diff --git a/packages/tui/src/prompts/suggest/read/cancel.ts b/packages/tui/src/prompts/suggest/read/cancel.ts deleted file mode 100644 index fec4286d..00000000 --- a/packages/tui/src/prompts/suggest/read/cancel.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { cancelPrompt } from '#tui/prompt'; -import { renderCancelledSuggestion } from '#tui/prompts/suggest/render'; -import { suggestionReadResult } from '#tui/prompts/suggest/read-result'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TextSuggestionReadResult } from '#tui/prompts/suggest/read-result'; -import type { SuggestReaderSession } from '#tui/prompts/suggest/read/session'; - -export const cancelSuggestionValue = async (options: SuggestOptions, session: SuggestReaderSession): Promise => { - const value = session.state().value; - - eraseRenderedFrame(session.frame()); - renderCancelledSuggestion(options.message, value, options.placeholder); - - return suggestionReadResult(await cancelPrompt(value), true, true); -}; diff --git a/packages/tui/src/status.ts b/packages/tui/src/status.ts deleted file mode 100644 index 6defe50c..00000000 --- a/packages/tui/src/status.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { progress, Progress } from '#tui/status/progress'; -export type { ProgressSignalTarget } from '#tui/status/progress'; -export { spin } from '#tui/status/spinner'; -export { Logger, task } from '#tui/status/task'; -export type { TaskDefinition } from '#tui/status/task'; -export { Stream, stream } from '#tui/status/stream'; diff --git a/packages/tui/src/status/task/logger.ts b/packages/tui/src/status/task/logger.ts deleted file mode 100644 index e8b6c3e8..00000000 --- a/packages/tui/src/status/task/logger.ts +++ /dev/null @@ -1 +0,0 @@ -export { Logger } from '#tui/status/task/logger/logger'; diff --git a/packages/tui/src/status/task/process-output/validators/writer.ts b/packages/tui/src/status/task/process-output/validators/writer.ts deleted file mode 100644 index 41caf619..00000000 --- a/packages/tui/src/status/task/process-output/validators/writer.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { parseProcessOutputCallback, parseProcessOutputEncoding } from '#tui/status/task/process-output/validators/writer/callback'; -export type { ProcessOutputCallback } from '#tui/status/task/process-output/validators/writer/callback'; -export { parseProcessOutputChunk, resolveProcessOutputWrite } from '#tui/status/task/process-output/validators/writer/chunk'; -export type { ResolvedProcessOutputWrite } from '#tui/status/task/process-output/validators/writer/chunk'; -export { parseProcessOutputWrite, parseWritableProcessStream } from '#tui/status/task/process-output/validators/writer/stream'; -export type { WritableProcessStream } from '#tui/status/task/process-output/validators/writer/stream'; diff --git a/packages/tui/src/string-utils/ansi.ts b/packages/tui/src/string-utils/ansi.ts deleted file mode 100644 index f29f0209..00000000 --- a/packages/tui/src/string-utils/ansi.ts +++ /dev/null @@ -1,7 +0,0 @@ -import stripAnsi from 'strip-ansi'; - -export { ansiCloseSequence, ESC } from '#tui/string-utils/ansi/codes'; -export { parseAnsiSegments } from '#tui/string-utils/ansi/segments'; -export type { AnsiSegment } from '#tui/string-utils/ansi/segments'; - -export const parseAnsiText = (value: string): string => stripAnsi(value); diff --git a/packages/tui/src/strings.ts b/packages/tui/src/strings.ts deleted file mode 100644 index 5cd4aba0..00000000 --- a/packages/tui/src/strings.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { parseAnsiSegments, parseAnsiText } from '#tui/string-utils/ansi'; -export type { AnsiSegment } from '#tui/string-utils/ansi'; -export { truncate } from '#tui/string-utils/truncate'; -export { visibleWidth } from '#tui/string-utils/width'; -export { wrap } from '#tui/string-utils/wrap'; diff --git a/packages/tui/src/theme.ts b/packages/tui/src/theme.ts deleted file mode 100644 index c397190c..00000000 --- a/packages/tui/src/theme.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { renderChoices } from '#tui/theme/choices'; -export { renderError } from '#tui/theme/error'; -export { renderQuestion } from '#tui/theme/question'; -export { symbols } from '#tui/theme/symbols'; -export { renderTable } from '#tui/theme/table'; diff --git a/packages/tui/src/typed-value.ts b/packages/tui/src/typed-value.ts deleted file mode 100644 index 68eb83ba..00000000 --- a/packages/tui/src/typed-value.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { applyTypedKey } from '#tui/typed-value/edit'; -export { readTypedValue } from '#tui/typed-value/read'; -export type { TypedValueReadResult } from '#tui/typed-value/read'; -export type { TypedValueOptions, TypedValueState } from '#tui/typed-value/types'; diff --git a/packages/tui/tsconfig.json b/packages/tui/tsconfig.json deleted file mode 100644 index 95773e9b..00000000 --- a/packages/tui/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": ["@ollin/infra/tsconfig/base.json", "@ollin/infra/tsconfig/tui.json"], - "compilerOptions": { - "baseUrl": ".", - "paths": { - "#tui/*": ["./src/*"], - "#tui/prompts/*": ["./src/prompts/*"] - } - }, - "include": ["src/**/*.ts", "vitest.config.ts"] -} diff --git a/pkgs-go/go.mod b/pkgs-go/go.mod new file mode 100644 index 00000000..9818ffb6 --- /dev/null +++ b/pkgs-go/go.mod @@ -0,0 +1,3 @@ +module pkgs-go + +go 1.26.4 diff --git a/pkgs-go/package.json b/pkgs-go/package.json new file mode 100644 index 00000000..51001d31 --- /dev/null +++ b/pkgs-go/package.json @@ -0,0 +1,10 @@ +{ + "name": "@ollin/pkgs-go", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "if find . -name '*.go' -print -quit | grep -q .; then GOCACHE=\"$PWD/../infra/.cache/go-build\" GOMODCACHE=\"$PWD/../infra/.cache/go-mod\" go build ./...; else echo 'pkgs-go: no Go sources yet, skipping build'; fi", + "test": "if find . -name '*.go' -print -quit | grep -q .; then GOCACHE=\"$PWD/../infra/.cache/go-build\" GOMODCACHE=\"$PWD/../infra/.cache/go-mod\" go test ./...; else echo 'pkgs-go: no Go sources yet, skipping test'; fi", + "typecheck": "if find . -name '*.go' -print -quit | grep -q .; then GOCACHE=\"$PWD/../infra/.cache/go-build\" GOMODCACHE=\"$PWD/../infra/.cache/go-mod\" go vet ./...; else echo 'pkgs-go: no Go sources yet, skipping vet'; fi" + } +} diff --git a/packages/tui/package.json b/pkgs-ts/console/package.json similarity index 98% rename from packages/tui/package.json rename to pkgs-ts/console/package.json index 8e705191..484d98d7 100644 --- a/packages/tui/package.json +++ b/pkgs-ts/console/package.json @@ -1,5 +1,5 @@ { - "name": "@ollin/tui", + "name": "@ollin/console", "version": "0.1.0", "type": "module", "types": "./dist/index.d.ts", @@ -178,11 +178,11 @@ } }, "imports": { - "#tui/*": { + "#console/*": { "types": "./dist/*.d.ts", "default": "./dist/*.js" }, - "#tui/prompts/*": { + "#console/prompts/*": { "types": "./dist/prompts/*.d.ts", "default": "./dist/prompts/*.js" } @@ -200,7 +200,7 @@ "zod": "^4.4.3" }, "devDependencies": { - "@ollin/infra": "workspace:*", + "@ollin/console-infra": "workspace:*", "@types/node": "^25.6.2", "typescript": "^6.0.3", "vitest": "^4.1.5" diff --git a/packages/tui/src/concerns/choice-label.ts b/pkgs-ts/console/src/concerns/choice-label.ts similarity index 65% rename from packages/tui/src/concerns/choice-label.ts rename to pkgs-ts/console/src/concerns/choice-label.ts index 23b72cdb..32790007 100644 --- a/packages/tui/src/concerns/choice-label.ts +++ b/pkgs-ts/console/src/concerns/choice-label.ts @@ -1,5 +1,5 @@ -import { choiceDisabledSuffix } from '#tui/theme/choice-disabled'; -import type { Choice } from '#tui/types'; +import { choiceDisabledSuffix } from '#console/theme/choice-disabled'; +import type { Choice } from '#console/types'; export const choiceLabel = (choice: Choice): string => { const disabled = choiceDisabledSuffix(choice.disabled); diff --git a/packages/tui/src/concerns/choice-match.ts b/pkgs-ts/console/src/concerns/choice-match.ts similarity index 86% rename from packages/tui/src/concerns/choice-match.ts rename to pkgs-ts/console/src/concerns/choice-match.ts index 7617ab3e..9aa2afa3 100644 --- a/packages/tui/src/concerns/choice-match.ts +++ b/pkgs-ts/console/src/concerns/choice-match.ts @@ -1,6 +1,6 @@ import { isDeepStrictEqual } from 'node:util'; -import { answerChoiceIndex } from '#tui/concerns/choice-normalize'; -import type { Choice } from '#tui/types'; +import { answerChoiceIndex } from '#console/concerns/choice-normalize'; +import type { Choice } from '#console/types'; export const choiceValueEquals = (left: unknown, right: unknown): boolean => Object.is(left, right) || isDeepStrictEqual(left, right); diff --git a/packages/tui/src/concerns/choice-navigation.ts b/pkgs-ts/console/src/concerns/choice-navigation.ts similarity index 88% rename from packages/tui/src/concerns/choice-navigation.ts rename to pkgs-ts/console/src/concerns/choice-navigation.ts index 66ba87c7..a81ddf62 100644 --- a/packages/tui/src/concerns/choice-navigation.ts +++ b/pkgs-ts/console/src/concerns/choice-navigation.ts @@ -1,5 +1,5 @@ -import { parseOptionalScrollSize } from '#tui/concerns/validators/scroll'; -import type { Choice } from '#tui/types'; +import { parseOptionalScrollSize } from '#console/concerns/validators/scroll'; +import type { Choice } from '#console/types'; export const firstEnabledIndex = (choices: Array>): number => { const index = choices.findIndex((choice) => !choice.disabled); diff --git a/packages/tui/src/concerns/choice-normalize.ts b/pkgs-ts/console/src/concerns/choice-normalize.ts similarity index 83% rename from packages/tui/src/concerns/choice-normalize.ts rename to pkgs-ts/console/src/concerns/choice-normalize.ts index 05e5c99f..16a40e58 100644 --- a/packages/tui/src/concerns/choice-normalize.ts +++ b/pkgs-ts/console/src/concerns/choice-normalize.ts @@ -1,6 +1,6 @@ -import { parseChoiceAnswerIndex, parseChoiceRecordValue } from '#tui/concerns/validators/choice-answer'; -import { parseChoice, parseChoiceOptions, parseChoiceRecordEntries, parseChoiceValue } from '#tui/concerns/validators/choice'; -import type { Choice, ChoiceOptions } from '#tui/types'; +import { parseChoiceAnswerIndex, parseChoiceRecordValue } from '#console/concerns/validators/choice-answer'; +import { parseChoice, parseChoiceOptions, parseChoiceRecordEntries, parseChoiceValue } from '#console/concerns/validators/choice'; +import type { Choice, ChoiceOptions } from '#console/types'; export const normalizeChoices = (options: ChoiceOptions): Array> => { const parsed = parseChoiceOptions(options); diff --git a/packages/tui/src/concerns/choice-render.ts b/pkgs-ts/console/src/concerns/choice-render.ts similarity index 85% rename from packages/tui/src/concerns/choice-render.ts rename to pkgs-ts/console/src/concerns/choice-render.ts index e69295a1..325071f2 100644 --- a/packages/tui/src/concerns/choice-render.ts +++ b/pkgs-ts/console/src/concerns/choice-render.ts @@ -1,9 +1,9 @@ -import { promptEnvironment } from '#tui/environment'; -import { choiceWindow } from '#tui/concerns/choice-navigation'; -import { renderScrollbarRows } from '#tui/concerns/scrollbar'; -import { choiceDisabledSuffix } from '#tui/theme/choice-disabled'; -import { cyan, dim } from '#tui/theme/styles'; -import type { Choice } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { choiceWindow } from '#console/concerns/choice-navigation'; +import { renderScrollbarRows } from '#console/concerns/scrollbar'; +import { choiceDisabledSuffix } from '#console/theme/choice-disabled'; +import { cyan, dim } from '#console/theme/styles'; +import type { Choice } from '#console/types'; export const renderInteractiveChoices = (message: string, choices: Array>, selected: number, marked: Set = new Set(), scroll?: number): void => { const environment = promptEnvironment(); diff --git a/pkgs-ts/console/src/concerns/choices.ts b/pkgs-ts/console/src/concerns/choices.ts new file mode 100644 index 00000000..5ff3870e --- /dev/null +++ b/pkgs-ts/console/src/concerns/choices.ts @@ -0,0 +1,4 @@ +export { choiceByValue, choiceValueEquals, findChoice } from '#console/concerns/choice-match'; +export { choiceWindow, firstEnabledIndex, nextEnabledIndex } from '#console/concerns/choice-navigation'; +export { normalizeChoices, normalizeSearchChoices } from '#console/concerns/choice-normalize'; +export { renderInteractiveChoices, renderInteractiveChecklist } from '#console/concerns/choice-render'; diff --git a/packages/tui/src/concerns/info.ts b/pkgs-ts/console/src/concerns/info.ts similarity index 85% rename from packages/tui/src/concerns/info.ts rename to pkgs-ts/console/src/concerns/info.ts index cbd411c7..4ef7a1eb 100644 --- a/packages/tui/src/concerns/info.ts +++ b/pkgs-ts/console/src/concerns/info.ts @@ -1,4 +1,4 @@ -import { isInfoCallback } from '#tui/concerns/validators/info'; +import { isInfoCallback } from '#console/concerns/validators/info'; export type InfoResolver = string | ((value: T | null) => string | null | undefined) | undefined; diff --git a/packages/tui/src/concerns/scrollbar.ts b/pkgs-ts/console/src/concerns/scrollbar.ts similarity index 85% rename from packages/tui/src/concerns/scrollbar.ts rename to pkgs-ts/console/src/concerns/scrollbar.ts index 4619cdbc..b09c2b22 100644 --- a/packages/tui/src/concerns/scrollbar.ts +++ b/pkgs-ts/console/src/concerns/scrollbar.ts @@ -1,6 +1,6 @@ -import { parseScrollbarState } from '#tui/concerns/validators/scrollbar'; -import { visibleWidth } from '#tui/strings'; -import { cyan, dim } from '#tui/theme/styles'; +import { parseScrollbarState } from '#console/concerns/validators/scrollbar'; +import { visibleWidth } from '#console/strings'; +import { cyan, dim } from '#console/theme/styles'; export const scrollbarPosition = (firstVisible: number, height: number, total: number): number => { if (firstVisible === 0) { diff --git a/packages/tui/src/concerns/text-options.ts b/pkgs-ts/console/src/concerns/text-options.ts similarity index 64% rename from packages/tui/src/concerns/text-options.ts rename to pkgs-ts/console/src/concerns/text-options.ts index afdf6055..e779ea8e 100644 --- a/packages/tui/src/concerns/text-options.ts +++ b/pkgs-ts/console/src/concerns/text-options.ts @@ -1,5 +1,5 @@ -import { isTextPromptLabel } from '#tui/concerns/validators/text-options'; -import type { TextPromptOptions } from '#tui/types'; +import { isTextPromptLabel } from '#console/concerns/validators/text-options'; +import type { TextPromptOptions } from '#console/types'; export const textOptions = (message: string | TextPromptOptions, fallback = ''): TextPromptOptions => { if (isTextPromptLabel(message)) { diff --git a/packages/tui/src/concerns/validators/choice-answer.ts b/pkgs-ts/console/src/concerns/validators/choice-answer.ts similarity index 100% rename from packages/tui/src/concerns/validators/choice-answer.ts rename to pkgs-ts/console/src/concerns/validators/choice-answer.ts diff --git a/packages/tui/src/concerns/validators/choice.ts b/pkgs-ts/console/src/concerns/validators/choice.ts similarity index 97% rename from packages/tui/src/concerns/validators/choice.ts rename to pkgs-ts/console/src/concerns/validators/choice.ts index bce1f185..2646f520 100644 --- a/packages/tui/src/concerns/validators/choice.ts +++ b/pkgs-ts/console/src/concerns/validators/choice.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { Choice, ChoiceOptions } from '#tui/types'; +import type { Choice, ChoiceOptions } from '#console/types'; const choiceSchema = z .object({ diff --git a/packages/tui/src/concerns/validators/info.ts b/pkgs-ts/console/src/concerns/validators/info.ts similarity index 82% rename from packages/tui/src/concerns/validators/info.ts rename to pkgs-ts/console/src/concerns/validators/info.ts index 3fcb3fa2..30b59634 100644 --- a/packages/tui/src/concerns/validators/info.ts +++ b/pkgs-ts/console/src/concerns/validators/info.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { InfoResolver } from '#tui/concerns/info'; +import type { InfoResolver } from '#console/concerns/info'; type InfoCallback = Exclude, string | undefined>; diff --git a/packages/tui/src/concerns/validators/scroll.ts b/pkgs-ts/console/src/concerns/validators/scroll.ts similarity index 100% rename from packages/tui/src/concerns/validators/scroll.ts rename to pkgs-ts/console/src/concerns/validators/scroll.ts diff --git a/packages/tui/src/concerns/validators/scrollbar.ts b/pkgs-ts/console/src/concerns/validators/scrollbar.ts similarity index 100% rename from packages/tui/src/concerns/validators/scrollbar.ts rename to pkgs-ts/console/src/concerns/validators/scrollbar.ts diff --git a/packages/tui/src/concerns/validators/text-options.ts b/pkgs-ts/console/src/concerns/validators/text-options.ts similarity index 100% rename from packages/tui/src/concerns/validators/text-options.ts rename to pkgs-ts/console/src/concerns/validators/text-options.ts diff --git a/packages/tui/src/contracts/base.ts b/pkgs-ts/console/src/contracts/base.ts similarity index 100% rename from packages/tui/src/contracts/base.ts rename to pkgs-ts/console/src/contracts/base.ts diff --git a/packages/tui/src/contracts/choices.ts b/pkgs-ts/console/src/contracts/choices.ts similarity index 100% rename from packages/tui/src/contracts/choices.ts rename to pkgs-ts/console/src/contracts/choices.ts diff --git a/packages/tui/src/contracts/environment.ts b/pkgs-ts/console/src/contracts/environment.ts similarity index 83% rename from packages/tui/src/contracts/environment.ts rename to pkgs-ts/console/src/contracts/environment.ts index fc0ea335..e610fdf5 100644 --- a/packages/tui/src/contracts/environment.ts +++ b/pkgs-ts/console/src/contracts/environment.ts @@ -1,4 +1,4 @@ -import type { MaybePromise } from '#tui/contracts/base'; +import type { MaybePromise } from '#console/contracts/base'; export type PromptOutput = { write(content: string): void; diff --git a/packages/tui/src/contracts/options.ts b/pkgs-ts/console/src/contracts/options.ts similarity index 71% rename from packages/tui/src/contracts/options.ts rename to pkgs-ts/console/src/contracts/options.ts index 2263fdaf..b2315d00 100644 --- a/packages/tui/src/contracts/options.ts +++ b/pkgs-ts/console/src/contracts/options.ts @@ -1,4 +1,4 @@ -import type { Validator } from '#tui/contracts/base'; +import type { Validator } from '#console/contracts/base'; export type BasePromptOptions = { message: string; diff --git a/packages/tui/src/contracts/output.ts b/pkgs-ts/console/src/contracts/output.ts similarity index 83% rename from packages/tui/src/contracts/output.ts rename to pkgs-ts/console/src/contracts/output.ts index 238beef4..79fe59bf 100644 --- a/packages/tui/src/contracts/output.ts +++ b/pkgs-ts/console/src/contracts/output.ts @@ -1,5 +1,5 @@ -import type { BasePromptOptions } from '#tui/contracts/options'; -import type { MaybePromise } from '#tui/contracts/base'; +import type { BasePromptOptions } from '#console/contracts/options'; +import type { MaybePromise } from '#console/contracts/base'; export type TableCell = string | number | boolean | null | undefined; diff --git a/packages/tui/src/contracts/prompts.ts b/pkgs-ts/console/src/contracts/prompts.ts similarity index 89% rename from packages/tui/src/contracts/prompts.ts rename to pkgs-ts/console/src/contracts/prompts.ts index 3f74f228..245f71f3 100644 --- a/packages/tui/src/contracts/prompts.ts +++ b/pkgs-ts/console/src/contracts/prompts.ts @@ -1,6 +1,6 @@ -import type { MaybePromise } from '#tui/contracts/base'; -import type { ChoiceOptions, PromptInfo } from '#tui/contracts/choices'; -import type { BasePromptOptions } from '#tui/contracts/options'; +import type { MaybePromise } from '#console/contracts/base'; +import type { ChoiceOptions, PromptInfo } from '#console/contracts/choices'; +import type { BasePromptOptions } from '#console/contracts/options'; export type TextPromptOptions = BasePromptOptions & { label?: string; diff --git a/packages/tui/src/contracts/status.ts b/pkgs-ts/console/src/contracts/status.ts similarity index 100% rename from packages/tui/src/contracts/status.ts rename to pkgs-ts/console/src/contracts/status.ts diff --git a/pkgs-ts/console/src/environment.ts b/pkgs-ts/console/src/environment.ts new file mode 100644 index 00000000..f87fa2eb --- /dev/null +++ b/pkgs-ts/console/src/environment.ts @@ -0,0 +1,5 @@ +export { configurePrompts, promptEnvironment, withPromptEnvironment } from '#console/environment/scope'; +export { createMemoryOutput } from '#console/environment/memory-output'; +export { createScriptedInput } from '#console/environment/scripted-input'; +export type { MemoryOutput } from '#console/environment/memory-output'; +export type { RawKeyInput } from '#console/environment/raw-key'; diff --git a/packages/tui/src/environment/default-input.ts b/pkgs-ts/console/src/environment/default-input.ts similarity index 82% rename from packages/tui/src/environment/default-input.ts rename to pkgs-ts/console/src/environment/default-input.ts index 8786924b..a8184d40 100644 --- a/packages/tui/src/environment/default-input.ts +++ b/pkgs-ts/console/src/environment/default-input.ts @@ -1,7 +1,7 @@ import { stdin as defaultStdin, stdout as defaultStdout } from 'node:process'; import { createInterface } from 'node:readline/promises'; -import { readRawKey } from '#tui/environment/raw-key'; -import type { PromptInput } from '#tui/types'; +import { readRawKey } from '#console/environment/raw-key'; +import type { PromptInput } from '#console/types'; export const defaultInput: PromptInput = { async readKey(): Promise { diff --git a/packages/tui/src/environment/memory-output.ts b/pkgs-ts/console/src/environment/memory-output.ts similarity index 71% rename from packages/tui/src/environment/memory-output.ts rename to pkgs-ts/console/src/environment/memory-output.ts index 3fc2b6ce..2e8dff10 100644 --- a/packages/tui/src/environment/memory-output.ts +++ b/pkgs-ts/console/src/environment/memory-output.ts @@ -1,5 +1,5 @@ -import { parsePromptOutputContent } from '#tui/environment/validators/output'; -import type { PromptOutput } from '#tui/types'; +import { parsePromptOutputContent } from '#console/environment/validators/output'; +import type { PromptOutput } from '#console/types'; export type MemoryOutput = PromptOutput & { clear(): void; diff --git a/packages/tui/src/environment/raw-key.ts b/pkgs-ts/console/src/environment/raw-key.ts similarity index 73% rename from packages/tui/src/environment/raw-key.ts rename to pkgs-ts/console/src/environment/raw-key.ts index 6dc0d4ea..f9de565e 100644 --- a/packages/tui/src/environment/raw-key.ts +++ b/pkgs-ts/console/src/environment/raw-key.ts @@ -1,6 +1,6 @@ -import { createRawKeyInputMode } from '#tui/environment/raw-key/mode'; -import { createRawKeySession } from '#tui/environment/raw-key/session'; -import type { RawKeyInput } from '#tui/environment/raw-key/types'; +import { createRawKeyInputMode } from '#console/environment/raw-key/mode'; +import { createRawKeySession } from '#console/environment/raw-key/session'; +import type { RawKeyInput } from '#console/environment/raw-key/types'; export type { RawKeyInput }; diff --git a/packages/tui/src/environment/raw-key/mode.ts b/pkgs-ts/console/src/environment/raw-key/mode.ts similarity index 88% rename from packages/tui/src/environment/raw-key/mode.ts rename to pkgs-ts/console/src/environment/raw-key/mode.ts index fcdc0a8b..34d2aab1 100644 --- a/packages/tui/src/environment/raw-key/mode.ts +++ b/pkgs-ts/console/src/environment/raw-key/mode.ts @@ -1,4 +1,4 @@ -import type { RawKeyInput } from '#tui/environment/raw-key/types'; +import type { RawKeyInput } from '#console/environment/raw-key/types'; export type RawKeyInputMode = { activate(): void; diff --git a/packages/tui/src/environment/raw-key/normalize.ts b/pkgs-ts/console/src/environment/raw-key/normalize.ts similarity index 83% rename from packages/tui/src/environment/raw-key/normalize.ts rename to pkgs-ts/console/src/environment/raw-key/normalize.ts index cfc16a44..66ebafde 100644 --- a/packages/tui/src/environment/raw-key/normalize.ts +++ b/pkgs-ts/console/src/environment/raw-key/normalize.ts @@ -1,5 +1,5 @@ -import { Key } from '#tui/key'; -import { parseKnownKeyValues } from '#tui/key/validators/value'; +import { Key } from '#console/key'; +import { parseKnownKeyValues } from '#console/key/validators/value'; const knownRawKeys = parseKnownKeyValues(); diff --git a/packages/tui/src/environment/raw-key/session.ts b/pkgs-ts/console/src/environment/raw-key/session.ts similarity index 83% rename from packages/tui/src/environment/raw-key/session.ts rename to pkgs-ts/console/src/environment/raw-key/session.ts index f7884df7..00f4e810 100644 --- a/packages/tui/src/environment/raw-key/session.ts +++ b/pkgs-ts/console/src/environment/raw-key/session.ts @@ -1,7 +1,7 @@ -import { isCompleteRawKey, normalizeRawKey } from '#tui/environment/raw-key/normalize'; -import { parseRawKeyChunkText } from '#tui/environment/raw-key/validators/chunk'; -import type { RawKeyInputMode } from '#tui/environment/raw-key/mode'; -import type { RawKeyInput } from '#tui/environment/raw-key/types'; +import { isCompleteRawKey, normalizeRawKey } from '#console/environment/raw-key/normalize'; +import { parseRawKeyChunkText } from '#console/environment/raw-key/validators/chunk'; +import type { RawKeyInputMode } from '#console/environment/raw-key/mode'; +import type { RawKeyInput } from '#console/environment/raw-key/types'; type RawKeySessionHandlers = { onData(chunk: unknown): void; diff --git a/packages/tui/src/environment/raw-key/types.ts b/pkgs-ts/console/src/environment/raw-key/types.ts similarity index 100% rename from packages/tui/src/environment/raw-key/types.ts rename to pkgs-ts/console/src/environment/raw-key/types.ts diff --git a/packages/tui/src/environment/raw-key/validators/chunk.ts b/pkgs-ts/console/src/environment/raw-key/validators/chunk.ts similarity index 100% rename from packages/tui/src/environment/raw-key/validators/chunk.ts rename to pkgs-ts/console/src/environment/raw-key/validators/chunk.ts diff --git a/packages/tui/src/environment/runtime.ts b/pkgs-ts/console/src/environment/runtime.ts similarity index 62% rename from packages/tui/src/environment/runtime.ts rename to pkgs-ts/console/src/environment/runtime.ts index 1feafba7..a853a8df 100644 --- a/packages/tui/src/environment/runtime.ts +++ b/pkgs-ts/console/src/environment/runtime.ts @@ -1,7 +1,7 @@ import { stderr as defaultStderr, stdin as defaultStdin, stdout as defaultStdout } from 'node:process'; -import { defaultInput } from '#tui/environment/default-input'; -import { outputFromStream } from '#tui/environment/stream-output'; -import type { PromptEnvironment } from '#tui/types'; +import { defaultInput } from '#console/environment/default-input'; +import { outputFromStream } from '#console/environment/stream-output'; +import type { PromptEnvironment } from '#console/types'; export const defaultEnvironment: PromptEnvironment = { input: defaultInput, diff --git a/packages/tui/src/environment/scope.ts b/pkgs-ts/console/src/environment/scope.ts similarity index 70% rename from packages/tui/src/environment/scope.ts rename to pkgs-ts/console/src/environment/scope.ts index 6e042ac0..6d2730f3 100644 --- a/packages/tui/src/environment/scope.ts +++ b/pkgs-ts/console/src/environment/scope.ts @@ -1,10 +1,10 @@ import { AsyncLocalStorage } from 'node:async_hooks'; -import { defaultEnvironment } from '#tui/environment/runtime'; -import { mergePromptEnvironment } from '#tui/environment/scope/merge'; -import { withPromptCancelScope } from '#tui/prompt/cancel'; -import { withPromptFallbackScope } from '#tui/prompt/fallback'; -import { withPromptGlobalValidationScope } from '#tui/prompt/validate-using'; -import type { MaybePromise, PromptEnvironment } from '#tui/types'; +import { defaultEnvironment } from '#console/environment/runtime'; +import { mergePromptEnvironment } from '#console/environment/scope/merge'; +import { withPromptCancelScope } from '#console/prompt/cancel'; +import { withPromptFallbackScope } from '#console/prompt/fallback'; +import { withPromptGlobalValidationScope } from '#console/prompt/validate-using'; +import type { MaybePromise, PromptEnvironment } from '#console/types'; let currentEnvironment: PromptEnvironment = defaultEnvironment; diff --git a/packages/tui/src/environment/scope/merge.ts b/pkgs-ts/console/src/environment/scope/merge.ts similarity index 67% rename from packages/tui/src/environment/scope/merge.ts rename to pkgs-ts/console/src/environment/scope/merge.ts index 892382f3..e50d0c25 100644 --- a/packages/tui/src/environment/scope/merge.ts +++ b/pkgs-ts/console/src/environment/scope/merge.ts @@ -1,5 +1,5 @@ -import { parsePromptEnvironmentPatch } from '#tui/environment/scope/validators/patch'; -import type { PromptEnvironment } from '#tui/types'; +import { parsePromptEnvironmentPatch } from '#console/environment/scope/validators/patch'; +import type { PromptEnvironment } from '#console/types'; export const mergePromptEnvironment = (current: PromptEnvironment, patch: Partial): PromptEnvironment => { const environment = parsePromptEnvironmentPatch(patch); diff --git a/packages/tui/src/environment/scope/validators/patch.ts b/pkgs-ts/console/src/environment/scope/validators/patch.ts similarity index 93% rename from packages/tui/src/environment/scope/validators/patch.ts rename to pkgs-ts/console/src/environment/scope/validators/patch.ts index 26eb1052..4d5ff4c6 100644 --- a/packages/tui/src/environment/scope/validators/patch.ts +++ b/pkgs-ts/console/src/environment/scope/validators/patch.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; -import type { PromptEnvironment, PromptInput, PromptOutput } from '#tui/types'; +import { functionSchema } from '#console/validators/function'; +import type { PromptEnvironment, PromptInput, PromptOutput } from '#console/types'; const promptInputPatchSchema = z .object({ diff --git a/packages/tui/src/environment/scripted-input.ts b/pkgs-ts/console/src/environment/scripted-input.ts similarity index 67% rename from packages/tui/src/environment/scripted-input.ts rename to pkgs-ts/console/src/environment/scripted-input.ts index b1db05b4..b8cbaf90 100644 --- a/packages/tui/src/environment/scripted-input.ts +++ b/pkgs-ts/console/src/environment/scripted-input.ts @@ -1,5 +1,5 @@ -import { parseScriptedInputLines } from '#tui/environment/validators/scripted-input'; -import type { PromptInput } from '#tui/types'; +import { parseScriptedInputLines } from '#console/environment/validators/scripted-input'; +import type { PromptInput } from '#console/types'; export const createScriptedInput = (lines: string[]): PromptInput => { const queued = parseScriptedInputLines(lines); diff --git a/packages/tui/src/environment/stream-output.ts b/pkgs-ts/console/src/environment/stream-output.ts similarity index 55% rename from packages/tui/src/environment/stream-output.ts rename to pkgs-ts/console/src/environment/stream-output.ts index 9aa6c6d9..d0716044 100644 --- a/packages/tui/src/environment/stream-output.ts +++ b/pkgs-ts/console/src/environment/stream-output.ts @@ -1,6 +1,6 @@ -import { parsePromptOutputContent } from '#tui/environment/validators/output'; -import { parseWritableOutputStream } from '#tui/environment/validators/stream-output'; -import type { PromptOutput } from '#tui/types'; +import { parsePromptOutputContent } from '#console/environment/validators/output'; +import { parseWritableOutputStream } from '#console/environment/validators/stream-output'; +import type { PromptOutput } from '#console/types'; export const outputFromStream = (stream: NodeJS.WritableStream): PromptOutput => { const writable = parseWritableOutputStream(stream); diff --git a/packages/tui/src/environment/validators/output.ts b/pkgs-ts/console/src/environment/validators/output.ts similarity index 100% rename from packages/tui/src/environment/validators/output.ts rename to pkgs-ts/console/src/environment/validators/output.ts diff --git a/packages/tui/src/environment/validators/scripted-input.ts b/pkgs-ts/console/src/environment/validators/scripted-input.ts similarity index 100% rename from packages/tui/src/environment/validators/scripted-input.ts rename to pkgs-ts/console/src/environment/validators/scripted-input.ts diff --git a/packages/tui/src/environment/validators/stream-output.ts b/pkgs-ts/console/src/environment/validators/stream-output.ts similarity index 88% rename from packages/tui/src/environment/validators/stream-output.ts rename to pkgs-ts/console/src/environment/validators/stream-output.ts index 34032db9..fa4fe7a5 100644 --- a/packages/tui/src/environment/validators/stream-output.ts +++ b/pkgs-ts/console/src/environment/validators/stream-output.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; +import { functionSchema } from '#console/validators/function'; const writableStreamSchema = z .object({ diff --git a/packages/tui/src/form.ts b/pkgs-ts/console/src/form.ts similarity index 67% rename from packages/tui/src/form.ts rename to pkgs-ts/console/src/form.ts index 98646ace..ef864874 100644 --- a/packages/tui/src/form.ts +++ b/pkgs-ts/console/src/form.ts @@ -1,8 +1,8 @@ -export { FormBuilder } from '#tui/form/builder/index'; -export type { FormResponses, FormStep, FormStepCondition } from '#tui/form/types'; +export { FormBuilder } from '#console/form/builder/index'; +export type { FormResponses, FormStep, FormStepCondition } from '#console/form/types'; -import { FormBuilder } from '#tui/form/builder/index'; -import type { MaybePromise } from '#tui/types'; +import { FormBuilder } from '#console/form/builder/index'; +import type { MaybePromise } from '#console/types'; export function form(): FormBuilder; diff --git a/packages/tui/src/form/builder/conditions.ts b/pkgs-ts/console/src/form/builder/conditions.ts similarity index 71% rename from packages/tui/src/form/builder/conditions.ts rename to pkgs-ts/console/src/form/builder/conditions.ts index 4d2b3caa..dae7741b 100644 --- a/packages/tui/src/form/builder/conditions.ts +++ b/pkgs-ts/console/src/form/builder/conditions.ts @@ -1,5 +1,5 @@ -import { resolveFormStepCondition } from '#tui/form/builder/validators/conditions'; -import type { FormResponses, FormStep } from '#tui/form/types'; +import { resolveFormStepCondition } from '#console/form/builder/validators/conditions'; +import type { FormResponses, FormStep } from '#console/form/types'; export const shouldRunStep = async (step: FormStep, responses: FormResponses): Promise => { return resolveFormStepCondition(step.condition, responses); diff --git a/packages/tui/src/form/builder/index.ts b/pkgs-ts/console/src/form/builder/index.ts similarity index 81% rename from packages/tui/src/form/builder/index.ts rename to pkgs-ts/console/src/form/builder/index.ts index 5b4f73d5..f58d69c4 100644 --- a/packages/tui/src/form/builder/index.ts +++ b/pkgs-ts/console/src/form/builder/index.ts @@ -1,9 +1,9 @@ -import { createFormResponses } from '#tui/form/builder/responses'; -import { sideEffectStep } from '#tui/form/builder/step'; -import { submitFormSteps } from '#tui/form/builder/submit'; -import { applyFormBuilderMethods, FormBuilderMethodSurface } from '#tui/form/builder/methods'; -import type { FormResponses, FormStep, FormStepCondition } from '#tui/form/types'; -import type { MaybePromise } from '#tui/types'; +import { createFormResponses } from '#console/form/builder/responses'; +import { sideEffectStep } from '#console/form/builder/step'; +import { submitFormSteps } from '#console/form/builder/submit'; +import { applyFormBuilderMethods, FormBuilderMethodSurface } from '#console/form/builder/methods'; +import type { FormResponses, FormStep, FormStepCondition } from '#console/form/types'; +import type { MaybePromise } from '#console/types'; export class FormBuilder extends FormBuilderMethodSurface { readonly #steps: FormStep[] = []; diff --git a/packages/tui/src/form/builder/methods.ts b/pkgs-ts/console/src/form/builder/methods.ts similarity index 81% rename from packages/tui/src/form/builder/methods.ts rename to pkgs-ts/console/src/form/builder/methods.ts index e5575e7a..ade72134 100644 --- a/packages/tui/src/form/builder/methods.ts +++ b/pkgs-ts/console/src/form/builder/methods.ts @@ -1,10 +1,10 @@ -import { outputBuilderMethods } from '#tui/form/builder/output'; -import { promptBuilderMethods } from '#tui/form/builder/prompts'; -import { statusBuilderMethods } from '#tui/form/builder/status'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { OutputBuilderMethods } from '#tui/form/builder/output'; -import type { PromptBuilderMethods } from '#tui/form/builder/prompts'; -import type { StatusBuilderMethods } from '#tui/form/builder/status'; +import { outputBuilderMethods } from '#console/form/builder/output'; +import { promptBuilderMethods } from '#console/form/builder/prompts'; +import { statusBuilderMethods } from '#console/form/builder/status'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { OutputBuilderMethods } from '#console/form/builder/output'; +import type { PromptBuilderMethods } from '#console/form/builder/prompts'; +import type { StatusBuilderMethods } from '#console/form/builder/status'; export type FormBuilderMethods = OutputBuilderMethods & PromptBuilderMethods & StatusBuilderMethods; diff --git a/packages/tui/src/form/builder/output.ts b/pkgs-ts/console/src/form/builder/output.ts similarity index 70% rename from packages/tui/src/form/builder/output.ts rename to pkgs-ts/console/src/form/builder/output.ts index 2506901b..c12a665e 100644 --- a/packages/tui/src/form/builder/output.ts +++ b/pkgs-ts/console/src/form/builder/output.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { OutputBuilderMethods } from '#tui/form/builder/output/contracts'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { OutputBuilderMethods } from '#console/form/builder/output/contracts'; import { alertFormStep, @@ -16,9 +16,9 @@ import { tableFormStep, titleFormStep, warningFormStep, -} from '#tui/form/builder/output/index'; +} from '#console/form/builder/output/index'; -export type { OutputBuilderMethods } from '#tui/form/builder/output/contracts'; +export type { OutputBuilderMethods } from '#console/form/builder/output/contracts'; export const outputBuilderMethods: OutputBuilderMethods & ThisType = { alert: alertFormStep, diff --git a/packages/tui/src/form/builder/output/contracts.ts b/pkgs-ts/console/src/form/builder/output/contracts.ts similarity index 95% rename from packages/tui/src/form/builder/output/contracts.ts rename to pkgs-ts/console/src/form/builder/output/contracts.ts index 7a0161c6..730b0d12 100644 --- a/packages/tui/src/form/builder/output/contracts.ts +++ b/pkgs-ts/console/src/form/builder/output/contracts.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { DataTablePromptOptions, DataTableRow, TableOptions } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { DataTablePromptOptions, DataTableRow, TableOptions } from '#console/types'; export type OutputBuilderMethods = { alert(this: FormBuilder, message: string, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/output/data-table.ts b/pkgs-ts/console/src/form/builder/output/data-table.ts similarity index 80% rename from packages/tui/src/form/builder/output/data-table.ts rename to pkgs-ts/console/src/form/builder/output/data-table.ts index 4f2b6f50..c2b01dce 100644 --- a/packages/tui/src/form/builder/output/data-table.ts +++ b/pkgs-ts/console/src/form/builder/output/data-table.ts @@ -1,8 +1,8 @@ -import { datatable } from '#tui/output'; -import { previousValue } from '#tui/form/builder/previous'; -import { resolveDataTableFormArguments } from '#tui/form/builder/validators/output'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { DataTablePromptOptions, DataTableRow } from '#tui/types'; +import { datatable } from '#console/output'; +import { previousValue } from '#console/form/builder/previous'; +import { resolveDataTableFormArguments } from '#console/form/builder/validators/output'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { DataTablePromptOptions, DataTableRow } from '#console/types'; export function datatableFormStep(this: FormBuilder, options: DataTablePromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/output/display.ts b/pkgs-ts/console/src/form/builder/output/display.ts similarity index 94% rename from packages/tui/src/form/builder/output/display.ts rename to pkgs-ts/console/src/form/builder/output/display.ts index 382fa90c..b2b03858 100644 --- a/packages/tui/src/form/builder/output/display.ts +++ b/pkgs-ts/console/src/form/builder/output/display.ts @@ -1,5 +1,5 @@ -import { alert, error, grid, info, intro, note, outro, warning } from '#tui/output'; -import type { FormBuilder } from '#tui/form/builder/index'; +import { alert, error, grid, info, intro, note, outro, warning } from '#console/output'; +import type { FormBuilder } from '#console/form/builder/index'; export const alertFormStep = function alertFormStep(this: FormBuilder, message: string, name?: string): FormBuilder { return this.addSideEffect(() => alert(message), name); diff --git a/pkgs-ts/console/src/form/builder/output/index.ts b/pkgs-ts/console/src/form/builder/output/index.ts new file mode 100644 index 00000000..bb01f0a0 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/output/index.ts @@ -0,0 +1,5 @@ +export { datatableFormStep } from '#console/form/builder/output/data-table'; +export { alertFormStep, errorFormStep, gridFormStep, infoFormStep, introFormStep, noteFormStep, outroFormStep, warningFormStep } from '#console/form/builder/output/display'; +export { notifyFormStep } from '#console/form/builder/output/notification'; +export { clearFormStep, titleFormStep } from '#console/form/builder/output/terminal'; +export { dataTableFormStep, tableFormStep } from '#console/form/builder/output/table'; diff --git a/packages/tui/src/form/builder/output/notification.ts b/pkgs-ts/console/src/form/builder/output/notification.ts similarity index 70% rename from packages/tui/src/form/builder/output/notification.ts rename to pkgs-ts/console/src/form/builder/output/notification.ts index 2b610874..ae09d619 100644 --- a/packages/tui/src/form/builder/output/notification.ts +++ b/pkgs-ts/console/src/form/builder/output/notification.ts @@ -1,5 +1,5 @@ -import { notify } from '#tui/output'; -import type { FormBuilder } from '#tui/form/builder/index'; +import { notify } from '#console/output'; +import type { FormBuilder } from '#console/form/builder/index'; export const notifyFormStep = function notifyFormStep(this: FormBuilder, title: string, body = '', subtitle = '', sound = '', icon = '', name?: string): FormBuilder { return this.addSideEffect(() => notify(title, body, subtitle, sound, icon), name); diff --git a/packages/tui/src/form/builder/output/table.ts b/pkgs-ts/console/src/form/builder/output/table.ts similarity index 86% rename from packages/tui/src/form/builder/output/table.ts rename to pkgs-ts/console/src/form/builder/output/table.ts index 0d9b10df..9cfbf2ef 100644 --- a/packages/tui/src/form/builder/output/table.ts +++ b/pkgs-ts/console/src/form/builder/output/table.ts @@ -1,7 +1,7 @@ -import { dataTable, table } from '#tui/output'; -import { resolveTableFormArguments } from '#tui/form/builder/validators/output'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { TableOptions } from '#tui/types'; +import { dataTable, table } from '#console/output'; +import { resolveTableFormArguments } from '#console/form/builder/validators/output'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { TableOptions } from '#console/types'; export function dataTableFormStep(this: FormBuilder, options: TableOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/output/terminal.ts b/pkgs-ts/console/src/form/builder/output/terminal.ts similarity index 74% rename from packages/tui/src/form/builder/output/terminal.ts rename to pkgs-ts/console/src/form/builder/output/terminal.ts index 7ae6d250..9a59533d 100644 --- a/packages/tui/src/form/builder/output/terminal.ts +++ b/pkgs-ts/console/src/form/builder/output/terminal.ts @@ -1,5 +1,5 @@ -import { clear, title } from '#tui/output'; -import type { FormBuilder } from '#tui/form/builder/index'; +import { clear, title } from '#console/output'; +import type { FormBuilder } from '#console/form/builder/index'; export const clearFormStep = function clearFormStep(this: FormBuilder, name?: string): FormBuilder { return this.addSideEffect(() => clear(), name); diff --git a/packages/tui/src/form/builder/previous.ts b/pkgs-ts/console/src/form/builder/previous.ts similarity index 88% rename from packages/tui/src/form/builder/previous.ts rename to pkgs-ts/console/src/form/builder/previous.ts index 9df58152..1669f9cb 100644 --- a/packages/tui/src/form/builder/previous.ts +++ b/pkgs-ts/console/src/form/builder/previous.ts @@ -1,4 +1,4 @@ -import { parsePreviousArray, parsePreviousBoolean, parsePreviousNumber, parsePreviousString, parsePreviousValue } from '#tui/form/builder/validators/previous'; +import { parsePreviousArray, parsePreviousBoolean, parsePreviousNumber, parsePreviousString, parsePreviousValue } from '#console/form/builder/validators/previous'; export const previousString = (previous: unknown, defaultValue: string): string => { return parsePreviousString(previous, defaultValue); diff --git a/pkgs-ts/console/src/form/builder/prompts.ts b/pkgs-ts/console/src/form/builder/prompts.ts new file mode 100644 index 00000000..38abfda9 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts.ts @@ -0,0 +1,11 @@ +import { basicPromptBuilderMethods } from '#console/form/builder/prompts/basic'; +import { choicePromptBuilderMethods } from '#console/form/builder/prompts/choices'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { PromptBuilderMethods } from '#console/form/builder/prompts/types'; + +export type { PromptBuilderMethods }; + +export const promptBuilderMethods: PromptBuilderMethods & ThisType = { + ...basicPromptBuilderMethods, + ...choicePromptBuilderMethods, +}; diff --git a/packages/tui/src/form/builder/prompts/basic.ts b/pkgs-ts/console/src/form/builder/prompts/basic.ts similarity index 55% rename from packages/tui/src/form/builder/prompts/basic.ts rename to pkgs-ts/console/src/form/builder/prompts/basic.ts index 1713b987..45c120e9 100644 --- a/packages/tui/src/form/builder/prompts/basic.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic.ts @@ -1,6 +1,6 @@ -import { numberFormStep, passwordFormStep, textFormStep, textareaFormStep } from '#tui/form/builder/prompts/basic/index'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { BasicPromptBuilderMethods } from '#tui/form/builder/prompts/types'; +import { numberFormStep, passwordFormStep, textFormStep, textareaFormStep } from '#console/form/builder/prompts/basic/index'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { BasicPromptBuilderMethods } from '#console/form/builder/prompts/types'; export const basicPromptBuilderMethods: BasicPromptBuilderMethods & ThisType = { number: numberFormStep, diff --git a/pkgs-ts/console/src/form/builder/prompts/basic/index.ts b/pkgs-ts/console/src/form/builder/prompts/basic/index.ts new file mode 100644 index 00000000..6843e603 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/basic/index.ts @@ -0,0 +1,4 @@ +export { numberFormStep } from '#console/form/builder/prompts/basic/number'; +export { passwordFormStep } from '#console/form/builder/prompts/basic/password'; +export { textFormStep } from '#console/form/builder/prompts/basic/text'; +export { textareaFormStep } from '#console/form/builder/prompts/basic/textarea'; diff --git a/packages/tui/src/form/builder/prompts/basic/number.ts b/pkgs-ts/console/src/form/builder/prompts/basic/number.ts similarity index 83% rename from packages/tui/src/form/builder/prompts/basic/number.ts rename to pkgs-ts/console/src/form/builder/prompts/basic/number.ts index 9b4c6f6b..24e50b66 100644 --- a/packages/tui/src/form/builder/prompts/basic/number.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic/number.ts @@ -1,8 +1,8 @@ -import { labelNumberOptions } from '#tui/form/builder/prompts/basic/number/options'; -import { runLabelNumberFormStep, runObjectNumberFormStep } from '#tui/form/builder/prompts/basic/number/step'; -import { resolveNumberFormArguments } from '#tui/form/builder/prompts/validators/basic'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { NumberPromptOptions } from '#tui/types'; +import { labelNumberOptions } from '#console/form/builder/prompts/basic/number/options'; +import { runLabelNumberFormStep, runObjectNumberFormStep } from '#console/form/builder/prompts/basic/number/step'; +import { resolveNumberFormArguments } from '#console/form/builder/prompts/validators/basic'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { NumberPromptOptions } from '#console/types'; export function numberFormStep(this: FormBuilder, options: NumberPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/basic/number/defaults.ts b/pkgs-ts/console/src/form/builder/prompts/basic/number/defaults.ts similarity index 66% rename from packages/tui/src/form/builder/prompts/basic/number/defaults.ts rename to pkgs-ts/console/src/form/builder/prompts/basic/number/defaults.ts index c9c9f96b..c19802db 100644 --- a/packages/tui/src/form/builder/prompts/basic/number/defaults.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic/number/defaults.ts @@ -1,7 +1,7 @@ -import { previousNumber } from '#tui/form/builder/previous'; -import { hasPromptDefault } from '#tui/validators/default'; -import { hasPreviousResponse } from '#tui/form/builder/validators/previous'; -import type { NumberPromptOptions } from '#tui/types'; +import { previousNumber } from '#console/form/builder/previous'; +import { hasPromptDefault } from '#console/validators/default'; +import { hasPreviousResponse } from '#console/form/builder/validators/previous'; +import type { NumberPromptOptions } from '#console/types'; export const numberOptionsWithPreviousDefault = (options: NumberPromptOptions, previous: unknown): NumberPromptOptions => { if (hasPreviousResponse(previous)) { diff --git a/packages/tui/src/form/builder/prompts/basic/number/options.ts b/pkgs-ts/console/src/form/builder/prompts/basic/number/options.ts similarity index 80% rename from packages/tui/src/form/builder/prompts/basic/number/options.ts rename to pkgs-ts/console/src/form/builder/prompts/basic/number/options.ts index 98b798d9..8e0426fe 100644 --- a/packages/tui/src/form/builder/prompts/basic/number/options.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic/number/options.ts @@ -1,6 +1,6 @@ -import { previousNumberDefault } from '#tui/form/builder/prompts/basic/number/defaults'; -import { hasPreviousResponse } from '#tui/form/builder/validators/previous'; -import type { NumberPromptOptions } from '#tui/types'; +import { previousNumberDefault } from '#console/form/builder/prompts/basic/number/defaults'; +import { hasPreviousResponse } from '#console/form/builder/validators/previous'; +import type { NumberPromptOptions } from '#console/types'; type LabelNumberOptionsInput = { defaultValue: number | string; diff --git a/packages/tui/src/form/builder/prompts/basic/number/step.ts b/pkgs-ts/console/src/form/builder/prompts/basic/number/step.ts similarity index 60% rename from packages/tui/src/form/builder/prompts/basic/number/step.ts rename to pkgs-ts/console/src/form/builder/prompts/basic/number/step.ts index fa3b8b8b..8b17e540 100644 --- a/packages/tui/src/form/builder/prompts/basic/number/step.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic/number/step.ts @@ -1,6 +1,6 @@ -import { number } from '#tui/prompts/basic'; -import { numberOptionsWithPreviousDefault } from '#tui/form/builder/prompts/basic/number/defaults'; -import type { NumberPromptOptions } from '#tui/types'; +import { number } from '#console/prompts/basic'; +import { numberOptionsWithPreviousDefault } from '#console/form/builder/prompts/basic/number/defaults'; +import type { NumberPromptOptions } from '#console/types'; export const runObjectNumberFormStep = (options: NumberPromptOptions, previous: unknown): Promise => { return number(numberOptionsWithPreviousDefault(options, previous)); diff --git a/packages/tui/src/form/builder/prompts/basic/password.ts b/pkgs-ts/console/src/form/builder/prompts/basic/password.ts similarity index 74% rename from packages/tui/src/form/builder/prompts/basic/password.ts rename to pkgs-ts/console/src/form/builder/prompts/basic/password.ts index 8b4d0ba6..ba9c430a 100644 --- a/packages/tui/src/form/builder/prompts/basic/password.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic/password.ts @@ -1,8 +1,8 @@ -import { password } from '#tui/prompts/basic'; -import { previousString } from '#tui/form/builder/previous'; -import { resolvePasswordFormArguments } from '#tui/form/builder/prompts/validators/basic'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { TextPromptOptions } from '#tui/types'; +import { password } from '#console/prompts/basic'; +import { previousString } from '#console/form/builder/previous'; +import { resolvePasswordFormArguments } from '#console/form/builder/prompts/validators/basic'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { TextPromptOptions } from '#console/types'; export function passwordFormStep(this: FormBuilder, options: TextPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/basic/text.ts b/pkgs-ts/console/src/form/builder/prompts/basic/text.ts similarity index 75% rename from packages/tui/src/form/builder/prompts/basic/text.ts rename to pkgs-ts/console/src/form/builder/prompts/basic/text.ts index d5eb4730..e9992327 100644 --- a/packages/tui/src/form/builder/prompts/basic/text.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic/text.ts @@ -1,8 +1,8 @@ -import { text } from '#tui/prompts/basic'; -import { previousString } from '#tui/form/builder/previous'; -import { resolveTextFormArguments } from '#tui/form/builder/prompts/validators/basic'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { TextPromptOptions } from '#tui/types'; +import { text } from '#console/prompts/basic'; +import { previousString } from '#console/form/builder/previous'; +import { resolveTextFormArguments } from '#console/form/builder/prompts/validators/basic'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { TextPromptOptions } from '#console/types'; export function textFormStep(this: FormBuilder, options: TextPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/basic/textarea.ts b/pkgs-ts/console/src/form/builder/prompts/basic/textarea.ts similarity index 76% rename from packages/tui/src/form/builder/prompts/basic/textarea.ts rename to pkgs-ts/console/src/form/builder/prompts/basic/textarea.ts index dc19f8d3..84e5b1f8 100644 --- a/packages/tui/src/form/builder/prompts/basic/textarea.ts +++ b/pkgs-ts/console/src/form/builder/prompts/basic/textarea.ts @@ -1,8 +1,8 @@ -import { textarea } from '#tui/prompts/basic'; -import { previousString } from '#tui/form/builder/previous'; -import { resolveTextareaFormArguments } from '#tui/form/builder/prompts/validators/basic'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { TextareaPromptOptions } from '#tui/types'; +import { textarea } from '#console/prompts/basic'; +import { previousString } from '#console/form/builder/previous'; +import { resolveTextareaFormArguments } from '#console/form/builder/prompts/validators/basic'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { TextareaPromptOptions } from '#console/types'; export function textareaFormStep(this: FormBuilder, options: TextareaPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/choice/autocomplete.ts b/pkgs-ts/console/src/form/builder/prompts/choice/autocomplete.ts similarity index 74% rename from packages/tui/src/form/builder/prompts/choice/autocomplete.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/autocomplete.ts index 3c93b90b..bf652764 100644 --- a/packages/tui/src/form/builder/prompts/choice/autocomplete.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/autocomplete.ts @@ -1,9 +1,9 @@ -import { autocomplete } from '#tui/prompts/choices'; -import { previousString } from '#tui/form/builder/previous'; -import { resolveAutocompleteFormArguments } from '#tui/form/builder/prompts/validators/suggest'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { SuggestOptions } from '#tui/prompts/choices'; -import type { TextPromptOptions } from '#tui/types'; +import { autocomplete } from '#console/prompts/choices'; +import { previousString } from '#console/form/builder/previous'; +import { resolveAutocompleteFormArguments } from '#console/form/builder/prompts/validators/suggest'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { SuggestOptions } from '#console/prompts/choices'; +import type { TextPromptOptions } from '#console/types'; export function autocompleteFormStep(this: FormBuilder, options: SuggestOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/choice/confirm.ts b/pkgs-ts/console/src/form/builder/prompts/choice/confirm.ts similarity index 76% rename from packages/tui/src/form/builder/prompts/choice/confirm.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/confirm.ts index 20ef2295..9c70fbbc 100644 --- a/packages/tui/src/form/builder/prompts/choice/confirm.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/confirm.ts @@ -1,8 +1,8 @@ -import { confirm } from '#tui/prompts/choices'; -import { previousBoolean } from '#tui/form/builder/previous'; -import { resolveConfirmFormArguments } from '#tui/form/builder/prompts/validators/select'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { ConfirmPromptOptions } from '#tui/types'; +import { confirm } from '#console/prompts/choices'; +import { previousBoolean } from '#console/form/builder/previous'; +import { resolveConfirmFormArguments } from '#console/form/builder/prompts/validators/select'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { ConfirmPromptOptions } from '#console/types'; export function confirmFormStep(this: FormBuilder, options: ConfirmPromptOptions, name?: string): FormBuilder; diff --git a/pkgs-ts/console/src/form/builder/prompts/choice/index.ts b/pkgs-ts/console/src/form/builder/prompts/choice/index.ts new file mode 100644 index 00000000..efb28387 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/choice/index.ts @@ -0,0 +1,8 @@ +export { autocompleteFormStep } from '#console/form/builder/prompts/choice/autocomplete'; +export { confirmFormStep } from '#console/form/builder/prompts/choice/confirm'; +export { multisearchFormStep } from '#console/form/builder/prompts/choice/multisearch'; +export { multiselectFormStep } from '#console/form/builder/prompts/choice/multiselect'; +export { pauseFormStep } from '#console/form/builder/prompts/choice/pause'; +export { searchFormStep } from '#console/form/builder/prompts/choice/search'; +export { selectFormStep } from '#console/form/builder/prompts/choice/select'; +export { suggestFormStep } from '#console/form/builder/prompts/choice/suggest'; diff --git a/packages/tui/src/form/builder/prompts/choice/multisearch.ts b/pkgs-ts/console/src/form/builder/prompts/choice/multisearch.ts similarity index 79% rename from packages/tui/src/form/builder/prompts/choice/multisearch.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/multisearch.ts index a9ade6e3..ed36f38a 100644 --- a/packages/tui/src/form/builder/prompts/choice/multisearch.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/multisearch.ts @@ -1,8 +1,8 @@ -import { multisearch } from '#tui/prompts/choices'; -import { previousArray } from '#tui/form/builder/previous'; -import { resolveMultiSearchFormArguments } from '#tui/form/builder/prompts/validators/search'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { MultiSearchPromptOptions } from '#tui/types'; +import { multisearch } from '#console/prompts/choices'; +import { previousArray } from '#console/form/builder/previous'; +import { resolveMultiSearchFormArguments } from '#console/form/builder/prompts/validators/search'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { MultiSearchPromptOptions } from '#console/types'; export function multisearchFormStep(this: FormBuilder, options: MultiSearchPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/choice/multiselect.ts b/pkgs-ts/console/src/form/builder/prompts/choice/multiselect.ts similarity index 78% rename from packages/tui/src/form/builder/prompts/choice/multiselect.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/multiselect.ts index 372e43ae..b27b10f7 100644 --- a/packages/tui/src/form/builder/prompts/choice/multiselect.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/multiselect.ts @@ -1,8 +1,8 @@ -import { multiselect } from '#tui/prompts/choices'; -import { previousArray } from '#tui/form/builder/previous'; -import { resolveMultiSelectFormArguments } from '#tui/form/builder/prompts/validators/select'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { ChoiceOptions, MultiSelectPromptOptions } from '#tui/types'; +import { multiselect } from '#console/prompts/choices'; +import { previousArray } from '#console/form/builder/previous'; +import { resolveMultiSelectFormArguments } from '#console/form/builder/prompts/validators/select'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { ChoiceOptions, MultiSelectPromptOptions } from '#console/types'; export function multiselectFormStep(this: FormBuilder, options: MultiSelectPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/choice/pause.ts b/pkgs-ts/console/src/form/builder/prompts/choice/pause.ts similarity index 62% rename from packages/tui/src/form/builder/prompts/choice/pause.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/pause.ts index d56165b6..87d1cb3c 100644 --- a/packages/tui/src/form/builder/prompts/choice/pause.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/pause.ts @@ -1,5 +1,5 @@ -import { pause } from '#tui/prompts/choices'; -import type { FormBuilder } from '#tui/form/builder/index'; +import { pause } from '#console/prompts/choices'; +import type { FormBuilder } from '#console/form/builder/index'; export const pauseFormStep = function pauseFormStep(this: FormBuilder, message = 'Press enter to continue...', name?: string): FormBuilder { return this.add(() => pause(message), name); diff --git a/packages/tui/src/form/builder/prompts/choice/search.ts b/pkgs-ts/console/src/form/builder/prompts/choice/search.ts similarity index 79% rename from packages/tui/src/form/builder/prompts/choice/search.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/search.ts index c4087278..a7477752 100644 --- a/packages/tui/src/form/builder/prompts/choice/search.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/search.ts @@ -1,8 +1,8 @@ -import { search } from '#tui/prompts/choices'; -import { previousValue } from '#tui/form/builder/previous'; -import { resolveSearchFormArguments } from '#tui/form/builder/prompts/validators/search'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { SearchPromptOptions } from '#tui/types'; +import { search } from '#console/prompts/choices'; +import { previousValue } from '#console/form/builder/previous'; +import { resolveSearchFormArguments } from '#console/form/builder/prompts/validators/search'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { SearchPromptOptions } from '#console/types'; export function searchFormStep(this: FormBuilder, options: SearchPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/choice/select.ts b/pkgs-ts/console/src/form/builder/prompts/choice/select.ts similarity index 77% rename from packages/tui/src/form/builder/prompts/choice/select.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/select.ts index 3e06ad10..a32f3cb3 100644 --- a/packages/tui/src/form/builder/prompts/choice/select.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/select.ts @@ -1,8 +1,8 @@ -import { select } from '#tui/prompts/choices'; -import { previousValue } from '#tui/form/builder/previous'; -import { resolveSelectFormArguments } from '#tui/form/builder/prompts/validators/select'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { ChoiceOptions, SelectPromptOptions } from '#tui/types'; +import { select } from '#console/prompts/choices'; +import { previousValue } from '#console/form/builder/previous'; +import { resolveSelectFormArguments } from '#console/form/builder/prompts/validators/select'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { ChoiceOptions, SelectPromptOptions } from '#console/types'; export function selectFormStep(this: FormBuilder, options: SelectPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/choice/suggest.ts b/pkgs-ts/console/src/form/builder/prompts/choice/suggest.ts similarity index 75% rename from packages/tui/src/form/builder/prompts/choice/suggest.ts rename to pkgs-ts/console/src/form/builder/prompts/choice/suggest.ts index 5ad47066..909790ef 100644 --- a/packages/tui/src/form/builder/prompts/choice/suggest.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choice/suggest.ts @@ -1,9 +1,9 @@ -import { suggest } from '#tui/prompts/choices'; -import { previousString } from '#tui/form/builder/previous'; -import { resolveSuggestFormArguments } from '#tui/form/builder/prompts/validators/suggest'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { SuggestOptions } from '#tui/prompts/choices'; -import type { TextPromptOptions } from '#tui/types'; +import { suggest } from '#console/prompts/choices'; +import { previousString } from '#console/form/builder/previous'; +import { resolveSuggestFormArguments } from '#console/form/builder/prompts/validators/suggest'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { SuggestOptions } from '#console/prompts/choices'; +import type { TextPromptOptions } from '#console/types'; export function suggestFormStep(this: FormBuilder, options: SuggestOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/choices.ts b/pkgs-ts/console/src/form/builder/prompts/choices.ts similarity index 70% rename from packages/tui/src/form/builder/prompts/choices.ts rename to pkgs-ts/console/src/form/builder/prompts/choices.ts index 7cb9be43..cc57125e 100644 --- a/packages/tui/src/form/builder/prompts/choices.ts +++ b/pkgs-ts/console/src/form/builder/prompts/choices.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { ChoicePromptBuilderMethods } from '#tui/form/builder/prompts/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { ChoicePromptBuilderMethods } from '#console/form/builder/prompts/types'; import { autocompleteFormStep, @@ -10,7 +10,7 @@ import { searchFormStep, selectFormStep, suggestFormStep, -} from '#tui/form/builder/prompts/choice/index'; +} from '#console/form/builder/prompts/choice/index'; export const choicePromptBuilderMethods: ChoicePromptBuilderMethods & ThisType = { autocomplete: autocompleteFormStep, diff --git a/packages/tui/src/form/builder/prompts/contracts/basic.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/basic.ts similarity index 91% rename from packages/tui/src/form/builder/prompts/contracts/basic.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/basic.ts index 46f27a1f..a41fa5e0 100644 --- a/packages/tui/src/form/builder/prompts/contracts/basic.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/basic.ts @@ -1,6 +1,6 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { NumberPromptOptions, TextareaPromptOptions, TextPromptOptions } from '#tui/types'; -import type { MaybePromise } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { NumberPromptOptions, TextareaPromptOptions, TextPromptOptions } from '#console/types'; +import type { MaybePromise } from '#console/types'; export type BasicPromptBuilderMethods = { number(this: FormBuilder, options: NumberPromptOptions, name?: string): FormBuilder; diff --git a/pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts new file mode 100644 index 00000000..6420f3ae --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices.ts @@ -0,0 +1,17 @@ +import type { AutocompletePromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/autocomplete'; +import type { ConfirmPromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/confirm'; +import type { MultiSearchPromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/multisearch'; +import type { MultiSelectPromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/multiselect'; +import type { PausePromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/pause'; +import type { SearchPromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/search'; +import type { SelectPromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/select'; +import type { SuggestPromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices/suggest'; + +export type ChoicePromptBuilderMethods = AutocompletePromptBuilderMethods & + ConfirmPromptBuilderMethods & + MultiSearchPromptBuilderMethods & + MultiSelectPromptBuilderMethods & + PausePromptBuilderMethods & + SearchPromptBuilderMethods & + SelectPromptBuilderMethods & + SuggestPromptBuilderMethods; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/autocomplete.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/autocomplete.ts similarity index 72% rename from packages/tui/src/form/builder/prompts/contracts/choices/autocomplete.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/autocomplete.ts index ccb7c424..d3f31b51 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/autocomplete.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/autocomplete.ts @@ -1,6 +1,6 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { SuggestOptions } from '#tui/prompts/choices'; -import type { TextPromptOptions } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { SuggestOptions } from '#console/prompts/choices'; +import type { TextPromptOptions } from '#console/types'; export type AutocompletePromptBuilderMethods = { autocomplete(this: FormBuilder, options: SuggestOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/confirm.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/confirm.ts similarity index 76% rename from packages/tui/src/form/builder/prompts/contracts/choices/confirm.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/confirm.ts index 52c2df09..b0fd62fe 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/confirm.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/confirm.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { ConfirmPromptOptions, MaybePromise } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { ConfirmPromptOptions, MaybePromise } from '#console/types'; export type ConfirmPromptBuilderMethods = { confirm(this: FormBuilder, options: ConfirmPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/multisearch.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/multisearch.ts similarity index 81% rename from packages/tui/src/form/builder/prompts/contracts/choices/multisearch.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/multisearch.ts index 04f78ea5..9d940fd4 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/multisearch.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/multisearch.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { MultiSearchPromptOptions } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { MultiSearchPromptOptions } from '#console/types'; export type MultiSearchPromptBuilderMethods = { multisearch(this: FormBuilder, options: MultiSearchPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/multiselect.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/multiselect.ts similarity index 86% rename from packages/tui/src/form/builder/prompts/contracts/choices/multiselect.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/multiselect.ts index cdccf478..5d8e46d8 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/multiselect.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/multiselect.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { ChoiceOptions, MaybePromise, MultiSelectPromptOptions } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { ChoiceOptions, MaybePromise, MultiSelectPromptOptions } from '#console/types'; export type MultiSelectPromptBuilderMethods = { multiselect(this: FormBuilder, options: MultiSelectPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/pause.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/pause.ts similarity index 65% rename from packages/tui/src/form/builder/prompts/contracts/choices/pause.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/pause.ts index 679a9d4f..64c441d5 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/pause.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/pause.ts @@ -1,4 +1,4 @@ -import type { FormBuilder } from '#tui/form/builder/index'; +import type { FormBuilder } from '#console/form/builder/index'; export type PausePromptBuilderMethods = { pause(this: FormBuilder, message?: string, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/search.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/search.ts similarity index 80% rename from packages/tui/src/form/builder/prompts/contracts/choices/search.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/search.ts index ff855f9f..fbbe4d90 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/search.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/search.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { SearchPromptOptions } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { SearchPromptOptions } from '#console/types'; export type SearchPromptBuilderMethods = { search(this: FormBuilder, options: SearchPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/select.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/select.ts similarity index 86% rename from packages/tui/src/form/builder/prompts/contracts/choices/select.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/select.ts index f76ebc02..d894c24a 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/select.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/select.ts @@ -1,5 +1,5 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { ChoiceOptions, MaybePromise, SelectPromptOptions } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { ChoiceOptions, MaybePromise, SelectPromptOptions } from '#console/types'; export type SelectPromptBuilderMethods = { select(this: FormBuilder, options: SelectPromptOptions, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/prompts/contracts/choices/suggest.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/suggest.ts similarity index 72% rename from packages/tui/src/form/builder/prompts/contracts/choices/suggest.ts rename to pkgs-ts/console/src/form/builder/prompts/contracts/choices/suggest.ts index 3760d9b6..03be03c2 100644 --- a/packages/tui/src/form/builder/prompts/contracts/choices/suggest.ts +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/choices/suggest.ts @@ -1,6 +1,6 @@ -import type { FormBuilder } from '#tui/form/builder/index'; -import type { SuggestOptions } from '#tui/prompts/choices'; -import type { TextPromptOptions } from '#tui/types'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { SuggestOptions } from '#console/prompts/choices'; +import type { TextPromptOptions } from '#console/types'; export type SuggestPromptBuilderMethods = { suggest(this: FormBuilder, options: SuggestOptions, name?: string): FormBuilder; diff --git a/pkgs-ts/console/src/form/builder/prompts/contracts/index.ts b/pkgs-ts/console/src/form/builder/prompts/contracts/index.ts new file mode 100644 index 00000000..6eb93c7f --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/contracts/index.ts @@ -0,0 +1,4 @@ +import type { BasicPromptBuilderMethods } from '#console/form/builder/prompts/contracts/basic'; +import type { ChoicePromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices'; + +export type PromptBuilderMethods = BasicPromptBuilderMethods & ChoicePromptBuilderMethods; diff --git a/pkgs-ts/console/src/form/builder/prompts/types.ts b/pkgs-ts/console/src/form/builder/prompts/types.ts new file mode 100644 index 00000000..2297ac95 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/types.ts @@ -0,0 +1,3 @@ +export type { BasicPromptBuilderMethods } from '#console/form/builder/prompts/contracts/basic'; +export type { ChoicePromptBuilderMethods } from '#console/form/builder/prompts/contracts/choices'; +export type { PromptBuilderMethods } from '#console/form/builder/prompts/contracts/index'; diff --git a/packages/tui/src/form/builder/prompts/validators/basic-label.ts b/pkgs-ts/console/src/form/builder/prompts/validators/basic-label.ts similarity index 100% rename from packages/tui/src/form/builder/prompts/validators/basic-label.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/basic-label.ts diff --git a/packages/tui/src/form/builder/prompts/validators/basic-number.ts b/pkgs-ts/console/src/form/builder/prompts/validators/basic-number.ts similarity index 91% rename from packages/tui/src/form/builder/prompts/validators/basic-number.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/basic-number.ts index 955535c3..8753f58e 100644 --- a/packages/tui/src/form/builder/prompts/validators/basic-number.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/basic-number.ts @@ -1,5 +1,5 @@ -import { isBasicPromptLabel, isBasicPromptOptions, parseBasicStepName } from '#tui/form/builder/prompts/validators/basic-label'; -import type { NumberPromptOptions } from '#tui/types'; +import { isBasicPromptLabel, isBasicPromptOptions, parseBasicStepName } from '#console/form/builder/prompts/validators/basic-label'; +import type { NumberPromptOptions } from '#console/types'; export type ResolvedNumberFormArguments = | { diff --git a/packages/tui/src/form/builder/prompts/validators/basic-text.ts b/pkgs-ts/console/src/form/builder/prompts/validators/basic-text.ts similarity index 89% rename from packages/tui/src/form/builder/prompts/validators/basic-text.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/basic-text.ts index 5d8d855f..68890db1 100644 --- a/packages/tui/src/form/builder/prompts/validators/basic-text.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/basic-text.ts @@ -1,5 +1,5 @@ -import { isBasicPromptOptions, parseBasicStepName } from '#tui/form/builder/prompts/validators/basic-label'; -import type { TextPromptOptions } from '#tui/types'; +import { isBasicPromptOptions, parseBasicStepName } from '#console/form/builder/prompts/validators/basic-label'; +import type { TextPromptOptions } from '#console/types'; export type ResolvedTextFormArguments = { name?: string; diff --git a/packages/tui/src/form/builder/prompts/validators/basic-textarea.ts b/pkgs-ts/console/src/form/builder/prompts/validators/basic-textarea.ts similarity index 82% rename from packages/tui/src/form/builder/prompts/validators/basic-textarea.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/basic-textarea.ts index dea0b4ab..fc2c5b2a 100644 --- a/packages/tui/src/form/builder/prompts/validators/basic-textarea.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/basic-textarea.ts @@ -1,5 +1,5 @@ -import { isBasicPromptOptions, parseBasicStepName } from '#tui/form/builder/prompts/validators/basic-label'; -import type { TextareaPromptOptions } from '#tui/types'; +import { isBasicPromptOptions, parseBasicStepName } from '#console/form/builder/prompts/validators/basic-label'; +import type { TextareaPromptOptions } from '#console/types'; export type ResolvedTextareaFormArguments = { name?: string; diff --git a/pkgs-ts/console/src/form/builder/prompts/validators/basic.ts b/pkgs-ts/console/src/form/builder/prompts/validators/basic.ts new file mode 100644 index 00000000..1b2eb3e9 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/validators/basic.ts @@ -0,0 +1,7 @@ +export { isBasicPromptLabel, isBasicPromptOptions, parseBasicStepName } from '#console/form/builder/prompts/validators/basic-label'; +export { resolveNumberFormArguments } from '#console/form/builder/prompts/validators/basic-number'; +export type { ResolvedNumberFormArguments } from '#console/form/builder/prompts/validators/basic-number'; +export { resolvePasswordFormArguments, resolveTextFormArguments } from '#console/form/builder/prompts/validators/basic-text'; +export type { ResolvedTextFormArguments } from '#console/form/builder/prompts/validators/basic-text'; +export { resolveTextareaFormArguments } from '#console/form/builder/prompts/validators/basic-textarea'; +export type { ResolvedTextareaFormArguments } from '#console/form/builder/prompts/validators/basic-textarea'; diff --git a/pkgs-ts/console/src/form/builder/prompts/validators/search.ts b/pkgs-ts/console/src/form/builder/prompts/validators/search.ts new file mode 100644 index 00000000..b68e8c12 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/validators/search.ts @@ -0,0 +1,6 @@ +export { isSearchPromptLabel, isSearchPromptOptions, parseSearchChoiceSource, parseSearchStepName } from '#console/form/builder/prompts/validators/search/common'; +export type { SearchChoiceSourceCallback } from '#console/form/builder/prompts/validators/search/common'; +export { resolveMultiSearchFormArguments } from '#console/form/builder/prompts/validators/search/multisearch'; +export type { ResolvedMultiSearchFormArguments } from '#console/form/builder/prompts/validators/search/multisearch'; +export { resolveSearchFormArguments } from '#console/form/builder/prompts/validators/search/search'; +export type { ResolvedSearchFormArguments } from '#console/form/builder/prompts/validators/search/search'; diff --git a/packages/tui/src/form/builder/prompts/validators/search/common.ts b/pkgs-ts/console/src/form/builder/prompts/validators/search/common.ts similarity index 85% rename from packages/tui/src/form/builder/prompts/validators/search/common.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/search/common.ts index 0befbd99..db4a41a4 100644 --- a/packages/tui/src/form/builder/prompts/validators/search/common.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/search/common.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; -import { choiceOptionsSchema } from '#tui/concerns/validators/choice'; -import { functionSchema } from '#tui/validators/function'; -import type { ChoiceOptions, MaybePromise } from '#tui/types'; +import { choiceOptionsSchema } from '#console/concerns/validators/choice'; +import { functionSchema } from '#console/validators/function'; +import type { ChoiceOptions, MaybePromise } from '#console/types'; export type SearchChoiceSourceCallback = (query: string) => MaybePromise>; diff --git a/packages/tui/src/form/builder/prompts/validators/search/multisearch.ts b/pkgs-ts/console/src/form/builder/prompts/validators/search/multisearch.ts similarity index 88% rename from packages/tui/src/form/builder/prompts/validators/search/multisearch.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/search/multisearch.ts index a1b93cf5..6a65d3a9 100644 --- a/packages/tui/src/form/builder/prompts/validators/search/multisearch.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/search/multisearch.ts @@ -1,5 +1,5 @@ -import { isSearchPromptOptions, parseSearchChoiceSource, parseSearchStepName } from '#tui/form/builder/prompts/validators/search/common'; -import type { MultiSearchPromptOptions } from '#tui/types'; +import { isSearchPromptOptions, parseSearchChoiceSource, parseSearchStepName } from '#console/form/builder/prompts/validators/search/common'; +import type { MultiSearchPromptOptions } from '#console/types'; export type ResolvedMultiSearchFormArguments = { name?: string; diff --git a/packages/tui/src/form/builder/prompts/validators/search/search.ts b/pkgs-ts/console/src/form/builder/prompts/validators/search/search.ts similarity index 88% rename from packages/tui/src/form/builder/prompts/validators/search/search.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/search/search.ts index 8aee2cde..cdb3fdeb 100644 --- a/packages/tui/src/form/builder/prompts/validators/search/search.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/search/search.ts @@ -1,5 +1,5 @@ -import { isSearchPromptOptions, parseSearchChoiceSource, parseSearchStepName } from '#tui/form/builder/prompts/validators/search/common'; -import type { SearchPromptOptions } from '#tui/types'; +import { isSearchPromptOptions, parseSearchChoiceSource, parseSearchStepName } from '#console/form/builder/prompts/validators/search/common'; +import type { SearchPromptOptions } from '#console/types'; export type ResolvedSearchFormArguments = { name?: string; diff --git a/pkgs-ts/console/src/form/builder/prompts/validators/select.ts b/pkgs-ts/console/src/form/builder/prompts/validators/select.ts new file mode 100644 index 00000000..43f4cab6 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/validators/select.ts @@ -0,0 +1,7 @@ +export { isSelectPromptLabel, isSelectPromptOptions, parseConfirmDefault, parseSelectChoiceOptions, parseSelectStepName } from '#console/form/builder/prompts/validators/select/common'; +export { resolveConfirmFormArguments } from '#console/form/builder/prompts/validators/select/confirm'; +export type { ResolvedConfirmFormArguments } from '#console/form/builder/prompts/validators/select/confirm'; +export { resolveMultiSelectFormArguments } from '#console/form/builder/prompts/validators/select/multiselect'; +export type { ResolvedMultiSelectFormArguments } from '#console/form/builder/prompts/validators/select/multiselect'; +export { resolveSelectFormArguments } from '#console/form/builder/prompts/validators/select/select'; +export type { ResolvedSelectFormArguments } from '#console/form/builder/prompts/validators/select/select'; diff --git a/packages/tui/src/form/builder/prompts/validators/select/common.ts b/pkgs-ts/console/src/form/builder/prompts/validators/select/common.ts similarity index 89% rename from packages/tui/src/form/builder/prompts/validators/select/common.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/select/common.ts index 6efa49ef..cc98ca3c 100644 --- a/packages/tui/src/form/builder/prompts/validators/select/common.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/select/common.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { choiceOptionsSchema } from '#tui/concerns/validators/choice'; -import type { ChoiceOptions } from '#tui/types'; +import { choiceOptionsSchema } from '#console/concerns/validators/choice'; +import type { ChoiceOptions } from '#console/types'; const selectPromptLabelSchema = z.string(); const selectPromptDefaultSchema = z.boolean(); diff --git a/packages/tui/src/form/builder/prompts/validators/select/confirm.ts b/pkgs-ts/console/src/form/builder/prompts/validators/select/confirm.ts similarity index 87% rename from packages/tui/src/form/builder/prompts/validators/select/confirm.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/select/confirm.ts index 947cf4ec..aa33a37e 100644 --- a/packages/tui/src/form/builder/prompts/validators/select/confirm.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/select/confirm.ts @@ -1,5 +1,5 @@ -import { isSelectPromptOptions, parseConfirmDefault, parseSelectStepName } from '#tui/form/builder/prompts/validators/select/common'; -import type { ConfirmPromptOptions } from '#tui/types'; +import { isSelectPromptOptions, parseConfirmDefault, parseSelectStepName } from '#console/form/builder/prompts/validators/select/common'; +import type { ConfirmPromptOptions } from '#console/types'; export type ResolvedConfirmFormArguments = { name?: string; diff --git a/packages/tui/src/form/builder/prompts/validators/select/multiselect.ts b/pkgs-ts/console/src/form/builder/prompts/validators/select/multiselect.ts similarity index 86% rename from packages/tui/src/form/builder/prompts/validators/select/multiselect.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/select/multiselect.ts index 21f68065..ffda8d82 100644 --- a/packages/tui/src/form/builder/prompts/validators/select/multiselect.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/select/multiselect.ts @@ -1,5 +1,5 @@ -import { isSelectPromptOptions, parseSelectChoiceOptions, parseSelectStepName } from '#tui/form/builder/prompts/validators/select/common'; -import type { ChoiceOptions, MultiSelectPromptOptions } from '#tui/types'; +import { isSelectPromptOptions, parseSelectChoiceOptions, parseSelectStepName } from '#console/form/builder/prompts/validators/select/common'; +import type { ChoiceOptions, MultiSelectPromptOptions } from '#console/types'; export type ResolvedMultiSelectFormArguments = { name?: string; diff --git a/packages/tui/src/form/builder/prompts/validators/select/select.ts b/pkgs-ts/console/src/form/builder/prompts/validators/select/select.ts similarity index 86% rename from packages/tui/src/form/builder/prompts/validators/select/select.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/select/select.ts index bbbe9c89..08d6d9ab 100644 --- a/packages/tui/src/form/builder/prompts/validators/select/select.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/select/select.ts @@ -1,5 +1,5 @@ -import { isSelectPromptOptions, parseSelectChoiceOptions, parseSelectStepName } from '#tui/form/builder/prompts/validators/select/common'; -import type { ChoiceOptions, SelectPromptOptions } from '#tui/types'; +import { isSelectPromptOptions, parseSelectChoiceOptions, parseSelectStepName } from '#console/form/builder/prompts/validators/select/common'; +import type { ChoiceOptions, SelectPromptOptions } from '#console/types'; export type ResolvedSelectFormArguments = { name?: string; diff --git a/pkgs-ts/console/src/form/builder/prompts/validators/suggest.ts b/pkgs-ts/console/src/form/builder/prompts/validators/suggest.ts new file mode 100644 index 00000000..4f511e51 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/prompts/validators/suggest.ts @@ -0,0 +1,6 @@ +export { resolveAutocompleteFormArguments } from '#console/form/builder/prompts/validators/suggest/autocomplete'; +export type { ResolvedAutocompleteFormArguments } from '#console/form/builder/prompts/validators/suggest/autocomplete'; +export { isSuggestPromptLabel, isSuggestPromptOptions, parseSuggestSource, parseSuggestStepName } from '#console/form/builder/prompts/validators/suggest/common'; +export type { SuggestSourceCallback } from '#console/form/builder/prompts/validators/suggest/common'; +export { resolveSuggestFormArguments } from '#console/form/builder/prompts/validators/suggest/suggest'; +export type { ResolvedSuggestFormArguments } from '#console/form/builder/prompts/validators/suggest/suggest'; diff --git a/packages/tui/src/form/builder/prompts/validators/suggest/autocomplete.ts b/pkgs-ts/console/src/form/builder/prompts/validators/suggest/autocomplete.ts similarity index 82% rename from packages/tui/src/form/builder/prompts/validators/suggest/autocomplete.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/suggest/autocomplete.ts index 8f9b2327..b6f77389 100644 --- a/packages/tui/src/form/builder/prompts/validators/suggest/autocomplete.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/suggest/autocomplete.ts @@ -1,6 +1,6 @@ -import { isSuggestPromptOptions, parseSuggestSource, parseSuggestStepName } from '#tui/form/builder/prompts/validators/suggest/common'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TextPromptOptions } from '#tui/types'; +import { isSuggestPromptOptions, parseSuggestSource, parseSuggestStepName } from '#console/form/builder/prompts/validators/suggest/common'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TextPromptOptions } from '#console/types'; export type ResolvedAutocompleteFormArguments = { name?: string; diff --git a/packages/tui/src/form/builder/prompts/validators/suggest/common.ts b/pkgs-ts/console/src/form/builder/prompts/validators/suggest/common.ts similarity index 90% rename from packages/tui/src/form/builder/prompts/validators/suggest/common.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/suggest/common.ts index 9e3231f3..09b36767 100644 --- a/packages/tui/src/form/builder/prompts/validators/suggest/common.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/suggest/common.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; -import type { MaybePromise } from '#tui/types'; +import { functionSchema } from '#console/validators/function'; +import type { MaybePromise } from '#console/types'; export type SuggestSourceCallback = (query: string) => MaybePromise; diff --git a/packages/tui/src/form/builder/prompts/validators/suggest/suggest.ts b/pkgs-ts/console/src/form/builder/prompts/validators/suggest/suggest.ts similarity index 82% rename from packages/tui/src/form/builder/prompts/validators/suggest/suggest.ts rename to pkgs-ts/console/src/form/builder/prompts/validators/suggest/suggest.ts index f7af1779..8c33c0a5 100644 --- a/packages/tui/src/form/builder/prompts/validators/suggest/suggest.ts +++ b/pkgs-ts/console/src/form/builder/prompts/validators/suggest/suggest.ts @@ -1,6 +1,6 @@ -import { isSuggestPromptOptions, parseSuggestSource, parseSuggestStepName } from '#tui/form/builder/prompts/validators/suggest/common'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TextPromptOptions } from '#tui/types'; +import { isSuggestPromptOptions, parseSuggestSource, parseSuggestStepName } from '#console/form/builder/prompts/validators/suggest/common'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TextPromptOptions } from '#console/types'; export type ResolvedSuggestFormArguments = { name?: string; diff --git a/packages/tui/src/form/builder/responses.ts b/pkgs-ts/console/src/form/builder/responses.ts similarity index 75% rename from packages/tui/src/form/builder/responses.ts rename to pkgs-ts/console/src/form/builder/responses.ts index ff83a1c5..2da93638 100644 --- a/packages/tui/src/form/builder/responses.ts +++ b/pkgs-ts/console/src/form/builder/responses.ts @@ -1,4 +1,4 @@ -import type { FormResponses } from '#tui/form/types'; +import type { FormResponses } from '#console/form/types'; class FormResponseList extends Array implements FormResponses { [name: string]: unknown; diff --git a/packages/tui/src/form/builder/revert.ts b/pkgs-ts/console/src/form/builder/revert.ts similarity index 76% rename from packages/tui/src/form/builder/revert.ts rename to pkgs-ts/console/src/form/builder/revert.ts index 739114f7..61048c4d 100644 --- a/packages/tui/src/form/builder/revert.ts +++ b/pkgs-ts/console/src/form/builder/revert.ts @@ -1,7 +1,7 @@ -import { promptEnvironment, withPromptEnvironment } from '#tui/environment'; -import { Key } from '#tui/key'; -import { rejectPromptRevert } from '#tui/prompt/revert'; -import type { MaybePromise, PromptInput } from '#tui/types'; +import { promptEnvironment, withPromptEnvironment } from '#console/environment'; +import { Key } from '#console/key'; +import { rejectPromptRevert } from '#console/prompt/revert'; +import type { MaybePromise, PromptInput } from '#console/types'; export class FormRevertedError extends Error { constructor() { diff --git a/packages/tui/src/form/builder/status.ts b/pkgs-ts/console/src/form/builder/status.ts similarity index 83% rename from packages/tui/src/form/builder/status.ts rename to pkgs-ts/console/src/form/builder/status.ts index 37ff4439..a94fa562 100644 --- a/packages/tui/src/form/builder/status.ts +++ b/pkgs-ts/console/src/form/builder/status.ts @@ -1,7 +1,7 @@ -import { progressFormStep, spinFormStep, streamFormStep, taskFormStep } from '#tui/form/builder/status/index'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { MaybePromise } from '#tui/types'; -import type { Logger, Progress, TaskDefinition } from '#tui/status'; +import { progressFormStep, spinFormStep, streamFormStep, taskFormStep } from '#console/form/builder/status/index'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { MaybePromise } from '#console/types'; +import type { Logger, Progress, TaskDefinition } from '#console/status'; export type StatusBuilderMethods = { progress(this: FormBuilder, total: number, message?: string, name?: string): FormBuilder; diff --git a/pkgs-ts/console/src/form/builder/status/index.ts b/pkgs-ts/console/src/form/builder/status/index.ts new file mode 100644 index 00000000..6324f6ec --- /dev/null +++ b/pkgs-ts/console/src/form/builder/status/index.ts @@ -0,0 +1,4 @@ +export { progressFormStep } from '#console/form/builder/status/progress'; +export { spinFormStep } from '#console/form/builder/status/spin'; +export { streamFormStep } from '#console/form/builder/status/stream'; +export { taskFormStep } from '#console/form/builder/status/task'; diff --git a/packages/tui/src/form/builder/status/progress.ts b/pkgs-ts/console/src/form/builder/status/progress.ts similarity index 77% rename from packages/tui/src/form/builder/status/progress.ts rename to pkgs-ts/console/src/form/builder/status/progress.ts index 64915bd6..d64cf6e7 100644 --- a/packages/tui/src/form/builder/status/progress.ts +++ b/pkgs-ts/console/src/form/builder/status/progress.ts @@ -1,8 +1,8 @@ -import { progress } from '#tui/status'; -import { resolveProgressFormArguments } from '#tui/form/builder/validators/status'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { MaybePromise } from '#tui/types'; -import type { Progress } from '#tui/status'; +import { progress } from '#console/status'; +import { resolveProgressFormArguments } from '#console/form/builder/validators/status'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { MaybePromise } from '#console/types'; +import type { Progress } from '#console/status'; export function progressFormStep(this: FormBuilder, total: number, message?: string, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/status/spin.ts b/pkgs-ts/console/src/form/builder/status/spin.ts similarity index 76% rename from packages/tui/src/form/builder/status/spin.ts rename to pkgs-ts/console/src/form/builder/status/spin.ts index 20d25120..af8813a2 100644 --- a/packages/tui/src/form/builder/status/spin.ts +++ b/pkgs-ts/console/src/form/builder/status/spin.ts @@ -1,7 +1,7 @@ -import { spin } from '#tui/status'; -import { resolveSpinFormArguments } from '#tui/form/builder/validators/status'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { MaybePromise } from '#tui/types'; +import { spin } from '#console/status'; +import { resolveSpinFormArguments } from '#console/form/builder/validators/status'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { MaybePromise } from '#console/types'; export function spinFormStep(this: FormBuilder, callback: () => MaybePromise, message?: string, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/status/stream.ts b/pkgs-ts/console/src/form/builder/status/stream.ts similarity index 77% rename from packages/tui/src/form/builder/status/stream.ts rename to pkgs-ts/console/src/form/builder/status/stream.ts index 5892bca3..d951c416 100644 --- a/packages/tui/src/form/builder/status/stream.ts +++ b/pkgs-ts/console/src/form/builder/status/stream.ts @@ -1,6 +1,6 @@ -import { stream } from '#tui/status'; -import { resolveStreamFormArguments } from '#tui/form/builder/validators/status'; -import type { FormBuilder } from '#tui/form/builder/index'; +import { stream } from '#console/status'; +import { resolveStreamFormArguments } from '#console/form/builder/validators/status'; +import type { FormBuilder } from '#console/form/builder/index'; export function streamFormStep(this: FormBuilder, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/status/task.ts b/pkgs-ts/console/src/form/builder/status/task.ts similarity index 75% rename from packages/tui/src/form/builder/status/task.ts rename to pkgs-ts/console/src/form/builder/status/task.ts index 637f0127..ad0bfe01 100644 --- a/packages/tui/src/form/builder/status/task.ts +++ b/pkgs-ts/console/src/form/builder/status/task.ts @@ -1,8 +1,8 @@ -import { task } from '#tui/status'; -import { resolveTaskFormArguments } from '#tui/form/builder/validators/status'; -import type { FormBuilder } from '#tui/form/builder/index'; -import type { MaybePromise } from '#tui/types'; -import type { Logger, TaskDefinition } from '#tui/status'; +import { task } from '#console/status'; +import { resolveTaskFormArguments } from '#console/form/builder/validators/status'; +import type { FormBuilder } from '#console/form/builder/index'; +import type { MaybePromise } from '#console/types'; +import type { Logger, TaskDefinition } from '#console/status'; export function taskFormStep(this: FormBuilder, definition: TaskDefinition, name?: string): FormBuilder; diff --git a/packages/tui/src/form/builder/step.ts b/pkgs-ts/console/src/form/builder/step.ts similarity index 76% rename from packages/tui/src/form/builder/step.ts rename to pkgs-ts/console/src/form/builder/step.ts index c0f30adc..47b8329b 100644 --- a/packages/tui/src/form/builder/step.ts +++ b/pkgs-ts/console/src/form/builder/step.ts @@ -1,4 +1,4 @@ -import type { MaybePromise } from '#tui/types'; +import type { MaybePromise } from '#console/types'; export const sideEffectStep = (callback: () => MaybePromise): (() => MaybePromise) => { return async () => { diff --git a/packages/tui/src/form/builder/submit.ts b/pkgs-ts/console/src/form/builder/submit.ts similarity index 73% rename from packages/tui/src/form/builder/submit.ts rename to pkgs-ts/console/src/form/builder/submit.ts index 57c30985..c96d2ad1 100644 --- a/packages/tui/src/form/builder/submit.ts +++ b/pkgs-ts/console/src/form/builder/submit.ts @@ -1,7 +1,7 @@ -import { shouldIgnoreStepWhenReverting, shouldRunStep } from '#tui/form/builder/conditions'; -import { runWithFormRevert } from '#tui/form/builder/revert'; -import { isFormRevertedError } from '#tui/form/builder/validators/revert'; -import type { FormResponses, FormStep } from '#tui/form/types'; +import { shouldIgnoreStepWhenReverting, shouldRunStep } from '#console/form/builder/conditions'; +import { runWithFormRevert } from '#console/form/builder/revert'; +import { isFormRevertedError } from '#console/form/builder/validators/revert'; +import type { FormResponses, FormStep } from '#console/form/types'; export const submitFormSteps = async (steps: FormStep[], responses: FormResponses): Promise => { let index = 0; diff --git a/packages/tui/src/form/builder/validators/conditions.ts b/pkgs-ts/console/src/form/builder/validators/conditions.ts similarity index 81% rename from packages/tui/src/form/builder/validators/conditions.ts rename to pkgs-ts/console/src/form/builder/validators/conditions.ts index e38689a0..21c8d96b 100644 --- a/packages/tui/src/form/builder/validators/conditions.ts +++ b/pkgs-ts/console/src/form/builder/validators/conditions.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import type { FormResponses, FormStepCondition } from '#tui/form/types'; -import type { MaybePromise } from '#tui/types'; +import type { FormResponses, FormStepCondition } from '#console/form/types'; +import type { MaybePromise } from '#console/types'; type FormStepConditionCallback = (responses: FormResponses) => MaybePromise; diff --git a/pkgs-ts/console/src/form/builder/validators/output.ts b/pkgs-ts/console/src/form/builder/validators/output.ts new file mode 100644 index 00000000..f425e743 --- /dev/null +++ b/pkgs-ts/console/src/form/builder/validators/output.ts @@ -0,0 +1,5 @@ +export { isNullOutputRows, parseOutputScroll, parseOutputStepName } from '#console/form/builder/validators/output/common'; +export { parseOutputDataTableRows, resolveDataTableFormArguments } from '#console/form/builder/validators/output/data-table'; +export type { ResolvedDataTableFormArguments } from '#console/form/builder/validators/output/data-table'; +export { parseOutputTableRows, resolveTableFormArguments } from '#console/form/builder/validators/output/table'; +export type { ResolvedTableFormArguments } from '#console/form/builder/validators/output/table'; diff --git a/packages/tui/src/form/builder/validators/output/common.ts b/pkgs-ts/console/src/form/builder/validators/output/common.ts similarity index 100% rename from packages/tui/src/form/builder/validators/output/common.ts rename to pkgs-ts/console/src/form/builder/validators/output/common.ts diff --git a/packages/tui/src/form/builder/validators/output/data-table.ts b/pkgs-ts/console/src/form/builder/validators/output/data-table.ts similarity index 83% rename from packages/tui/src/form/builder/validators/output/data-table.ts rename to pkgs-ts/console/src/form/builder/validators/output/data-table.ts index 3bd37999..13e53578 100644 --- a/packages/tui/src/form/builder/validators/output/data-table.ts +++ b/pkgs-ts/console/src/form/builder/validators/output/data-table.ts @@ -1,8 +1,8 @@ -import { isNullOutputRows, parseOutputScroll, parseOutputStepName } from '#tui/form/builder/validators/output/common'; -import { dataTableStepName, isDataTablePromptOptions } from '#tui/output/validators/data-table'; -import { dataTableRowsSchema } from '#tui/output/validators/data-table/schemas'; +import { isNullOutputRows, parseOutputScroll, parseOutputStepName } from '#console/form/builder/validators/output/common'; +import { dataTableStepName, isDataTablePromptOptions } from '#console/output/validators/data-table'; +import { dataTableRowsSchema } from '#console/output/validators/data-table/schemas'; import type { z } from 'zod'; -import type { DataTablePromptOptions, DataTableRow } from '#tui/types'; +import type { DataTablePromptOptions, DataTableRow } from '#console/types'; const outputDataTableRowsSchema = (): z.ZodType>> => dataTableRowsSchema as z.ZodType>>; diff --git a/packages/tui/src/form/builder/validators/output/table.ts b/pkgs-ts/console/src/form/builder/validators/output/table.ts similarity index 79% rename from packages/tui/src/form/builder/validators/output/table.ts rename to pkgs-ts/console/src/form/builder/validators/output/table.ts index 4eca758c..cee4144a 100644 --- a/packages/tui/src/form/builder/validators/output/table.ts +++ b/pkgs-ts/console/src/form/builder/validators/output/table.ts @@ -1,7 +1,7 @@ -import { isNullOutputRows } from '#tui/form/builder/validators/output/common'; -import { isTableOptions, tableStepName } from '#tui/output/validators/table'; -import { tableRowsSchema } from '#tui/output/validators/table/schemas'; -import type { TableOptions } from '#tui/types'; +import { isNullOutputRows } from '#console/form/builder/validators/output/common'; +import { isTableOptions, tableStepName } from '#console/output/validators/table'; +import { tableRowsSchema } from '#console/output/validators/table/schemas'; +import type { TableOptions } from '#console/types'; export type ResolvedTableFormArguments = | { diff --git a/packages/tui/src/form/builder/validators/previous.ts b/pkgs-ts/console/src/form/builder/validators/previous.ts similarity index 100% rename from packages/tui/src/form/builder/validators/previous.ts rename to pkgs-ts/console/src/form/builder/validators/previous.ts diff --git a/packages/tui/src/form/builder/validators/revert.ts b/pkgs-ts/console/src/form/builder/validators/revert.ts similarity index 78% rename from packages/tui/src/form/builder/validators/revert.ts rename to pkgs-ts/console/src/form/builder/validators/revert.ts index a942e66b..2100e093 100644 --- a/packages/tui/src/form/builder/validators/revert.ts +++ b/pkgs-ts/console/src/form/builder/validators/revert.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { FormRevertedError } from '#tui/form/builder/revert'; +import { FormRevertedError } from '#console/form/builder/revert'; const formRevertedErrorSchema = z.instanceof(FormRevertedError); diff --git a/pkgs-ts/console/src/form/builder/validators/status.ts b/pkgs-ts/console/src/form/builder/validators/status.ts new file mode 100644 index 00000000..6bd81d0d --- /dev/null +++ b/pkgs-ts/console/src/form/builder/validators/status.ts @@ -0,0 +1,9 @@ +export { isProgressTotal, isStatusLabel, parseProgressCallback, parseStatusCallback, parseStatusLabel } from '#console/form/builder/validators/status/common'; +export { resolveProgressFormArguments } from '#console/form/builder/validators/status/progress'; +export type { ResolvedProgressFormArguments } from '#console/form/builder/validators/status/progress'; +export { resolveSpinFormArguments } from '#console/form/builder/validators/status/spin'; +export type { ResolvedSpinFormArguments } from '#console/form/builder/validators/status/spin'; +export { isStreamSource, resolveStreamFormArguments } from '#console/form/builder/validators/status/stream'; +export type { ResolvedStreamFormArguments } from '#console/form/builder/validators/status/stream'; +export { resolveTaskFormArguments } from '#console/form/builder/validators/status/task'; +export type { ResolvedTaskFormArguments } from '#console/form/builder/validators/status/task'; diff --git a/packages/tui/src/form/builder/validators/status/common.ts b/pkgs-ts/console/src/form/builder/validators/status/common.ts similarity index 90% rename from packages/tui/src/form/builder/validators/status/common.ts rename to pkgs-ts/console/src/form/builder/validators/status/common.ts index 3758f215..5aac4b81 100644 --- a/packages/tui/src/form/builder/validators/status/common.ts +++ b/pkgs-ts/console/src/form/builder/validators/status/common.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; -import type { MaybePromise } from '#tui/types'; -import type { Progress } from '#tui/status'; +import { functionSchema } from '#console/validators/function'; +import type { MaybePromise } from '#console/types'; +import type { Progress } from '#console/status'; const progressTotalSchema = z.number(); const statusLabelSchema = z.string(); diff --git a/packages/tui/src/form/builder/validators/status/progress.ts b/pkgs-ts/console/src/form/builder/validators/status/progress.ts similarity index 79% rename from packages/tui/src/form/builder/validators/status/progress.ts rename to pkgs-ts/console/src/form/builder/validators/status/progress.ts index 77ca388c..ecf54885 100644 --- a/packages/tui/src/form/builder/validators/status/progress.ts +++ b/pkgs-ts/console/src/form/builder/validators/status/progress.ts @@ -1,7 +1,7 @@ -import { isProgressTotal, isStatusLabel, parseRequiredProgressCallback, parseStatusLabel } from '#tui/form/builder/validators/status/common'; -import { progressStepsArgument } from '#tui/status/progress/validators/arguments'; -import type { MaybePromise } from '#tui/types'; -import type { Progress } from '#tui/status'; +import { isProgressTotal, isStatusLabel, parseRequiredProgressCallback, parseStatusLabel } from '#console/form/builder/validators/status/common'; +import { progressStepsArgument } from '#console/status/progress/validators/arguments'; +import type { MaybePromise } from '#console/types'; +import type { Progress } from '#console/status'; export type ResolvedProgressFormArguments = | { diff --git a/packages/tui/src/form/builder/validators/status/spin.ts b/pkgs-ts/console/src/form/builder/validators/status/spin.ts similarity index 88% rename from packages/tui/src/form/builder/validators/status/spin.ts rename to pkgs-ts/console/src/form/builder/validators/status/spin.ts index dfac6e12..69654850 100644 --- a/packages/tui/src/form/builder/validators/status/spin.ts +++ b/pkgs-ts/console/src/form/builder/validators/status/spin.ts @@ -1,5 +1,5 @@ -import { isStatusLabel, parseStatusCallback, parseStatusLabel } from '#tui/form/builder/validators/status/common'; -import type { MaybePromise } from '#tui/types'; +import { isStatusLabel, parseStatusCallback, parseStatusLabel } from '#console/form/builder/validators/status/common'; +import type { MaybePromise } from '#console/types'; export type ResolvedSpinFormArguments = | { diff --git a/packages/tui/src/form/builder/validators/status/stream.ts b/pkgs-ts/console/src/form/builder/validators/status/stream.ts similarity index 83% rename from packages/tui/src/form/builder/validators/status/stream.ts rename to pkgs-ts/console/src/form/builder/validators/status/stream.ts index 576dcb99..025a6d2d 100644 --- a/packages/tui/src/form/builder/validators/status/stream.ts +++ b/pkgs-ts/console/src/form/builder/validators/status/stream.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { isStatusLabel } from '#tui/form/builder/validators/status/common'; -import { asyncIterableSchema, iterableSchema } from '#tui/validators/iterable'; +import { isStatusLabel } from '#console/form/builder/validators/status/common'; +import { asyncIterableSchema, iterableSchema } from '#console/validators/iterable'; const streamSourceSchema = z.union([asyncIterableSchema(), iterableSchema()]); diff --git a/packages/tui/src/form/builder/validators/status/task.ts b/pkgs-ts/console/src/form/builder/validators/status/task.ts similarity index 72% rename from packages/tui/src/form/builder/validators/status/task.ts rename to pkgs-ts/console/src/form/builder/validators/status/task.ts index 4ca5745c..6f2bd362 100644 --- a/packages/tui/src/form/builder/validators/status/task.ts +++ b/pkgs-ts/console/src/form/builder/validators/status/task.ts @@ -1,8 +1,8 @@ -import { isStatusLabel, parseStatusLabel } from '#tui/form/builder/validators/status/common'; -import { parseTaskCallback } from '#tui/status/task/validators/definition'; -import type { MaybePromise } from '#tui/types'; -import type { TaskDefinition } from '#tui/status'; -import type { Logger } from '#tui/status/task/logger'; +import { isStatusLabel, parseStatusLabel } from '#console/form/builder/validators/status/common'; +import { parseTaskCallback } from '#console/status/task/validators/definition'; +import type { MaybePromise } from '#console/types'; +import type { TaskDefinition } from '#console/status'; +import type { Logger } from '#console/status/task/logger'; export type ResolvedTaskFormArguments = | { diff --git a/packages/tui/src/form/types.ts b/pkgs-ts/console/src/form/types.ts similarity index 88% rename from packages/tui/src/form/types.ts rename to pkgs-ts/console/src/form/types.ts index a5941ca5..5ae26a6d 100644 --- a/packages/tui/src/form/types.ts +++ b/pkgs-ts/console/src/form/types.ts @@ -1,4 +1,4 @@ -import type { MaybePromise } from '#tui/types'; +import type { MaybePromise } from '#console/types'; export interface FormResponses extends Array { [name: string]: unknown; diff --git a/packages/tui/src/index.ts b/pkgs-ts/console/src/index.ts similarity index 55% rename from packages/tui/src/index.ts rename to pkgs-ts/console/src/index.ts index 3be5aeaf..052fda94 100644 --- a/packages/tui/src/index.ts +++ b/pkgs-ts/console/src/index.ts @@ -1,14 +1,14 @@ -export { configurePrompts, createMemoryOutput, createScriptedInput, promptEnvironment, withPromptEnvironment } from '#tui/environment'; -export type { MemoryOutput, RawKeyInput } from '#tui/environment'; -export { FormBuilder, form } from '#tui/form'; -export type { FormResponses, FormStep, FormStepCondition } from '#tui/form'; -export { Key, keyFromEvent, oneOf } from '#tui/key'; -export type { KeyboardEventLike, KeyName, KeyValue } from '#tui/key'; -export { renderOpenTuiTextFrame } from '#tui/opentui'; -export type { OpenTuiFrame } from '#tui/opentui'; -export { confirm, select, multiselect, suggest, search, multisearch, autocomplete, pause } from '#tui/prompts/choices'; -export type { SuggestOptions } from '#tui/prompts/choices'; -export { number, password, text, textarea } from '#tui/prompts/basic'; +export { configurePrompts, createMemoryOutput, createScriptedInput, promptEnvironment, withPromptEnvironment } from '#console/environment'; +export type { MemoryOutput, RawKeyInput } from '#console/environment'; +export { FormBuilder, form } from '#console/form'; +export type { FormResponses, FormStep, FormStepCondition } from '#console/form'; +export { Key, keyFromEvent, oneOf } from '#console/key'; +export type { KeyboardEventLike, KeyName, KeyValue } from '#console/key'; +export { renderOpenTuiTextFrame } from '#console/opentui'; +export type { OpenTuiFrame } from '#console/opentui'; +export { confirm, select, multiselect, suggest, search, multisearch, autocomplete, pause } from '#console/prompts/choices'; +export type { SuggestOptions } from '#console/prompts/choices'; +export { number, password, text, textarea } from '#console/prompts/basic'; export { alert, clear, @@ -29,12 +29,12 @@ export { table, title, warning, -} from '#tui/output'; -export type { NoteType, NotificationCommand, NotificationOptions, NotificationPlatform, NotificationRuntime } from '#tui/output'; -export { cancelUsing, fallbackUsing, fallbackWhen, PromptValidationError, validateUsing } from '#tui/prompt'; -export type { PromptCancelHandler, PromptFallbackCondition, PromptFallbackHandler, PromptFallbackKind, PromptGlobalValidator } from '#tui/prompt'; -export { Logger, Progress, Stream, progress, spin, stream, task } from '#tui/status'; -export type { ProgressSignalTarget, TaskDefinition } from '#tui/status'; +} from '#console/output'; +export type { NoteType, NotificationCommand, NotificationOptions, NotificationPlatform, NotificationRuntime } from '#console/output'; +export { cancelUsing, fallbackUsing, fallbackWhen, PromptValidationError, validateUsing } from '#console/prompt'; +export type { PromptCancelHandler, PromptFallbackCondition, PromptFallbackHandler, PromptFallbackKind, PromptGlobalValidator } from '#console/prompt'; +export { Logger, Progress, Stream, progress, spin, stream, task } from '#console/status'; +export type { ProgressSignalTarget, TaskDefinition } from '#console/status'; export { backgroundColor, clearTerminal, @@ -47,12 +47,12 @@ export { showCursor, supportsTrueColor, terminalSize, -} from '#tui/terminal'; -export type { TerminalSize } from '#tui/terminal'; -export { applyTypedKey, readTypedValue } from '#tui/typed-value'; -export type { TypedValueOptions, TypedValueReadResult, TypedValueState } from '#tui/typed-value'; -export { parseAnsiSegments, parseAnsiText, truncate, visibleWidth, wrap } from '#tui/strings'; -export type { AnsiSegment } from '#tui/strings'; +} from '#console/terminal'; +export type { TerminalSize } from '#console/terminal'; +export { applyTypedKey, readTypedValue } from '#console/typed-value'; +export type { TypedValueOptions, TypedValueReadResult, TypedValueState } from '#console/typed-value'; +export { parseAnsiSegments, parseAnsiText, truncate, visibleWidth, wrap } from '#console/strings'; +export type { AnsiSegment } from '#console/strings'; export type { BasePromptOptions, Choice, @@ -80,4 +80,4 @@ export type { TextPromptOptions, ValidationResult, Validator, -} from '#tui/types'; +} from '#console/types'; diff --git a/pkgs-ts/console/src/key.ts b/pkgs-ts/console/src/key.ts new file mode 100644 index 00000000..a90d06db --- /dev/null +++ b/pkgs-ts/console/src/key.ts @@ -0,0 +1,4 @@ +export { Key } from '#console/key/constants'; +export { keyFromEvent } from '#console/key/event'; +export { oneOf } from '#console/key/match'; +export type { KeyboardEventLike, KeyName, KeyValue } from '#console/key/types'; diff --git a/packages/tui/src/key/constants.ts b/pkgs-ts/console/src/key/constants.ts similarity index 100% rename from packages/tui/src/key/constants.ts rename to pkgs-ts/console/src/key/constants.ts diff --git a/packages/tui/src/key/event.ts b/pkgs-ts/console/src/key/event.ts similarity index 76% rename from packages/tui/src/key/event.ts rename to pkgs-ts/console/src/key/event.ts index c89e727c..3b8a06b3 100644 --- a/packages/tui/src/key/event.ts +++ b/pkgs-ts/console/src/key/event.ts @@ -1,8 +1,8 @@ -import { Key } from '#tui/key/constants'; -import { ctrlKeyMap, namedKeyMap, shiftedKeyMap } from '#tui/key/event/maps'; -import { firstKeyValue, keyValueFromName } from '#tui/key/event/value'; -import { parseKeyboardEvent } from '#tui/key/validators/event'; -import type { KeyboardEventLike, KeyName } from '#tui/key/types'; +import { Key } from '#console/key/constants'; +import { ctrlKeyMap, namedKeyMap, shiftedKeyMap } from '#console/key/event/maps'; +import { firstKeyValue, keyValueFromName } from '#console/key/event/value'; +import { parseKeyboardEvent } from '#console/key/validators/event'; +import type { KeyboardEventLike, KeyName } from '#console/key/types'; export const keyFromEvent = (event: KeyboardEventLike): KeyName | string => { const parsedEvent = parseKeyboardEvent(event); diff --git a/packages/tui/src/key/event/maps.ts b/pkgs-ts/console/src/key/event/maps.ts similarity index 81% rename from packages/tui/src/key/event/maps.ts rename to pkgs-ts/console/src/key/event/maps.ts index da2aa2fd..1db15d74 100644 --- a/packages/tui/src/key/event/maps.ts +++ b/pkgs-ts/console/src/key/event/maps.ts @@ -1,5 +1,5 @@ -import { Key } from '#tui/key/constants'; -import type { KeyName } from '#tui/key/types'; +import { Key } from '#console/key/constants'; +import type { KeyName } from '#console/key/types'; export const ctrlKeyMap: Record = { a: Key.ctrlA, diff --git a/packages/tui/src/key/event/value.ts b/pkgs-ts/console/src/key/event/value.ts similarity index 60% rename from packages/tui/src/key/event/value.ts rename to pkgs-ts/console/src/key/event/value.ts index b6fb2f2c..8e5281d2 100644 --- a/packages/tui/src/key/event/value.ts +++ b/pkgs-ts/console/src/key/event/value.ts @@ -1,6 +1,6 @@ -import { Key } from '#tui/key/constants'; -import { parseFirstKeyValue, parseKeyLookupName } from '#tui/key/validators/value'; -import type { KeyValue } from '#tui/key/types'; +import { Key } from '#console/key/constants'; +import { parseFirstKeyValue, parseKeyLookupName } from '#console/key/validators/value'; +import type { KeyValue } from '#console/key/types'; export const keyValueFromName = (name: string): KeyValue | undefined => { const keyName = parseKeyLookupName(name); diff --git a/packages/tui/src/key/match.ts b/pkgs-ts/console/src/key/match.ts similarity index 56% rename from packages/tui/src/key/match.ts rename to pkgs-ts/console/src/key/match.ts index a5204feb..81eef303 100644 --- a/packages/tui/src/key/match.ts +++ b/pkgs-ts/console/src/key/match.ts @@ -1,5 +1,5 @@ -import { parseKeyMatchValues } from '#tui/key/validators/match'; -import type { KeyValue } from '#tui/key/types'; +import { parseKeyMatchValues } from '#console/key/validators/match'; +import type { KeyValue } from '#console/key/types'; export const oneOf = (keys: KeyValue[], match: string): string | undefined => { return parseKeyMatchValues(keys).includes(match) ? match : undefined; diff --git a/packages/tui/src/key/types.ts b/pkgs-ts/console/src/key/types.ts similarity index 83% rename from packages/tui/src/key/types.ts rename to pkgs-ts/console/src/key/types.ts index 19091507..827cac74 100644 --- a/packages/tui/src/key/types.ts +++ b/pkgs-ts/console/src/key/types.ts @@ -1,4 +1,4 @@ -import type { Key } from '#tui/key/constants'; +import type { Key } from '#console/key/constants'; export type KeyValue = string | readonly string[]; diff --git a/packages/tui/src/key/validators/event.ts b/pkgs-ts/console/src/key/validators/event.ts similarity index 87% rename from packages/tui/src/key/validators/event.ts rename to pkgs-ts/console/src/key/validators/event.ts index beb73bfe..a40e1456 100644 --- a/packages/tui/src/key/validators/event.ts +++ b/pkgs-ts/console/src/key/validators/event.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { KeyboardEventLike } from '#tui/key/types'; +import type { KeyboardEventLike } from '#console/key/types'; const keyboardEventSchema = z .object({ diff --git a/packages/tui/src/key/validators/match.ts b/pkgs-ts/console/src/key/validators/match.ts similarity index 90% rename from packages/tui/src/key/validators/match.ts rename to pkgs-ts/console/src/key/validators/match.ts index 2d70a9ec..d9db546e 100644 --- a/packages/tui/src/key/validators/match.ts +++ b/pkgs-ts/console/src/key/validators/match.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { KeyValue } from '#tui/key/types'; +import type { KeyValue } from '#console/key/types'; const keyValueSchema = z.union([z.string().transform((value) => [value]), z.array(z.string()).transform((values) => [...values])]); diff --git a/packages/tui/src/key/validators/value.ts b/pkgs-ts/console/src/key/validators/value.ts similarity index 89% rename from packages/tui/src/key/validators/value.ts rename to pkgs-ts/console/src/key/validators/value.ts index bcb879e2..2d810a25 100644 --- a/packages/tui/src/key/validators/value.ts +++ b/pkgs-ts/console/src/key/validators/value.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { Key } from '#tui/key/constants'; -import type { KeyValue } from '#tui/key/types'; +import { Key } from '#console/key/constants'; +import type { KeyValue } from '#console/key/types'; type KeyLookupName = keyof typeof Key; diff --git a/packages/tui/src/opentui.ts b/pkgs-ts/console/src/opentui.ts similarity index 100% rename from packages/tui/src/opentui.ts rename to pkgs-ts/console/src/opentui.ts diff --git a/pkgs-ts/console/src/output.ts b/pkgs-ts/console/src/output.ts new file mode 100644 index 00000000..7d0a52d5 --- /dev/null +++ b/pkgs-ts/console/src/output.ts @@ -0,0 +1,7 @@ +export { alert, error, info, intro, note, outro, warning } from '#console/output/notes'; +export type { NoteType } from '#console/output/notes'; +export { commandExists, executeNotificationCommand, notificationCommand, notificationCommands, notify, notifyForPlatform } from '#console/output/notify'; +export type { NotificationCommand, NotificationOptions, NotificationPlatform, NotificationRuntime } from '#console/output/notify'; +export { datatable } from '#console/output/data-table'; +export { dataTable, grid, table } from '#console/output/table'; +export { clear, title } from '#console/output/terminal'; diff --git a/packages/tui/src/output/data-table.ts b/pkgs-ts/console/src/output/data-table.ts similarity index 78% rename from packages/tui/src/output/data-table.ts rename to pkgs-ts/console/src/output/data-table.ts index db43acf9..6e3fd006 100644 --- a/packages/tui/src/output/data-table.ts +++ b/pkgs-ts/console/src/output/data-table.ts @@ -1,7 +1,7 @@ -import { normalizeDataTablePromptOptions } from '#tui/output/data-table/options'; -import { runDataTablePrompt } from '#tui/output/data-table/run'; -import { parseDataTablePromptOptions } from '#tui/output/validators/data-table'; -import type { DataTablePromptOptions, DataTableRow } from '#tui/types'; +import { normalizeDataTablePromptOptions } from '#console/output/data-table/options'; +import { runDataTablePrompt } from '#console/output/data-table/run'; +import { parseDataTablePromptOptions } from '#console/output/validators/data-table'; +import type { DataTablePromptOptions, DataTableRow } from '#console/types'; export function datatable(options: DataTablePromptOptions): Promise; diff --git a/packages/tui/src/output/data-table/body/active.ts b/pkgs-ts/console/src/output/data-table/body/active.ts similarity index 67% rename from packages/tui/src/output/data-table/body/active.ts rename to pkgs-ts/console/src/output/data-table/body/active.ts index f5b3fb29..531a1bb9 100644 --- a/packages/tui/src/output/data-table/body/active.ts +++ b/pkgs-ts/console/src/output/data-table/body/active.ts @@ -1,12 +1,12 @@ -import { renderTable } from '#tui/theme'; -import { expandMultilineDataTableRows } from '#tui/output/data-table/multiline'; -import { dataTableRowCells } from '#tui/output/data-table/rows'; -import { renderDataTableHeaders } from '#tui/output/data-table/body/headers'; -import { renderScrollableDataTable } from '#tui/output/data-table/scrollbar'; -import { dataTableRowWindow } from '#tui/output/data-table/selection'; -import { fixedVisualDataTableRows } from '#tui/output/data-table/visual-window'; -import { fitDataTableColumns } from '#tui/output/data-table/widths'; -import type { DataTableBodyOptions } from '#tui/output/data-table/body/types'; +import { renderTable } from '#console/theme'; +import { expandMultilineDataTableRows } from '#console/output/data-table/multiline'; +import { dataTableRowCells } from '#console/output/data-table/rows'; +import { renderDataTableHeaders } from '#console/output/data-table/body/headers'; +import { renderScrollableDataTable } from '#console/output/data-table/scrollbar'; +import { dataTableRowWindow } from '#console/output/data-table/selection'; +import { fixedVisualDataTableRows } from '#console/output/data-table/visual-window'; +import { fitDataTableColumns } from '#console/output/data-table/widths'; +import type { DataTableBodyOptions } from '#console/output/data-table/body/types'; export const renderDataTableBody = (options: DataTableBodyOptions): string[] => { if (options.rows.length === 0) { diff --git a/packages/tui/src/output/data-table/body/cancelled.ts b/pkgs-ts/console/src/output/data-table/body/cancelled.ts similarity index 65% rename from packages/tui/src/output/data-table/body/cancelled.ts rename to pkgs-ts/console/src/output/data-table/body/cancelled.ts index db2c346d..f7bbce49 100644 --- a/packages/tui/src/output/data-table/body/cancelled.ts +++ b/pkgs-ts/console/src/output/data-table/body/cancelled.ts @@ -1,7 +1,7 @@ -import { expandMultilineDataTableRows } from '#tui/output/data-table/multiline'; -import { dataTableRowCells } from '#tui/output/data-table/rows'; -import { dim, strikethrough } from '#tui/theme/styles'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; +import { expandMultilineDataTableRows } from '#console/output/data-table/multiline'; +import { dataTableRowCells } from '#console/output/data-table/rows'; +import { dim, strikethrough } from '#console/theme/styles'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; export const renderCancelledDataTableRows = (headers: string[], rows: Array>, selected: number): string[][] => { return rows.flatMap(({ row }, index) => { diff --git a/packages/tui/src/output/data-table/body/headers.ts b/pkgs-ts/console/src/output/data-table/body/headers.ts similarity index 100% rename from packages/tui/src/output/data-table/body/headers.ts rename to pkgs-ts/console/src/output/data-table/body/headers.ts diff --git a/packages/tui/src/output/data-table/body/submitted.ts b/pkgs-ts/console/src/output/data-table/body/submitted.ts similarity index 62% rename from packages/tui/src/output/data-table/body/submitted.ts rename to pkgs-ts/console/src/output/data-table/body/submitted.ts index 6e657049..0de1f371 100644 --- a/packages/tui/src/output/data-table/body/submitted.ts +++ b/pkgs-ts/console/src/output/data-table/body/submitted.ts @@ -1,5 +1,5 @@ -import { dataTableRowCells } from '#tui/output/data-table/rows'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; +import { dataTableRowCells } from '#console/output/data-table/rows'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; export const renderSubmittedDataTableRow = (headers: string[], rows: Array>, selected: number): string | null => { const row = rows[selected]; diff --git a/packages/tui/src/output/data-table/body/types.ts b/pkgs-ts/console/src/output/data-table/body/types.ts similarity index 59% rename from packages/tui/src/output/data-table/body/types.ts rename to pkgs-ts/console/src/output/data-table/body/types.ts index 2ce3ad5b..4c61ae11 100644 --- a/packages/tui/src/output/data-table/body/types.ts +++ b/pkgs-ts/console/src/output/data-table/body/types.ts @@ -1,5 +1,5 @@ -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; -import type { DataTableRow } from '#tui/types'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; +import type { DataTableRow } from '#console/types'; export type DataTableBodyOptions = { allRows: Array>; diff --git a/packages/tui/src/output/data-table/keys.ts b/pkgs-ts/console/src/output/data-table/keys.ts similarity index 94% rename from packages/tui/src/output/data-table/keys.ts rename to pkgs-ts/console/src/output/data-table/keys.ts index c9280adc..746bdf89 100644 --- a/packages/tui/src/output/data-table/keys.ts +++ b/pkgs-ts/console/src/output/data-table/keys.ts @@ -1,4 +1,4 @@ -import { Key, oneOf } from '#tui/key'; +import { Key, oneOf } from '#console/key'; export type DataTableNavigationAction = 'first' | 'last' | 'next' | 'page-next' | 'page-previous' | 'previous'; diff --git a/packages/tui/src/output/data-table/multiline.ts b/pkgs-ts/console/src/output/data-table/multiline.ts similarity index 100% rename from packages/tui/src/output/data-table/multiline.ts rename to pkgs-ts/console/src/output/data-table/multiline.ts diff --git a/packages/tui/src/output/data-table/navigation.ts b/pkgs-ts/console/src/output/data-table/navigation.ts similarity index 88% rename from packages/tui/src/output/data-table/navigation.ts rename to pkgs-ts/console/src/output/data-table/navigation.ts index d25bf1ef..f74a9829 100644 --- a/packages/tui/src/output/data-table/navigation.ts +++ b/pkgs-ts/console/src/output/data-table/navigation.ts @@ -1,6 +1,6 @@ -import { parseScrollSize } from '#tui/concerns/validators/scroll'; -import { parseDataTableRowTotal, parseDataTableSelectedIndex } from '#tui/output/data-table/validators/selection'; -import type { DataTableNavigationAction } from '#tui/output/data-table/keys'; +import { parseScrollSize } from '#console/concerns/validators/scroll'; +import { parseDataTableRowTotal, parseDataTableSelectedIndex } from '#console/output/data-table/validators/selection'; +import type { DataTableNavigationAction } from '#console/output/data-table/keys'; export const nextDataTableSelection = (selected: number, total: number): number => { const rowTotal = parseDataTableRowTotal(total); diff --git a/packages/tui/src/output/data-table/options.ts b/pkgs-ts/console/src/output/data-table/options.ts similarity index 85% rename from packages/tui/src/output/data-table/options.ts rename to pkgs-ts/console/src/output/data-table/options.ts index e6911a8c..1d545116 100644 --- a/packages/tui/src/output/data-table/options.ts +++ b/pkgs-ts/console/src/output/data-table/options.ts @@ -1,7 +1,7 @@ -import { parseDataTableDefault, parseInitialDataTableRow } from '#tui/output/validators/data-table'; -import { dataTableRowValue } from '#tui/output/data-table/rows'; -import { hasPromptDefault } from '#tui/validators/default'; -import type { DataTablePromptOptions, DataTableRow } from '#tui/types'; +import { parseDataTableDefault, parseInitialDataTableRow } from '#console/output/validators/data-table'; +import { dataTableRowValue } from '#console/output/data-table/rows'; +import { hasPromptDefault } from '#console/validators/default'; +import type { DataTablePromptOptions, DataTableRow } from '#console/types'; export type NormalizedDataTablePromptOptions = DataTablePromptOptions & { hasDefault: boolean; diff --git a/pkgs-ts/console/src/output/data-table/read.ts b/pkgs-ts/console/src/output/data-table/read.ts new file mode 100644 index 00000000..ce8aa6ad --- /dev/null +++ b/pkgs-ts/console/src/output/data-table/read.ts @@ -0,0 +1,15 @@ +import { promptEnvironment } from '#console/environment'; +import { readDataTableFallbackSelection } from '#console/output/data-table/reader/fallback'; +import { readDataTableSelectionInteractive } from '#console/output/data-table/reader/interactive'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; +import type { DataTableSelectionReadResult } from '#console/output/data-table/types'; + +export const readDataTableSelection = async (options: DataTableReadOptions, headers: string[]): Promise> => { + const environment = promptEnvironment(); + + if (!environment.input.readKey) { + return readDataTableFallbackSelection(options, headers); + } + + return readDataTableSelectionInteractive(environment.input.readKey, options, headers); +}; diff --git a/packages/tui/src/output/data-table/reader/cancel.ts b/pkgs-ts/console/src/output/data-table/reader/cancel.ts similarity index 64% rename from packages/tui/src/output/data-table/reader/cancel.ts rename to pkgs-ts/console/src/output/data-table/reader/cancel.ts index c1eaa854..b51714ba 100644 --- a/packages/tui/src/output/data-table/reader/cancel.ts +++ b/pkgs-ts/console/src/output/data-table/reader/cancel.ts @@ -1,11 +1,11 @@ -import { cancelPrompt } from '#tui/prompt'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderCancelledDataTableFrame } from '#tui/output/data-table/render'; -import { dataTableRowValue } from '#tui/output/data-table/rows'; -import { selectedDataTableValue } from '#tui/output/data-table/reader/result'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; -import type { DataTableSearchMode } from '#tui/output/data-table/search'; -import type { DataTableSelectionReadResult, VisibleDataTableRow } from '#tui/output/data-table/types'; +import { cancelPrompt } from '#console/prompt'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderCancelledDataTableFrame } from '#console/output/data-table/render'; +import { dataTableRowValue } from '#console/output/data-table/rows'; +import { selectedDataTableValue } from '#console/output/data-table/reader/result'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; +import type { DataTableSearchMode } from '#console/output/data-table/search'; +import type { DataTableSelectionReadResult, VisibleDataTableRow } from '#console/output/data-table/types'; const cancelledDataTableValue = (options: DataTableReadOptions, rows: Array>, selected: number): T | number => { if (rows[selected] !== undefined) { diff --git a/packages/tui/src/output/data-table/reader/fallback.ts b/pkgs-ts/console/src/output/data-table/reader/fallback.ts similarity index 61% rename from packages/tui/src/output/data-table/reader/fallback.ts rename to pkgs-ts/console/src/output/data-table/reader/fallback.ts index dfdd2fff..d1a9ab29 100644 --- a/packages/tui/src/output/data-table/reader/fallback.ts +++ b/pkgs-ts/console/src/output/data-table/reader/fallback.ts @@ -1,9 +1,9 @@ -import { ask } from '#tui/prompt/ask'; -import { promptEnvironment } from '#tui/environment'; -import { visibleDataTableRows } from '#tui/output/data-table/rows'; -import { assertSelectedDataTableRow, dataTableSelectionResult, initialDataTableSelection } from '#tui/output/data-table/reader/result'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; -import type { DataTableSelectionReadResult } from '#tui/output/data-table/types'; +import { ask } from '#console/prompt/ask'; +import { promptEnvironment } from '#console/environment'; +import { visibleDataTableRows } from '#console/output/data-table/rows'; +import { assertSelectedDataTableRow, dataTableSelectionResult, initialDataTableSelection } from '#console/output/data-table/reader/result'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; +import type { DataTableSelectionReadResult } from '#console/output/data-table/types'; export const readDataTableFallbackSelection = async (options: DataTableReadOptions, headers: string[]): Promise> => { const environment = promptEnvironment(); diff --git a/packages/tui/src/output/data-table/reader/interactive.ts b/pkgs-ts/console/src/output/data-table/reader/interactive.ts similarity index 72% rename from packages/tui/src/output/data-table/reader/interactive.ts rename to pkgs-ts/console/src/output/data-table/reader/interactive.ts index 3a0e71c2..8519c1a8 100644 --- a/packages/tui/src/output/data-table/reader/interactive.ts +++ b/pkgs-ts/console/src/output/data-table/reader/interactive.ts @@ -1,11 +1,11 @@ -import { Key } from '#tui/key'; -import { dataTableNavigationAction, startsDataTableSearch } from '#tui/output/data-table/keys'; -import { cancelDataTableSelection } from '#tui/output/data-table/reader/cancel'; -import { assertSelectedDataTableRow, dataTableSelectionResult } from '#tui/output/data-table/reader/result'; -import { createDataTableReaderSession } from '#tui/output/data-table/reader/session'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; -import type { DataTableSelectionReadResult } from '#tui/output/data-table/types'; -import type { PromptInput } from '#tui/types'; +import { Key } from '#console/key'; +import { dataTableNavigationAction, startsDataTableSearch } from '#console/output/data-table/keys'; +import { cancelDataTableSelection } from '#console/output/data-table/reader/cancel'; +import { assertSelectedDataTableRow, dataTableSelectionResult } from '#console/output/data-table/reader/result'; +import { createDataTableReaderSession } from '#console/output/data-table/reader/session'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; +import type { DataTableSelectionReadResult } from '#console/output/data-table/types'; +import type { PromptInput } from '#console/types'; export const readDataTableSelectionInteractive = async ( readKey: NonNullable, diff --git a/packages/tui/src/output/data-table/reader/result.ts b/pkgs-ts/console/src/output/data-table/reader/result.ts similarity index 81% rename from packages/tui/src/output/data-table/reader/result.ts rename to pkgs-ts/console/src/output/data-table/reader/result.ts index ec3c52c6..4948f18b 100644 --- a/packages/tui/src/output/data-table/reader/result.ts +++ b/pkgs-ts/console/src/output/data-table/reader/result.ts @@ -1,8 +1,8 @@ -import { PromptValidationError } from '#tui/prompt'; -import { choiceValueEquals } from '#tui/concerns/choices'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { dataTableRowValue } from '#tui/output/data-table/rows'; -import type { DataTableSelectionReadResult, VisibleDataTableRow } from '#tui/output/data-table/types'; +import { PromptValidationError } from '#console/prompt'; +import { choiceValueEquals } from '#console/concerns/choices'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { dataTableRowValue } from '#console/output/data-table/rows'; +import type { DataTableSelectionReadResult, VisibleDataTableRow } from '#console/output/data-table/types'; const invalidRow = (): PromptValidationError => new PromptValidationError('Please select a valid row.'); diff --git a/packages/tui/src/output/data-table/reader/session.ts b/pkgs-ts/console/src/output/data-table/reader/session.ts similarity index 68% rename from packages/tui/src/output/data-table/reader/session.ts rename to pkgs-ts/console/src/output/data-table/reader/session.ts index c8e7e541..d8ecfffa 100644 --- a/packages/tui/src/output/data-table/reader/session.ts +++ b/pkgs-ts/console/src/output/data-table/reader/session.ts @@ -1,9 +1,9 @@ -import { renderDataTableReaderSessionFrame } from '#tui/output/data-table/reader/session/render'; -import { createDataTableReaderState } from '#tui/output/data-table/reader/state'; -import type { DataTableNavigationAction } from '#tui/output/data-table/keys'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; -import type { DataTableSearchMode } from '#tui/output/data-table/search'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; +import { renderDataTableReaderSessionFrame } from '#console/output/data-table/reader/session/render'; +import { createDataTableReaderState } from '#console/output/data-table/reader/state'; +import type { DataTableNavigationAction } from '#console/output/data-table/keys'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; +import type { DataTableSearchMode } from '#console/output/data-table/search'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; export type DataTableReaderSession = { applySearchKey(key: string): boolean; diff --git a/packages/tui/src/output/data-table/reader/session/render.ts b/pkgs-ts/console/src/output/data-table/reader/session/render.ts similarity index 64% rename from packages/tui/src/output/data-table/reader/session/render.ts rename to pkgs-ts/console/src/output/data-table/reader/session/render.ts index f4aeaeb6..463c12cd 100644 --- a/packages/tui/src/output/data-table/reader/session/render.ts +++ b/pkgs-ts/console/src/output/data-table/reader/session/render.ts @@ -1,7 +1,7 @@ -import { renderDataTableFrame } from '#tui/output/data-table/render'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import type { DataTableReaderState } from '#tui/output/data-table/reader/state'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; +import { renderDataTableFrame } from '#console/output/data-table/render'; +import { eraseRenderedFrame } from '#console/status/frame'; +import type { DataTableReaderState } from '#console/output/data-table/reader/state'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; export const renderDataTableReaderSessionFrame = (options: DataTableReadOptions, headers: string[], state: DataTableReaderState, currentFrame: string): string => { if (currentFrame.length > 0) { diff --git a/packages/tui/src/output/data-table/reader/state.ts b/pkgs-ts/console/src/output/data-table/reader/state.ts similarity index 71% rename from packages/tui/src/output/data-table/reader/state.ts rename to pkgs-ts/console/src/output/data-table/reader/state.ts index 133f1006..6c2f017f 100644 --- a/packages/tui/src/output/data-table/reader/state.ts +++ b/pkgs-ts/console/src/output/data-table/reader/state.ts @@ -1,11 +1,11 @@ -import { createDataTableReaderSelectionState } from '#tui/output/data-table/reader/state/selection'; -import { applyDataTableReaderSearchKey, beginDataTableReaderSearch } from '#tui/output/data-table/reader/state/search'; -import { visibleDataTableRows } from '#tui/output/data-table/rows'; -import { initialDataTableSearchState } from '#tui/output/data-table/search'; -import type { DataTableNavigationAction } from '#tui/output/data-table/keys'; -import type { DataTableSearchState } from '#tui/output/data-table/search'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; +import { createDataTableReaderSelectionState } from '#console/output/data-table/reader/state/selection'; +import { applyDataTableReaderSearchKey, beginDataTableReaderSearch } from '#console/output/data-table/reader/state/search'; +import { visibleDataTableRows } from '#console/output/data-table/rows'; +import { initialDataTableSearchState } from '#console/output/data-table/search'; +import type { DataTableNavigationAction } from '#console/output/data-table/keys'; +import type { DataTableSearchState } from '#console/output/data-table/search'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; export type DataTableReaderState = { applySearchKey(key: string): boolean; diff --git a/packages/tui/src/output/data-table/reader/state/search.ts b/pkgs-ts/console/src/output/data-table/reader/state/search.ts similarity index 86% rename from packages/tui/src/output/data-table/reader/state/search.ts rename to pkgs-ts/console/src/output/data-table/reader/state/search.ts index a83d4c49..78bd1d28 100644 --- a/packages/tui/src/output/data-table/reader/state/search.ts +++ b/pkgs-ts/console/src/output/data-table/reader/state/search.ts @@ -1,5 +1,5 @@ -import { applyDataTableSearchKey, startDataTableSearch } from '#tui/output/data-table/search'; -import type { DataTableSearchChange, DataTableSearchState } from '#tui/output/data-table/search'; +import { applyDataTableSearchKey, startDataTableSearch } from '#console/output/data-table/search'; +import type { DataTableSearchChange, DataTableSearchState } from '#console/output/data-table/search'; export type DataTableReaderSearchChange = DataTableSearchChange; diff --git a/packages/tui/src/output/data-table/reader/state/selection.ts b/pkgs-ts/console/src/output/data-table/reader/state/selection.ts similarity index 62% rename from packages/tui/src/output/data-table/reader/state/selection.ts rename to pkgs-ts/console/src/output/data-table/reader/state/selection.ts index e32f6a71..b9bd3808 100644 --- a/packages/tui/src/output/data-table/reader/state/selection.ts +++ b/pkgs-ts/console/src/output/data-table/reader/state/selection.ts @@ -1,8 +1,8 @@ -import { moveDataTableSelection } from '#tui/output/data-table/navigation'; -import { initialDataTableSelection } from '#tui/output/data-table/reader/result'; -import type { DataTableNavigationAction } from '#tui/output/data-table/keys'; -import type { DataTableReadOptions } from '#tui/output/data-table/reader/types'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; +import { moveDataTableSelection } from '#console/output/data-table/navigation'; +import { initialDataTableSelection } from '#console/output/data-table/reader/result'; +import type { DataTableNavigationAction } from '#console/output/data-table/keys'; +import type { DataTableReadOptions } from '#console/output/data-table/reader/types'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; export type DataTableReaderSelectionState = { move(action: DataTableNavigationAction, total: number): void; diff --git a/packages/tui/src/output/data-table/reader/types.ts b/pkgs-ts/console/src/output/data-table/reader/types.ts similarity index 60% rename from packages/tui/src/output/data-table/reader/types.ts rename to pkgs-ts/console/src/output/data-table/reader/types.ts index 42360b01..a1d534db 100644 --- a/packages/tui/src/output/data-table/reader/types.ts +++ b/pkgs-ts/console/src/output/data-table/reader/types.ts @@ -1,4 +1,4 @@ -import type { DataTablePromptOptions } from '#tui/types'; +import type { DataTablePromptOptions } from '#console/types'; export type DataTableReadOptions = DataTablePromptOptions & { hasDefault?: boolean; diff --git a/pkgs-ts/console/src/output/data-table/render-body.ts b/pkgs-ts/console/src/output/data-table/render-body.ts new file mode 100644 index 00000000..7f7e68fb --- /dev/null +++ b/pkgs-ts/console/src/output/data-table/render-body.ts @@ -0,0 +1,5 @@ +export { renderDataTableBody } from '#console/output/data-table/body/active'; +export { renderCancelledDataTableRows } from '#console/output/data-table/body/cancelled'; +export { renderDataTableHeaders } from '#console/output/data-table/body/headers'; +export { renderSubmittedDataTableRow } from '#console/output/data-table/body/submitted'; +export type { DataTableBodyOptions } from '#console/output/data-table/body/types'; diff --git a/packages/tui/src/output/data-table/render.ts b/pkgs-ts/console/src/output/data-table/render.ts similarity index 78% rename from packages/tui/src/output/data-table/render.ts rename to pkgs-ts/console/src/output/data-table/render.ts index eb9187ab..44a63a7d 100644 --- a/packages/tui/src/output/data-table/render.ts +++ b/pkgs-ts/console/src/output/data-table/render.ts @@ -1,11 +1,11 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderTable } from '#tui/theme'; -import { renderCancelledDataTableRows, renderDataTableBody, renderDataTableHeaders, renderSubmittedDataTableRow } from '#tui/output/data-table/render-body'; -import { clampDataTableSelection } from '#tui/output/data-table/selection'; -import { dim, red } from '#tui/theme/styles'; -import type { DataTableRow } from '#tui/types'; -import type { DataTableSearchMode } from '#tui/output/data-table/search'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; +import { promptEnvironment } from '#console/environment'; +import { renderTable } from '#console/theme'; +import { renderCancelledDataTableRows, renderDataTableBody, renderDataTableHeaders, renderSubmittedDataTableRow } from '#console/output/data-table/render-body'; +import { clampDataTableSelection } from '#console/output/data-table/selection'; +import { dim, red } from '#console/theme/styles'; +import type { DataTableRow } from '#console/types'; +import type { DataTableSearchMode } from '#console/output/data-table/search'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; type RenderDataTableFrameOptions = { allRows: Array>; diff --git a/pkgs-ts/console/src/output/data-table/rows.ts b/pkgs-ts/console/src/output/data-table/rows.ts new file mode 100644 index 00000000..b0383cb6 --- /dev/null +++ b/pkgs-ts/console/src/output/data-table/rows.ts @@ -0,0 +1,4 @@ +export { stringifyDataTableCell } from '#console/output/data-table/rows/cells'; +export { dataTableRowCells, dataTableRowFields, dataTableRowLabel, dataTableRowValue } from '#console/output/data-table/rows/fields'; +export { deriveDataTableHeaders } from '#console/output/data-table/rows/headers'; +export { visibleDataTableRows } from '#console/output/data-table/rows/visible'; diff --git a/packages/tui/src/output/data-table/rows/cells.ts b/pkgs-ts/console/src/output/data-table/rows/cells.ts similarity index 74% rename from packages/tui/src/output/data-table/rows/cells.ts rename to pkgs-ts/console/src/output/data-table/rows/cells.ts index 062577f2..66b81327 100644 --- a/packages/tui/src/output/data-table/rows/cells.ts +++ b/pkgs-ts/console/src/output/data-table/rows/cells.ts @@ -1,4 +1,4 @@ -import type { TableCell } from '#tui/types'; +import type { TableCell } from '#console/types'; export const stringifyDataTableCell = (value: TableCell): string => { return value === null || value === undefined ? '' : String(value); diff --git a/packages/tui/src/output/data-table/rows/fields.ts b/pkgs-ts/console/src/output/data-table/rows/fields.ts similarity index 85% rename from packages/tui/src/output/data-table/rows/fields.ts rename to pkgs-ts/console/src/output/data-table/rows/fields.ts index f6c9bd9f..b02879c6 100644 --- a/packages/tui/src/output/data-table/rows/fields.ts +++ b/pkgs-ts/console/src/output/data-table/rows/fields.ts @@ -1,6 +1,6 @@ -import { parseDataTableArrayRowFields, parseDataTableRowShape, parseDataTableRowValue } from '#tui/output/validators/data-table'; -import { stringifyDataTableCell } from '#tui/output/data-table/rows/cells'; -import type { DataTableRow, TableCell } from '#tui/types'; +import { parseDataTableArrayRowFields, parseDataTableRowShape, parseDataTableRowValue } from '#console/output/validators/data-table'; +import { stringifyDataTableCell } from '#console/output/data-table/rows/cells'; +import type { DataTableRow, TableCell } from '#console/types'; export const dataTableRowFields = (row: DataTableRow): Record => { const shape = parseDataTableRowShape(row); diff --git a/packages/tui/src/output/data-table/rows/headers.ts b/pkgs-ts/console/src/output/data-table/rows/headers.ts similarity index 66% rename from packages/tui/src/output/data-table/rows/headers.ts rename to pkgs-ts/console/src/output/data-table/rows/headers.ts index b7ded314..f44359a5 100644 --- a/packages/tui/src/output/data-table/rows/headers.ts +++ b/pkgs-ts/console/src/output/data-table/rows/headers.ts @@ -1,6 +1,6 @@ -import { parseDataTableArrayHeaders, parseDataTableRecordHeaders, parseDataTableRowShape } from '#tui/output/validators/data-table'; -import { dataTableRowFields } from '#tui/output/data-table/rows/fields'; -import type { DataTableRow } from '#tui/types'; +import { parseDataTableArrayHeaders, parseDataTableRecordHeaders, parseDataTableRowShape } from '#console/output/validators/data-table'; +import { dataTableRowFields } from '#console/output/data-table/rows/fields'; +import type { DataTableRow } from '#console/types'; export const deriveDataTableHeaders = (rows: Array>): string[] => { const first = rows[0]; diff --git a/packages/tui/src/output/data-table/rows/visible.ts b/pkgs-ts/console/src/output/data-table/rows/visible.ts similarity index 67% rename from packages/tui/src/output/data-table/rows/visible.ts rename to pkgs-ts/console/src/output/data-table/rows/visible.ts index 22555f64..96d6df5e 100644 --- a/packages/tui/src/output/data-table/rows/visible.ts +++ b/pkgs-ts/console/src/output/data-table/rows/visible.ts @@ -1,6 +1,6 @@ -import { dataTableRowLabel } from '#tui/output/data-table/rows/fields'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; -import type { DataTablePromptOptions } from '#tui/types'; +import { dataTableRowLabel } from '#console/output/data-table/rows/fields'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; +import type { DataTablePromptOptions } from '#console/types'; export const visibleDataTableRows = (options: DataTablePromptOptions, headers: string[], query: string): Array> => { const rows = options.rows.map((row, index) => ({ index, row })); diff --git a/packages/tui/src/output/data-table/run.ts b/pkgs-ts/console/src/output/data-table/run.ts similarity index 62% rename from packages/tui/src/output/data-table/run.ts rename to pkgs-ts/console/src/output/data-table/run.ts index e81e4576..3b3e09f7 100644 --- a/packages/tui/src/output/data-table/run.ts +++ b/pkgs-ts/console/src/output/data-table/run.ts @@ -1,13 +1,13 @@ -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { promptEnvironment } from '#tui/environment'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { dataTableValidationOptions, preserveDataTableRetryDefault, transformDataTableValue } from '#tui/output/data-table/options'; -import { readDataTableSelection } from '#tui/output/data-table/read'; -import { renderSubmittedDataTableFrame } from '#tui/output/data-table/render'; -import { deriveDataTableHeaders } from '#tui/output/data-table/rows'; -import type { DataTableSelectionReadResult } from '#tui/output/data-table/types'; -import type { NormalizedDataTablePromptOptions } from '#tui/output/data-table/options'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { promptEnvironment } from '#console/environment'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { dataTableValidationOptions, preserveDataTableRetryDefault, transformDataTableValue } from '#console/output/data-table/options'; +import { readDataTableSelection } from '#console/output/data-table/read'; +import { renderSubmittedDataTableFrame } from '#console/output/data-table/render'; +import { deriveDataTableHeaders } from '#console/output/data-table/rows'; +import type { DataTableSelectionReadResult } from '#console/output/data-table/types'; +import type { NormalizedDataTablePromptOptions } from '#console/output/data-table/options'; export const runDataTablePrompt = async (options: NormalizedDataTablePromptOptions): Promise => { const validationOptions = await dataTableValidationOptions(options, !promptEnvironment().interactive); diff --git a/packages/tui/src/output/data-table/scrollbar.ts b/pkgs-ts/console/src/output/data-table/scrollbar.ts similarity index 80% rename from packages/tui/src/output/data-table/scrollbar.ts rename to pkgs-ts/console/src/output/data-table/scrollbar.ts index b0b51b4b..996ec68a 100644 --- a/packages/tui/src/output/data-table/scrollbar.ts +++ b/pkgs-ts/console/src/output/data-table/scrollbar.ts @@ -1,5 +1,5 @@ -import { renderScrollbarRows } from '#tui/concerns/scrollbar'; -import { renderTable } from '#tui/theme'; +import { renderScrollbarRows } from '#console/concerns/scrollbar'; +import { renderTable } from '#console/theme'; export const renderScrollableDataTable = (headers: string[], rows: string[][], firstVisible: number, visibleRows: number, totalRows: number): string => { const lines = renderTable(headers, rows).split('\n'); diff --git a/packages/tui/src/output/data-table/search.ts b/pkgs-ts/console/src/output/data-table/search.ts similarity index 90% rename from packages/tui/src/output/data-table/search.ts rename to pkgs-ts/console/src/output/data-table/search.ts index 82dbf924..d4167d84 100644 --- a/packages/tui/src/output/data-table/search.ts +++ b/pkgs-ts/console/src/output/data-table/search.ts @@ -1,6 +1,6 @@ -import { Key } from '#tui/key'; -import { applyTypedKey } from '#tui/typed-value'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { Key } from '#console/key'; +import { applyTypedKey } from '#console/typed-value'; +import type { TypedValueState } from '#console/typed-value/types'; export type DataTableSearchMode = 'browse' | 'search'; diff --git a/packages/tui/src/output/data-table/selection.ts b/pkgs-ts/console/src/output/data-table/selection.ts similarity index 78% rename from packages/tui/src/output/data-table/selection.ts rename to pkgs-ts/console/src/output/data-table/selection.ts index 85f448ac..0e1d9913 100644 --- a/packages/tui/src/output/data-table/selection.ts +++ b/pkgs-ts/console/src/output/data-table/selection.ts @@ -1,6 +1,6 @@ -import { parseOptionalScrollSize } from '#tui/concerns/validators/scroll'; -import { parseDataTableRowTotal, parseDataTableSelectedIndex } from '#tui/output/data-table/validators/selection'; -import type { VisibleDataTableRow } from '#tui/output/data-table/types'; +import { parseOptionalScrollSize } from '#console/concerns/validators/scroll'; +import { parseDataTableRowTotal, parseDataTableSelectedIndex } from '#console/output/data-table/validators/selection'; +import type { VisibleDataTableRow } from '#console/output/data-table/types'; export const clampDataTableSelection = (selected: number, rows: Array>): number => { return parseDataTableSelectedIndex(selected, rows.length); diff --git a/packages/tui/src/output/data-table/types.ts b/pkgs-ts/console/src/output/data-table/types.ts similarity index 83% rename from packages/tui/src/output/data-table/types.ts rename to pkgs-ts/console/src/output/data-table/types.ts index 1c5d089a..4d3f81b0 100644 --- a/packages/tui/src/output/data-table/types.ts +++ b/pkgs-ts/console/src/output/data-table/types.ts @@ -1,4 +1,4 @@ -import type { DataTableRow } from '#tui/types'; +import type { DataTableRow } from '#console/types'; export type VisibleDataTableRow = { index: number; diff --git a/packages/tui/src/output/data-table/validators/selection.ts b/pkgs-ts/console/src/output/data-table/validators/selection.ts similarity index 100% rename from packages/tui/src/output/data-table/validators/selection.ts rename to pkgs-ts/console/src/output/data-table/validators/selection.ts diff --git a/packages/tui/src/output/data-table/visual-window.ts b/pkgs-ts/console/src/output/data-table/visual-window.ts similarity index 85% rename from packages/tui/src/output/data-table/visual-window.ts rename to pkgs-ts/console/src/output/data-table/visual-window.ts index 3787a519..af1984d3 100644 --- a/packages/tui/src/output/data-table/visual-window.ts +++ b/pkgs-ts/console/src/output/data-table/visual-window.ts @@ -1,4 +1,4 @@ -import { parseOptionalScrollSize } from '#tui/concerns/validators/scroll'; +import { parseOptionalScrollSize } from '#console/concerns/validators/scroll'; export const fixedVisualDataTableRows = (rows: string[][], scroll?: number): string[][] => { const height = parseOptionalScrollSize(scroll); diff --git a/packages/tui/src/output/data-table/widths.ts b/pkgs-ts/console/src/output/data-table/widths.ts similarity index 59% rename from packages/tui/src/output/data-table/widths.ts rename to pkgs-ts/console/src/output/data-table/widths.ts index 4565a66e..49fb2901 100644 --- a/packages/tui/src/output/data-table/widths.ts +++ b/pkgs-ts/console/src/output/data-table/widths.ts @@ -1,7 +1,7 @@ -import { terminalSize } from '#tui/terminal'; -import { truncateDataTableColumns } from '#tui/output/data-table/widths/truncate'; -import { dataTableColumnWidths } from '#tui/output/data-table/widths/columns'; -import { parseDataTableWidth } from '#tui/output/data-table/widths/validators/dimensions'; +import { terminalSize } from '#console/terminal'; +import { truncateDataTableColumns } from '#console/output/data-table/widths/truncate'; +import { dataTableColumnWidths } from '#console/output/data-table/widths/columns'; +import { parseDataTableWidth } from '#console/output/data-table/widths/validators/dimensions'; type FitDataTableColumnsOptions = { allRows: string[][]; diff --git a/packages/tui/src/output/data-table/widths/available.ts b/pkgs-ts/console/src/output/data-table/widths/available.ts similarity index 89% rename from packages/tui/src/output/data-table/widths/available.ts rename to pkgs-ts/console/src/output/data-table/widths/available.ts index 35443034..04e50230 100644 --- a/packages/tui/src/output/data-table/widths/available.ts +++ b/pkgs-ts/console/src/output/data-table/widths/available.ts @@ -1,4 +1,4 @@ -import { parseDataTableColumnCount, parseDataTableWidth } from '#tui/output/data-table/widths/validators/dimensions'; +import { parseDataTableColumnCount, parseDataTableWidth } from '#console/output/data-table/widths/validators/dimensions'; export const availableDataTableCellWidth = (columnCount: number, maxWidth: number): number => { const columns = parseDataTableColumnCount(columnCount); diff --git a/packages/tui/src/output/data-table/widths/columns.ts b/pkgs-ts/console/src/output/data-table/widths/columns.ts similarity index 71% rename from packages/tui/src/output/data-table/widths/columns.ts rename to pkgs-ts/console/src/output/data-table/widths/columns.ts index 52d7a86d..335d0c0b 100644 --- a/packages/tui/src/output/data-table/widths/columns.ts +++ b/pkgs-ts/console/src/output/data-table/widths/columns.ts @@ -1,7 +1,7 @@ -import { visibleWidth } from '#tui/strings'; -import { availableDataTableCellWidth } from '#tui/output/data-table/widths/available'; -import { naturalDataTableColumnWidth } from '#tui/output/data-table/widths/natural'; -import { shrinkDataTableColumnWidths } from '#tui/output/data-table/widths/shrink'; +import { visibleWidth } from '#console/strings'; +import { availableDataTableCellWidth } from '#console/output/data-table/widths/available'; +import { naturalDataTableColumnWidth } from '#console/output/data-table/widths/natural'; +import { shrinkDataTableColumnWidths } from '#console/output/data-table/widths/shrink'; export const dataTableColumnWidths = (headers: string[], rows: string[][], maxWidth: number): number[] => { const columnCount = Math.max(headers.length, ...rows.map((row) => row.length)); diff --git a/packages/tui/src/output/data-table/widths/natural.ts b/pkgs-ts/console/src/output/data-table/widths/natural.ts similarity index 79% rename from packages/tui/src/output/data-table/widths/natural.ts rename to pkgs-ts/console/src/output/data-table/widths/natural.ts index 667db77c..e254bc1a 100644 --- a/packages/tui/src/output/data-table/widths/natural.ts +++ b/pkgs-ts/console/src/output/data-table/widths/natural.ts @@ -1,5 +1,5 @@ -import { visibleWidth } from '#tui/strings'; -import { splitMultilineDataTableCell } from '#tui/output/data-table/multiline'; +import { visibleWidth } from '#console/strings'; +import { splitMultilineDataTableCell } from '#console/output/data-table/multiline'; export const naturalDataTableColumnWidth = (rows: string[][], column: number): number => { const widths = rows diff --git a/packages/tui/src/output/data-table/widths/shrink.ts b/pkgs-ts/console/src/output/data-table/widths/shrink.ts similarity index 100% rename from packages/tui/src/output/data-table/widths/shrink.ts rename to pkgs-ts/console/src/output/data-table/widths/shrink.ts diff --git a/packages/tui/src/output/data-table/widths/truncate.ts b/pkgs-ts/console/src/output/data-table/widths/truncate.ts similarity index 81% rename from packages/tui/src/output/data-table/widths/truncate.ts rename to pkgs-ts/console/src/output/data-table/widths/truncate.ts index 28780424..015588dd 100644 --- a/packages/tui/src/output/data-table/widths/truncate.ts +++ b/pkgs-ts/console/src/output/data-table/widths/truncate.ts @@ -1,5 +1,5 @@ -import { truncate, visibleWidth } from '#tui/strings'; -import { splitMultilineDataTableCell } from '#tui/output/data-table/multiline'; +import { truncate, visibleWidth } from '#console/strings'; +import { splitMultilineDataTableCell } from '#console/output/data-table/multiline'; type TruncateDataTableColumnsOptions = { headers: string[]; diff --git a/packages/tui/src/output/data-table/widths/validators/dimensions.ts b/pkgs-ts/console/src/output/data-table/widths/validators/dimensions.ts similarity index 100% rename from packages/tui/src/output/data-table/widths/validators/dimensions.ts rename to pkgs-ts/console/src/output/data-table/widths/validators/dimensions.ts diff --git a/packages/tui/src/output/grid-output.ts b/pkgs-ts/console/src/output/grid-output.ts similarity index 68% rename from packages/tui/src/output/grid-output.ts rename to pkgs-ts/console/src/output/grid-output.ts index dd9ccaab..5ef89c67 100644 --- a/packages/tui/src/output/grid-output.ts +++ b/pkgs-ts/console/src/output/grid-output.ts @@ -1,5 +1,5 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderGrid } from '#tui/output/grid'; +import { promptEnvironment } from '#console/environment'; +import { renderGrid } from '#console/output/grid'; export const grid = (items: Array = [], maxWidth?: number): void => { const rendered = renderGrid(items, maxWidth); diff --git a/packages/tui/src/output/grid.ts b/pkgs-ts/console/src/output/grid.ts similarity index 62% rename from packages/tui/src/output/grid.ts rename to pkgs-ts/console/src/output/grid.ts index f80e47f3..3ca33b61 100644 --- a/packages/tui/src/output/grid.ts +++ b/pkgs-ts/console/src/output/grid.ts @@ -1,7 +1,7 @@ -import { createGridLayout } from '#tui/output/grid/layout'; -import { boxedGridLines } from '#tui/output/grid/lines'; -import { parseGridWidth } from '#tui/output/grid/validators/layout'; -import { terminalSize } from '#tui/terminal'; +import { createGridLayout } from '#console/output/grid/layout'; +import { boxedGridLines } from '#console/output/grid/lines'; +import { parseGridWidth } from '#console/output/grid/validators/layout'; +import { terminalSize } from '#console/terminal'; export const renderGrid = (items: Array = [], maxWidth?: number): string => { if (items.length === 0) { diff --git a/packages/tui/src/output/grid/layout.ts b/pkgs-ts/console/src/output/grid/layout.ts similarity index 92% rename from packages/tui/src/output/grid/layout.ts rename to pkgs-ts/console/src/output/grid/layout.ts index f11d182d..7e5a454a 100644 --- a/packages/tui/src/output/grid/layout.ts +++ b/pkgs-ts/console/src/output/grid/layout.ts @@ -1,5 +1,5 @@ -import { visibleWidth } from '#tui/strings'; -import { parseGridWidth } from '#tui/output/grid/validators/layout'; +import { visibleWidth } from '#console/strings'; +import { parseGridWidth } from '#console/output/grid/validators/layout'; export type GridLayout = { rows: string[][]; diff --git a/packages/tui/src/output/grid/lines.ts b/pkgs-ts/console/src/output/grid/lines.ts similarity index 88% rename from packages/tui/src/output/grid/lines.ts rename to pkgs-ts/console/src/output/grid/lines.ts index 66fb0b5d..2530c405 100644 --- a/packages/tui/src/output/grid/lines.ts +++ b/pkgs-ts/console/src/output/grid/lines.ts @@ -1,5 +1,5 @@ -import { visibleWidth } from '#tui/strings'; -import type { GridLayout } from '#tui/output/grid/layout'; +import { visibleWidth } from '#console/strings'; +import type { GridLayout } from '#console/output/grid/layout'; const padGridCell = (value: string, width: number): string => `${value}${' '.repeat(Math.max(0, width - visibleWidth(value)))}`; diff --git a/packages/tui/src/output/grid/validators/layout.ts b/pkgs-ts/console/src/output/grid/validators/layout.ts similarity index 100% rename from packages/tui/src/output/grid/validators/layout.ts rename to pkgs-ts/console/src/output/grid/validators/layout.ts diff --git a/packages/tui/src/output/notes.ts b/pkgs-ts/console/src/output/notes.ts similarity index 71% rename from packages/tui/src/output/notes.ts rename to pkgs-ts/console/src/output/notes.ts index 389542a5..cabc2638 100644 --- a/packages/tui/src/output/notes.ts +++ b/pkgs-ts/console/src/output/notes.ts @@ -1,8 +1,8 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderNoteLines } from '#tui/output/notes/render'; -import type { NoteType } from '#tui/output/notes/types'; +import { promptEnvironment } from '#console/environment'; +import { renderNoteLines } from '#console/output/notes/render'; +import type { NoteType } from '#console/output/notes/types'; -export type { NoteType } from '#tui/output/notes/types'; +export type { NoteType } from '#console/output/notes/types'; export const note = (message: string, type?: NoteType | null): void => { promptEnvironment().output.write(`${renderNoteLines(message, type).join('\n')}\n`); diff --git a/packages/tui/src/output/notes/render.ts b/pkgs-ts/console/src/output/notes/render.ts similarity index 82% rename from packages/tui/src/output/notes/render.ts rename to pkgs-ts/console/src/output/notes/render.ts index 9dcc0362..1550b190 100644 --- a/packages/tui/src/output/notes/render.ts +++ b/pkgs-ts/console/src/output/notes/render.ts @@ -1,7 +1,7 @@ -import { visibleWidth } from '#tui/strings'; -import { parseNoteMessageLines } from '#tui/output/notes/validators/message'; -import { backgroundCyan, backgroundRed, black, green, red, white, yellow } from '#tui/theme/styles'; -import type { NoteType } from '#tui/output/notes/types'; +import { visibleWidth } from '#console/strings'; +import { parseNoteMessageLines } from '#console/output/notes/validators/message'; +import { backgroundCyan, backgroundRed, black, green, red, white, yellow } from '#console/theme/styles'; +import type { NoteType } from '#console/output/notes/types'; const paddedIntroLines = (lines: string[]): string[] => { const padded = lines.map((line) => ` ${line} `); diff --git a/packages/tui/src/output/notes/types.ts b/pkgs-ts/console/src/output/notes/types.ts similarity index 100% rename from packages/tui/src/output/notes/types.ts rename to pkgs-ts/console/src/output/notes/types.ts diff --git a/packages/tui/src/output/notes/validators/message.ts b/pkgs-ts/console/src/output/notes/validators/message.ts similarity index 100% rename from packages/tui/src/output/notes/validators/message.ts rename to pkgs-ts/console/src/output/notes/validators/message.ts diff --git a/packages/tui/src/output/notify.ts b/pkgs-ts/console/src/output/notify.ts similarity index 76% rename from packages/tui/src/output/notify.ts rename to pkgs-ts/console/src/output/notify.ts index 7c327b9d..38170856 100644 --- a/packages/tui/src/output/notify.ts +++ b/pkgs-ts/console/src/output/notify.ts @@ -1,15 +1,15 @@ import { platform } from 'node:process'; -import { note } from '#tui/output/notes'; -import { notificationCommands } from '#tui/output/notify/commands'; -import { availableNotificationCommands, commandExists, executeNotificationCommand } from '#tui/output/notify/executor'; -import { parseNotificationPlatform } from '#tui/output/notify/validators/platform'; -import type { NotificationCommand, NotificationPlatform } from '#tui/output/notify/commands'; -import type { NotificationRuntime } from '#tui/output/notify/executor'; +import { note } from '#console/output/notes'; +import { notificationCommands } from '#console/output/notify/commands'; +import { availableNotificationCommands, commandExists, executeNotificationCommand } from '#console/output/notify/executor'; +import { parseNotificationPlatform } from '#console/output/notify/validators/platform'; +import type { NotificationCommand, NotificationPlatform } from '#console/output/notify/commands'; +import type { NotificationRuntime } from '#console/output/notify/executor'; export type { NotificationRuntime }; export type { NotificationCommand }; export type { NotificationPlatform }; -export type { NotificationOptions } from '#tui/output/notify/validators/options'; +export type { NotificationOptions } from '#console/output/notify/validators/options'; export { commandExists, executeNotificationCommand, notificationCommands }; export const notificationCommand = (targetPlatform: NotificationPlatform, title: string, body = '', subtitle = '', sound = '', icon = ''): NotificationCommand | null => { diff --git a/packages/tui/src/output/notify/commands.ts b/pkgs-ts/console/src/output/notify/commands.ts similarity index 80% rename from packages/tui/src/output/notify/commands.ts rename to pkgs-ts/console/src/output/notify/commands.ts index fc75860c..3eb11acc 100644 --- a/packages/tui/src/output/notify/commands.ts +++ b/pkgs-ts/console/src/output/notify/commands.ts @@ -1,13 +1,13 @@ -import { parseNotificationOptions } from '#tui/output/notify/validators/options'; -import type { NotificationPlatform } from '#tui/output/notify/validators/platform'; -import type { ResolvedNotificationOptions } from '#tui/output/notify/validators/options'; +import { parseNotificationOptions } from '#console/output/notify/validators/options'; +import type { NotificationPlatform } from '#console/output/notify/validators/platform'; +import type { ResolvedNotificationOptions } from '#console/output/notify/validators/options'; export type NotificationCommand = { args: string[]; bin: string; }; -export type { NotificationPlatform } from '#tui/output/notify/validators/platform'; +export type { NotificationPlatform } from '#console/output/notify/validators/platform'; const macOsNotificationCommand = (options: ResolvedNotificationOptions): NotificationCommand => { const script = [ diff --git a/packages/tui/src/output/notify/executor.ts b/pkgs-ts/console/src/output/notify/executor.ts similarity index 92% rename from packages/tui/src/output/notify/executor.ts rename to pkgs-ts/console/src/output/notify/executor.ts index f504f20e..df75b7b8 100644 --- a/packages/tui/src/output/notify/executor.ts +++ b/pkgs-ts/console/src/output/notify/executor.ts @@ -1,6 +1,6 @@ import { spawnSync } from 'node:child_process'; -import { parseNotificationCommand, parseNotificationCommandBin, parseNotificationCommands } from '#tui/output/notify/validators/command'; -import type { NotificationCommand, NotificationPlatform } from '#tui/output/notify/commands'; +import { parseNotificationCommand, parseNotificationCommandBin, parseNotificationCommands } from '#console/output/notify/validators/command'; +import type { NotificationCommand, NotificationPlatform } from '#console/output/notify/commands'; export type NotificationRuntime = { commandExists?: (bin: string) => boolean; diff --git a/packages/tui/src/output/notify/validators/command.ts b/pkgs-ts/console/src/output/notify/validators/command.ts similarity index 92% rename from packages/tui/src/output/notify/validators/command.ts rename to pkgs-ts/console/src/output/notify/validators/command.ts index 36133c62..82a0a8e0 100644 --- a/packages/tui/src/output/notify/validators/command.ts +++ b/pkgs-ts/console/src/output/notify/validators/command.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { NotificationCommand } from '#tui/output/notify/commands'; +import type { NotificationCommand } from '#console/output/notify/commands'; const notificationCommandBinSchema = z .string() diff --git a/packages/tui/src/output/notify/validators/options.ts b/pkgs-ts/console/src/output/notify/validators/options.ts similarity index 100% rename from packages/tui/src/output/notify/validators/options.ts rename to pkgs-ts/console/src/output/notify/validators/options.ts diff --git a/packages/tui/src/output/notify/validators/platform.ts b/pkgs-ts/console/src/output/notify/validators/platform.ts similarity index 100% rename from packages/tui/src/output/notify/validators/platform.ts rename to pkgs-ts/console/src/output/notify/validators/platform.ts diff --git a/packages/tui/src/output/table-output.ts b/pkgs-ts/console/src/output/table-output.ts similarity index 62% rename from packages/tui/src/output/table-output.ts rename to pkgs-ts/console/src/output/table-output.ts index 95920245..8f7086fb 100644 --- a/packages/tui/src/output/table-output.ts +++ b/pkgs-ts/console/src/output/table-output.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { parseTableOptions, tableRowCells } from '#tui/output/validators/table'; -import { renderTable } from '#tui/theme'; -import type { TableOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { parseTableOptions, tableRowCells } from '#console/output/validators/table'; +import { renderTable } from '#console/theme'; +import type { TableOptions } from '#console/types'; export const table = (headersOrOptions: TableOptions | string[] = [], rows: TableOptions['rows'] | null = null): void => { const options = parseTableOptions(headersOrOptions, rows); diff --git a/pkgs-ts/console/src/output/table.ts b/pkgs-ts/console/src/output/table.ts new file mode 100644 index 00000000..a16543fb --- /dev/null +++ b/pkgs-ts/console/src/output/table.ts @@ -0,0 +1,2 @@ +export { grid } from '#console/output/grid-output'; +export { dataTable, table } from '#console/output/table-output'; diff --git a/packages/tui/src/output/terminal.ts b/pkgs-ts/console/src/output/terminal.ts similarity index 66% rename from packages/tui/src/output/terminal.ts rename to pkgs-ts/console/src/output/terminal.ts index 4c1444d5..e7a2d40b 100644 --- a/packages/tui/src/output/terminal.ts +++ b/pkgs-ts/console/src/output/terminal.ts @@ -1,4 +1,4 @@ -import { clearTerminal, setTerminalTitle } from '#tui/terminal'; +import { clearTerminal, setTerminalTitle } from '#console/terminal'; export const title = (value: string): void => { setTerminalTitle(value); diff --git a/packages/tui/src/output/validators/cells.ts b/pkgs-ts/console/src/output/validators/cells.ts similarity index 85% rename from packages/tui/src/output/validators/cells.ts rename to pkgs-ts/console/src/output/validators/cells.ts index 96ae0a07..bd38ffdb 100644 --- a/packages/tui/src/output/validators/cells.ts +++ b/pkgs-ts/console/src/output/validators/cells.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { TableCell } from '#tui/types'; +import type { TableCell } from '#console/types'; export const tableCellSchema: z.ZodType = z.union([z.string(), z.number(), z.boolean(), z.null(), z.undefined()]); diff --git a/packages/tui/src/output/validators/data-table.ts b/pkgs-ts/console/src/output/validators/data-table.ts similarity index 58% rename from packages/tui/src/output/validators/data-table.ts rename to pkgs-ts/console/src/output/validators/data-table.ts index d70a3d9f..41680a7a 100644 --- a/packages/tui/src/output/validators/data-table.ts +++ b/pkgs-ts/console/src/output/validators/data-table.ts @@ -1,4 +1,4 @@ -export { dataTableStepName, isDataTablePromptOptions, parseDataTableDefault, parseDataTablePromptOptions, parseInitialDataTableRow } from '#tui/output/validators/data-table/options'; +export { dataTableStepName, isDataTablePromptOptions, parseDataTableDefault, parseDataTablePromptOptions, parseInitialDataTableRow } from '#console/output/validators/data-table/options'; export { isDataObjectRow, parseDataTableArrayHeaders, @@ -6,5 +6,5 @@ export { parseDataTableRecordHeaders, parseDataTableRowShape, parseDataTableRowValue, -} from '#tui/output/validators/data-table/row-shape'; -export type { DataTableRowShape } from '#tui/output/validators/data-table/row-shape'; +} from '#console/output/validators/data-table/row-shape'; +export type { DataTableRowShape } from '#console/output/validators/data-table/row-shape'; diff --git a/packages/tui/src/output/validators/data-table/options.ts b/pkgs-ts/console/src/output/validators/data-table/options.ts similarity index 93% rename from packages/tui/src/output/validators/data-table/options.ts rename to pkgs-ts/console/src/output/validators/data-table/options.ts index 4e900f9f..28101af1 100644 --- a/packages/tui/src/output/validators/data-table/options.ts +++ b/pkgs-ts/console/src/output/validators/data-table/options.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { dataTableHeadersSchema, dataTablePromptOptionsSchema, dataTableRowsSchema, dataTableStepNameSchema } from '#tui/output/validators/data-table/schemas'; -import type { DataTablePromptOptions, DataTableRow } from '#tui/types'; +import { dataTableHeadersSchema, dataTablePromptOptionsSchema, dataTableRowsSchema, dataTableStepNameSchema } from '#console/output/validators/data-table/schemas'; +import type { DataTablePromptOptions, DataTableRow } from '#console/types'; const dataTableDefaultSchema = (): z.ZodType => z.unknown() as z.ZodType; const dataTablePromptOptionsTypedSchema = (): z.ZodType> => dataTablePromptOptionsSchema as z.ZodType>; diff --git a/packages/tui/src/output/validators/data-table/row-shape.ts b/pkgs-ts/console/src/output/validators/data-table/row-shape.ts similarity index 95% rename from packages/tui/src/output/validators/data-table/row-shape.ts rename to pkgs-ts/console/src/output/validators/data-table/row-shape.ts index e249e91c..d9ba128f 100644 --- a/packages/tui/src/output/validators/data-table/row-shape.ts +++ b/pkgs-ts/console/src/output/validators/data-table/row-shape.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { dataObjectRowSchema, dataTableArrayRowSchema, dataTableRecordRowSchema } from '#tui/output/validators/data-table/schemas'; -import type { DataTableObjectRow, DataTableRow, TableCell } from '#tui/types'; +import { dataObjectRowSchema, dataTableArrayRowSchema, dataTableRecordRowSchema } from '#console/output/validators/data-table/schemas'; +import type { DataTableObjectRow, DataTableRow, TableCell } from '#console/types'; const typedDataObjectRowSchema = (): z.ZodType> => dataObjectRowSchema as z.ZodType>; const dataTableRowValueSchema = (): z.ZodType => z.unknown() as z.ZodType; diff --git a/packages/tui/src/output/validators/data-table/schemas.ts b/pkgs-ts/console/src/output/validators/data-table/schemas.ts similarity index 85% rename from packages/tui/src/output/validators/data-table/schemas.ts rename to pkgs-ts/console/src/output/validators/data-table/schemas.ts index ea81c4ad..cf80052d 100644 --- a/packages/tui/src/output/validators/data-table/schemas.ts +++ b/pkgs-ts/console/src/output/validators/data-table/schemas.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { tableCellArraySchema, tableCellRecordSchema } from '#tui/output/validators/cells'; -import type { DataTableObjectRow } from '#tui/types'; +import { tableCellArraySchema, tableCellRecordSchema } from '#console/output/validators/cells'; +import type { DataTableObjectRow } from '#console/types'; export const dataTableArrayRowSchema = tableCellArraySchema; diff --git a/packages/tui/src/output/validators/table.ts b/pkgs-ts/console/src/output/validators/table.ts similarity index 84% rename from packages/tui/src/output/validators/table.ts rename to pkgs-ts/console/src/output/validators/table.ts index 760d8045..a6f60786 100644 --- a/packages/tui/src/output/validators/table.ts +++ b/pkgs-ts/console/src/output/validators/table.ts @@ -1,8 +1,8 @@ -import { tableHeadersSchema, tableOptionsSchema, tableRowsSchema, tableStepNameSchema } from '#tui/output/validators/table/schemas'; -import { inferredTableHeaders } from '#tui/output/validators/table/rows'; -import type { TableOptions } from '#tui/types'; +import { tableHeadersSchema, tableOptionsSchema, tableRowsSchema, tableStepNameSchema } from '#console/output/validators/table/schemas'; +import { inferredTableHeaders } from '#console/output/validators/table/rows'; +import type { TableOptions } from '#console/types'; -export { tableRowCells } from '#tui/output/validators/table/rows'; +export { tableRowCells } from '#console/output/validators/table/rows'; export const isTableOptions = (value: unknown): value is TableOptions => { return tableOptionsSchema.safeParse(value).success; diff --git a/packages/tui/src/output/validators/table/rows.ts b/pkgs-ts/console/src/output/validators/table/rows.ts similarity index 84% rename from packages/tui/src/output/validators/table/rows.ts rename to pkgs-ts/console/src/output/validators/table/rows.ts index 4da15eab..7b9b78c9 100644 --- a/packages/tui/src/output/validators/table/rows.ts +++ b/pkgs-ts/console/src/output/validators/table/rows.ts @@ -1,5 +1,5 @@ -import { tableCellArraySchema, tableCellRecordSchema } from '#tui/output/validators/cells'; -import type { TableCell, TableOptions } from '#tui/types'; +import { tableCellArraySchema, tableCellRecordSchema } from '#console/output/validators/cells'; +import type { TableCell, TableOptions } from '#console/types'; export const inferredTableHeaders = (rows: TableOptions['rows']): string[] => { const firstRow = rows[0]; diff --git a/packages/tui/src/output/validators/table/schemas.ts b/pkgs-ts/console/src/output/validators/table/schemas.ts similarity index 74% rename from packages/tui/src/output/validators/table/schemas.ts rename to pkgs-ts/console/src/output/validators/table/schemas.ts index 6772fd0a..b72580ab 100644 --- a/packages/tui/src/output/validators/table/schemas.ts +++ b/pkgs-ts/console/src/output/validators/table/schemas.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { tableCellArraySchema, tableCellRecordSchema } from '#tui/output/validators/cells'; -import type { TableOptions } from '#tui/types'; +import { tableCellArraySchema, tableCellRecordSchema } from '#console/output/validators/cells'; +import type { TableOptions } from '#console/types'; export const tableRowSchema = z.union([tableCellArraySchema, tableCellRecordSchema]); diff --git a/pkgs-ts/console/src/prompt.ts b/pkgs-ts/console/src/prompt.ts new file mode 100644 index 00000000..af782341 --- /dev/null +++ b/pkgs-ts/console/src/prompt.ts @@ -0,0 +1,10 @@ +export { ask } from '#console/prompt/ask'; +export { cancelPrompt, cancelUsing } from '#console/prompt/cancel'; +export type { PromptCancelHandler } from '#console/prompt/cancel'; +export { PromptValidationError } from '#console/prompt/error'; +export { fallbackUsing, fallbackWhen, promptWithFallback, shouldFallback } from '#console/prompt/fallback'; +export type { PromptFallbackCondition, PromptFallbackHandler, PromptFallbackKind } from '#console/prompt/fallback'; +export { promptUntilValid } from '#console/prompt/lifecycle'; +export { validateUsing } from '#console/prompt/validate-using'; +export type { PromptGlobalValidator } from '#console/prompt/validate-using'; +export { ensureRequired, validationMessage } from '#console/prompt/validation'; diff --git a/packages/tui/src/prompt/active-frame.ts b/pkgs-ts/console/src/prompt/active-frame.ts similarity index 87% rename from packages/tui/src/prompt/active-frame.ts rename to pkgs-ts/console/src/prompt/active-frame.ts index d628b33a..8104476d 100644 --- a/packages/tui/src/prompt/active-frame.ts +++ b/pkgs-ts/console/src/prompt/active-frame.ts @@ -1,4 +1,4 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; +import { eraseRenderedFrame } from '#console/status/frame'; export type ActivePromptFrame = { clear: () => void; diff --git a/packages/tui/src/prompt/ask.ts b/pkgs-ts/console/src/prompt/ask.ts similarity index 65% rename from packages/tui/src/prompt/ask.ts rename to pkgs-ts/console/src/prompt/ask.ts index 8cfd2690..75fe1e15 100644 --- a/packages/tui/src/prompt/ask.ts +++ b/pkgs-ts/console/src/prompt/ask.ts @@ -1,6 +1,6 @@ -import { promptEnvironment } from '#tui/environment'; -import { PromptValidationError } from '#tui/prompt/error'; -import { renderQuestion } from '#tui/theme'; +import { promptEnvironment } from '#console/environment'; +import { PromptValidationError } from '#console/prompt/error'; +import { renderQuestion } from '#console/theme'; export const ask = async (message: string, hint?: string): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompt/cancel.ts b/pkgs-ts/console/src/prompt/cancel.ts similarity index 88% rename from packages/tui/src/prompt/cancel.ts rename to pkgs-ts/console/src/prompt/cancel.ts index a401d2f3..110bcc9f 100644 --- a/packages/tui/src/prompt/cancel.ts +++ b/pkgs-ts/console/src/prompt/cancel.ts @@ -1,6 +1,6 @@ import { AsyncLocalStorage } from 'node:async_hooks'; -import { parseCancelValue } from '#tui/prompt/validators/cancel'; -import type { MaybePromise } from '#tui/types'; +import { parseCancelValue } from '#console/prompt/validators/cancel'; +import type { MaybePromise } from '#console/types'; export type PromptCancelHandler = () => MaybePromise; diff --git a/packages/tui/src/prompt/error.ts b/pkgs-ts/console/src/prompt/error.ts similarity index 100% rename from packages/tui/src/prompt/error.ts rename to pkgs-ts/console/src/prompt/error.ts diff --git a/packages/tui/src/prompt/fallback.ts b/pkgs-ts/console/src/prompt/fallback.ts similarity index 96% rename from packages/tui/src/prompt/fallback.ts rename to pkgs-ts/console/src/prompt/fallback.ts index a6897412..541ce420 100644 --- a/packages/tui/src/prompt/fallback.ts +++ b/pkgs-ts/console/src/prompt/fallback.ts @@ -1,6 +1,6 @@ import { AsyncLocalStorage } from 'node:async_hooks'; -import { parseFallbackHandler, resolveFallbackCondition } from '#tui/prompt/validators/fallback'; -import type { MaybePromise } from '#tui/types'; +import { parseFallbackHandler, resolveFallbackCondition } from '#console/prompt/validators/fallback'; +import type { MaybePromise } from '#console/types'; export type PromptFallbackKind = 'autocomplete' | 'confirm' | 'datatable' | 'multisearch' | 'multiselect' | 'number' | 'password' | 'pause' | 'search' | 'select' | 'suggest' | 'text' | 'textarea'; diff --git a/packages/tui/src/prompt/lifecycle.ts b/pkgs-ts/console/src/prompt/lifecycle.ts similarity index 57% rename from packages/tui/src/prompt/lifecycle.ts rename to pkgs-ts/console/src/prompt/lifecycle.ts index bd08bab6..946ad0c8 100644 --- a/packages/tui/src/prompt/lifecycle.ts +++ b/pkgs-ts/console/src/prompt/lifecycle.ts @@ -1,8 +1,8 @@ -import { promptEnvironment } from '#tui/environment'; -import { resolveInteractivePrompt } from '#tui/prompt/lifecycle/interactive'; -import { resolveNonInteractivePrompt } from '#tui/prompt/lifecycle/non-interactive'; -import type { PromptInvalidHandler, PromptReader, PromptValidHandler } from '#tui/prompt/lifecycle/types'; -import type { BasePromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { resolveInteractivePrompt } from '#console/prompt/lifecycle/interactive'; +import { resolveNonInteractivePrompt } from '#console/prompt/lifecycle/non-interactive'; +import type { PromptInvalidHandler, PromptReader, PromptValidHandler } from '#console/prompt/lifecycle/types'; +import type { BasePromptOptions } from '#console/types'; export const promptUntilValid = async (options: BasePromptOptions, read: PromptReader, onValid?: PromptValidHandler, onInvalid?: PromptInvalidHandler): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompt/lifecycle/interactive.ts b/pkgs-ts/console/src/prompt/lifecycle/interactive.ts similarity index 67% rename from packages/tui/src/prompt/lifecycle/interactive.ts rename to pkgs-ts/console/src/prompt/lifecycle/interactive.ts index fa977cbc..f1c2f904 100644 --- a/packages/tui/src/prompt/lifecycle/interactive.ts +++ b/pkgs-ts/console/src/prompt/lifecycle/interactive.ts @@ -1,10 +1,10 @@ -import { promptEnvironment } from '#tui/environment'; -import { validatedPromptValue } from '#tui/prompt/lifecycle/validation'; -import { isPromptValidationError } from '#tui/prompt/validators/error'; -import { parseInvalidPromptValue } from '#tui/prompt/validators/invalid'; -import { renderError } from '#tui/theme'; -import type { PromptInvalidHandler, PromptReader, PromptValidHandler } from '#tui/prompt/lifecycle/types'; -import type { BasePromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { validatedPromptValue } from '#console/prompt/lifecycle/validation'; +import { isPromptValidationError } from '#console/prompt/validators/error'; +import { parseInvalidPromptValue } from '#console/prompt/validators/invalid'; +import { renderError } from '#console/theme'; +import type { PromptInvalidHandler, PromptReader, PromptValidHandler } from '#console/prompt/lifecycle/types'; +import type { BasePromptOptions } from '#console/types'; export const resolveInteractivePrompt = async (options: BasePromptOptions, read: PromptReader, onValid?: PromptValidHandler, onInvalid?: PromptInvalidHandler): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompt/lifecycle/non-interactive.ts b/pkgs-ts/console/src/prompt/lifecycle/non-interactive.ts similarity index 54% rename from packages/tui/src/prompt/lifecycle/non-interactive.ts rename to pkgs-ts/console/src/prompt/lifecycle/non-interactive.ts index 8de8ff22..6eb279ed 100644 --- a/packages/tui/src/prompt/lifecycle/non-interactive.ts +++ b/pkgs-ts/console/src/prompt/lifecycle/non-interactive.ts @@ -1,7 +1,7 @@ -import { PromptValidationError } from '#tui/prompt/error'; -import { validatedPromptValue } from '#tui/prompt/lifecycle/validation'; -import { parsePromptDefault } from '#tui/validators/default'; -import type { BasePromptOptions } from '#tui/types'; +import { PromptValidationError } from '#console/prompt/error'; +import { validatedPromptValue } from '#console/prompt/lifecycle/validation'; +import { parsePromptDefault } from '#console/validators/default'; +import type { BasePromptOptions } from '#console/types'; export const resolveNonInteractivePrompt = async (options: BasePromptOptions): Promise => { const value = parsePromptDefault(options.default); diff --git a/packages/tui/src/prompt/lifecycle/types.ts b/pkgs-ts/console/src/prompt/lifecycle/types.ts similarity index 100% rename from packages/tui/src/prompt/lifecycle/types.ts rename to pkgs-ts/console/src/prompt/lifecycle/types.ts diff --git a/packages/tui/src/prompt/lifecycle/validation.ts b/pkgs-ts/console/src/prompt/lifecycle/validation.ts similarity index 63% rename from packages/tui/src/prompt/lifecycle/validation.ts rename to pkgs-ts/console/src/prompt/lifecycle/validation.ts index 2131455a..bd5270b5 100644 --- a/packages/tui/src/prompt/lifecycle/validation.ts +++ b/pkgs-ts/console/src/prompt/lifecycle/validation.ts @@ -1,5 +1,5 @@ -import { ensureRequired, validationMessage } from '#tui/prompt/validation'; -import type { BasePromptOptions } from '#tui/types'; +import { ensureRequired, validationMessage } from '#console/prompt/validation'; +import type { BasePromptOptions } from '#console/types'; export const validatedPromptValue = async (options: BasePromptOptions, value: T): Promise => { return ensureRequired(value, options.required) ?? (await validationMessage(value, options.validate, options)); diff --git a/packages/tui/src/prompt/revert.ts b/pkgs-ts/console/src/prompt/revert.ts similarity index 54% rename from packages/tui/src/prompt/revert.ts rename to pkgs-ts/console/src/prompt/revert.ts index d47cdce1..8cc67692 100644 --- a/packages/tui/src/prompt/revert.ts +++ b/pkgs-ts/console/src/prompt/revert.ts @@ -1,5 +1,5 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderError } from '#tui/theme'; +import { promptEnvironment } from '#console/environment'; +import { renderError } from '#console/theme'; export const rejectPromptRevert = (): void => { promptEnvironment().error.write(renderError('This cannot be reverted.')); diff --git a/packages/tui/src/prompt/submission.ts b/pkgs-ts/console/src/prompt/submission.ts similarity index 100% rename from packages/tui/src/prompt/submission.ts rename to pkgs-ts/console/src/prompt/submission.ts diff --git a/packages/tui/src/prompt/validate-using.ts b/pkgs-ts/console/src/prompt/validate-using.ts similarity index 91% rename from packages/tui/src/prompt/validate-using.ts rename to pkgs-ts/console/src/prompt/validate-using.ts index 1bcf7e97..63a42bcb 100644 --- a/packages/tui/src/prompt/validate-using.ts +++ b/pkgs-ts/console/src/prompt/validate-using.ts @@ -1,6 +1,6 @@ import { AsyncLocalStorage } from 'node:async_hooks'; -import { parseGlobalValidationOptions } from '#tui/prompt/validators/global-validation'; -import type { BasePromptOptions, MaybePromise, ValidationResult } from '#tui/types'; +import { parseGlobalValidationOptions } from '#console/prompt/validators/global-validation'; +import type { BasePromptOptions, MaybePromise, ValidationResult } from '#console/types'; export type PromptGlobalValidator = (value: T, options: BasePromptOptions) => MaybePromise; diff --git a/packages/tui/src/prompt/validation.ts b/pkgs-ts/console/src/prompt/validation.ts similarity index 74% rename from packages/tui/src/prompt/validation.ts rename to pkgs-ts/console/src/prompt/validation.ts index 081ddae2..ccc4a380 100644 --- a/packages/tui/src/prompt/validation.ts +++ b/pkgs-ts/console/src/prompt/validation.ts @@ -1,7 +1,7 @@ -import { requiredMessage } from '#tui/validators/required'; -import { parseValidationResult } from '#tui/validators/result'; -import { globalValidationMessage } from '#tui/prompt/validate-using'; -import type { BasePromptOptions, Validator } from '#tui/types'; +import { requiredMessage } from '#console/validators/required'; +import { parseValidationResult } from '#console/validators/result'; +import { globalValidationMessage } from '#console/prompt/validate-using'; +import type { BasePromptOptions, Validator } from '#console/types'; const validationErrorMessage = (result: string | null | undefined): string | undefined => { if (result !== undefined && result !== null && result.length > 0) { diff --git a/packages/tui/src/prompt/validators/cancel.ts b/pkgs-ts/console/src/prompt/validators/cancel.ts similarity index 100% rename from packages/tui/src/prompt/validators/cancel.ts rename to pkgs-ts/console/src/prompt/validators/cancel.ts diff --git a/packages/tui/src/prompt/validators/error.ts b/pkgs-ts/console/src/prompt/validators/error.ts similarity index 80% rename from packages/tui/src/prompt/validators/error.ts rename to pkgs-ts/console/src/prompt/validators/error.ts index 9d7be16a..282d19a7 100644 --- a/packages/tui/src/prompt/validators/error.ts +++ b/pkgs-ts/console/src/prompt/validators/error.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { PromptValidationError } from '#tui/prompt/error'; +import { PromptValidationError } from '#console/prompt/error'; const promptValidationErrorSchema = z.instanceof(PromptValidationError); diff --git a/packages/tui/src/prompt/validators/fallback.ts b/pkgs-ts/console/src/prompt/validators/fallback.ts similarity index 83% rename from packages/tui/src/prompt/validators/fallback.ts rename to pkgs-ts/console/src/prompt/validators/fallback.ts index 3070bb88..e69a12e2 100644 --- a/packages/tui/src/prompt/validators/fallback.ts +++ b/pkgs-ts/console/src/prompt/validators/fallback.ts @@ -1,7 +1,7 @@ -import { functionSchema } from '#tui/validators/function'; +import { functionSchema } from '#console/validators/function'; import type { z } from 'zod'; -import type { PromptFallbackCondition } from '#tui/prompt/fallback'; -import type { PromptFallbackHandler } from '#tui/prompt/fallback'; +import type { PromptFallbackCondition } from '#console/prompt/fallback'; +import type { PromptFallbackHandler } from '#console/prompt/fallback'; type PromptFallbackConditionCallback = Exclude; diff --git a/packages/tui/src/prompt/validators/global-validation.ts b/pkgs-ts/console/src/prompt/validators/global-validation.ts similarity index 88% rename from packages/tui/src/prompt/validators/global-validation.ts rename to pkgs-ts/console/src/prompt/validators/global-validation.ts index c4b8767c..688ee3ac 100644 --- a/packages/tui/src/prompt/validators/global-validation.ts +++ b/pkgs-ts/console/src/prompt/validators/global-validation.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { BasePromptOptions } from '#tui/types'; +import type { BasePromptOptions } from '#console/types'; const globalValidationOptionsSchema = z.unknown() as z.ZodType>; diff --git a/packages/tui/src/prompt/validators/invalid.ts b/pkgs-ts/console/src/prompt/validators/invalid.ts similarity index 100% rename from packages/tui/src/prompt/validators/invalid.ts rename to pkgs-ts/console/src/prompt/validators/invalid.ts diff --git a/pkgs-ts/console/src/prompts.ts b/pkgs-ts/console/src/prompts.ts new file mode 100644 index 00000000..b3352d71 --- /dev/null +++ b/pkgs-ts/console/src/prompts.ts @@ -0,0 +1,3 @@ +export { number, password, text, textarea } from '#console/prompts/basic'; +export { autocomplete, confirm, multisearch, multiselect, pause, search, select, suggest } from '#console/prompts/choices'; +export type { SuggestOptions } from '#console/prompts/choices'; diff --git a/pkgs-ts/console/src/prompts/basic.ts b/pkgs-ts/console/src/prompts/basic.ts new file mode 100644 index 00000000..22380979 --- /dev/null +++ b/pkgs-ts/console/src/prompts/basic.ts @@ -0,0 +1,4 @@ +export { text } from '#console/prompts/text'; +export { textarea } from '#console/prompts/textarea'; +export { password } from '#console/prompts/password'; +export { number } from '#console/prompts/number'; diff --git a/pkgs-ts/console/src/prompts/choices.ts b/pkgs-ts/console/src/prompts/choices.ts new file mode 100644 index 00000000..5119553d --- /dev/null +++ b/pkgs-ts/console/src/prompts/choices.ts @@ -0,0 +1,5 @@ +export { confirm, multiselect, select } from '#console/prompts/select/index'; +export { autocomplete, suggest } from '#console/prompts/suggest/index'; +export { multisearch, search } from '#console/prompts/search/index'; +export { pause } from '#console/prompts/pause'; +export type { SuggestOptions } from '#console/prompts/suggest/index'; diff --git a/packages/tui/src/prompts/number.ts b/pkgs-ts/console/src/prompts/number.ts similarity index 84% rename from packages/tui/src/prompts/number.ts rename to pkgs-ts/console/src/prompts/number.ts index c8b6bcf3..06aca5ea 100644 --- a/packages/tui/src/prompts/number.ts +++ b/pkgs-ts/console/src/prompts/number.ts @@ -1,6 +1,6 @@ -import { normalizeNumberPromptOptions } from '#tui/prompts/number/options'; -import { runNumberPrompt } from '#tui/prompts/number/run'; -import type { NumberPromptOptions } from '#tui/types'; +import { normalizeNumberPromptOptions } from '#console/prompts/number/options'; +import { runNumberPrompt } from '#console/prompts/number/run'; +import type { NumberPromptOptions } from '#console/types'; export function number(options: NumberPromptOptions): Promise; diff --git a/packages/tui/src/prompts/number/defaults.ts b/pkgs-ts/console/src/prompts/number/defaults.ts similarity index 82% rename from packages/tui/src/prompts/number/defaults.ts rename to pkgs-ts/console/src/prompts/number/defaults.ts index 88984312..0627c1be 100644 --- a/packages/tui/src/prompts/number/defaults.ts +++ b/pkgs-ts/console/src/prompts/number/defaults.ts @@ -1,6 +1,6 @@ -import { PromptValidationError } from '#tui/prompt'; -import { parseNumberInput } from '#tui/prompts/number/validators/value'; -import type { NumberPromptOptions } from '#tui/types'; +import { PromptValidationError } from '#console/prompt'; +import { parseNumberInput } from '#console/prompts/number/validators/value'; +import type { NumberPromptOptions } from '#console/types'; export type NormalizedNumberPromptOptions = NumberPromptOptions & { default: number | string; diff --git a/packages/tui/src/prompts/number/fallback.ts b/pkgs-ts/console/src/prompts/number/fallback.ts similarity index 66% rename from packages/tui/src/prompts/number/fallback.ts rename to pkgs-ts/console/src/prompts/number/fallback.ts index 70bd08d5..9b08ac5f 100644 --- a/packages/tui/src/prompts/number/fallback.ts +++ b/pkgs-ts/console/src/prompts/number/fallback.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { PromptValidationError } from '#tui/prompt'; -import { renderQuestion } from '#tui/theme'; -import type { NumberInputOptions, NumberReadResult } from '#tui/prompts/number/types'; +import { promptEnvironment } from '#console/environment'; +import { PromptValidationError } from '#console/prompt'; +import { renderQuestion } from '#console/theme'; +import type { NumberInputOptions, NumberReadResult } from '#console/prompts/number/types'; export const readNumberFallbackValue = async (message: string, options: NumberInputOptions): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompts/number/input.ts b/pkgs-ts/console/src/prompts/number/input.ts similarity index 50% rename from packages/tui/src/prompts/number/input.ts rename to pkgs-ts/console/src/prompts/number/input.ts index 2373760c..953717b5 100644 --- a/packages/tui/src/prompts/number/input.ts +++ b/pkgs-ts/console/src/prompts/number/input.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { readNumberFallbackValue } from '#tui/prompts/number/fallback'; -import { readInteractiveNumberValue } from '#tui/prompts/number/interactive'; -import type { NumberInputOptions, NumberReadResult } from '#tui/prompts/number/types'; +import { promptEnvironment } from '#console/environment'; +import { readNumberFallbackValue } from '#console/prompts/number/fallback'; +import { readInteractiveNumberValue } from '#console/prompts/number/interactive'; +import type { NumberInputOptions, NumberReadResult } from '#console/prompts/number/types'; export const readNumberValue = async (message: string, options: NumberInputOptions = {}): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompts/number/interactive.ts b/pkgs-ts/console/src/prompts/number/interactive.ts similarity index 75% rename from packages/tui/src/prompts/number/interactive.ts rename to pkgs-ts/console/src/prompts/number/interactive.ts index ecd62798..c33560bf 100644 --- a/packages/tui/src/prompts/number/interactive.ts +++ b/pkgs-ts/console/src/prompts/number/interactive.ts @@ -1,8 +1,8 @@ -import { promptEnvironment } from '#tui/environment'; -import { Key } from '#tui/key'; -import { cancelPrompt } from '#tui/prompt'; -import { createNumberReaderSession } from '#tui/prompts/number/session'; -import type { NumberInputOptions, NumberReadResult } from '#tui/prompts/number/types'; +import { promptEnvironment } from '#console/environment'; +import { Key } from '#console/key'; +import { cancelPrompt } from '#console/prompt'; +import { createNumberReaderSession } from '#console/prompts/number/session'; +import type { NumberInputOptions, NumberReadResult } from '#console/prompts/number/types'; export const readInteractiveNumberValue = async (message: string, options: NumberInputOptions): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompts/number/options.ts b/pkgs-ts/console/src/prompts/number/options.ts similarity index 81% rename from packages/tui/src/prompts/number/options.ts rename to pkgs-ts/console/src/prompts/number/options.ts index d9587f36..7a5ee9b5 100644 --- a/packages/tui/src/prompts/number/options.ts +++ b/pkgs-ts/console/src/prompts/number/options.ts @@ -1,7 +1,7 @@ -import { hasNumberDefaultArgument, isNumberPromptLabel, parseNumberDefault } from '#tui/prompts/number/validators/overload'; -import { hasPromptDefault } from '#tui/validators/default'; -import type { NormalizedNumberPromptOptions } from '#tui/prompts/number/defaults'; -import type { NumberPromptOptions } from '#tui/types'; +import { hasNumberDefaultArgument, isNumberPromptLabel, parseNumberDefault } from '#console/prompts/number/validators/overload'; +import { hasPromptDefault } from '#console/validators/default'; +import type { NormalizedNumberPromptOptions } from '#console/prompts/number/defaults'; +import type { NumberPromptOptions } from '#console/types'; export type NumberPromptArgumentOptions = { defaultValue: number | string; diff --git a/packages/tui/src/prompts/number/render.ts b/pkgs-ts/console/src/prompts/number/render.ts similarity index 82% rename from packages/tui/src/prompts/number/render.ts rename to pkgs-ts/console/src/prompts/number/render.ts index 5774f253..01df69d8 100644 --- a/packages/tui/src/prompts/number/render.ts +++ b/pkgs-ts/console/src/prompts/number/render.ts @@ -1,9 +1,9 @@ -import { promptEnvironment } from '#tui/environment'; -import { parseNumericValue } from '#tui/prompts/number/validators/value'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red, strikethrough } from '#tui/theme/styles'; -import { placeholderWithCursor, valueWithCursor } from '#tui/typed-value/cursor'; -import type { NumberInputOptions } from '#tui/prompts/number/types'; +import { promptEnvironment } from '#console/environment'; +import { parseNumericValue } from '#console/prompts/number/validators/value'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red, strikethrough } from '#console/theme/styles'; +import { placeholderWithCursor, valueWithCursor } from '#console/typed-value/cursor'; +import type { NumberInputOptions } from '#console/prompts/number/types'; const UP_ARROW = '▲'; const DOWN_ARROW = '▼'; diff --git a/packages/tui/src/prompts/number/run.ts b/pkgs-ts/console/src/prompts/number/run.ts similarity index 75% rename from packages/tui/src/prompts/number/run.ts rename to pkgs-ts/console/src/prompts/number/run.ts index 8ba251e6..e48c6b43 100644 --- a/packages/tui/src/prompts/number/run.ts +++ b/pkgs-ts/console/src/prompts/number/run.ts @@ -1,12 +1,12 @@ -import { promptUntilValid, promptWithFallback, PromptValidationError } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { numberDefault, preserveNumberRetryDefault, transformNumberValue } from '#tui/prompts/number/defaults'; -import { readNumberValue } from '#tui/prompts/number/input'; -import { renderSubmittedNumberValue } from '#tui/prompts/number/render'; -import { parseNumberInput } from '#tui/prompts/number/validators/value'; -import type { NormalizedNumberPromptOptions } from '#tui/prompts/number/defaults'; -import type { NumberPromptOptions } from '#tui/types'; +import { promptUntilValid, promptWithFallback, PromptValidationError } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { numberDefault, preserveNumberRetryDefault, transformNumberValue } from '#console/prompts/number/defaults'; +import { readNumberValue } from '#console/prompts/number/input'; +import { renderSubmittedNumberValue } from '#console/prompts/number/render'; +import { parseNumberInput } from '#console/prompts/number/validators/value'; +import type { NormalizedNumberPromptOptions } from '#console/prompts/number/defaults'; +import type { NumberPromptOptions } from '#console/types'; export const runNumberPrompt = async (options: NormalizedNumberPromptOptions): Promise => { const validationOptions: NumberPromptOptions = { diff --git a/packages/tui/src/prompts/number/session.ts b/pkgs-ts/console/src/prompts/number/session.ts similarity index 84% rename from packages/tui/src/prompts/number/session.ts rename to pkgs-ts/console/src/prompts/number/session.ts index 1be619c9..0aa1284d 100644 --- a/packages/tui/src/prompts/number/session.ts +++ b/pkgs-ts/console/src/prompts/number/session.ts @@ -1,7 +1,7 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderCancelledNumberValue, renderNumberValue } from '#tui/prompts/number/render'; -import { applyNumberReaderInput, initialNumberReaderState, steppedNumberReaderState } from '#tui/prompts/number/session/state'; -import type { NumberInputOptions } from '#tui/prompts/number/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderCancelledNumberValue, renderNumberValue } from '#console/prompts/number/render'; +import { applyNumberReaderInput, initialNumberReaderState, steppedNumberReaderState } from '#console/prompts/number/session/state'; +import type { NumberInputOptions } from '#console/prompts/number/types'; export type NumberReaderSession = { applyTypedInput(key: string): { cancelled: boolean; submitted: boolean }; diff --git a/packages/tui/src/prompts/number/session/state.ts b/pkgs-ts/console/src/prompts/number/session/state.ts similarity index 79% rename from packages/tui/src/prompts/number/session/state.ts rename to pkgs-ts/console/src/prompts/number/session/state.ts index 81414cdb..f60eb23c 100644 --- a/packages/tui/src/prompts/number/session/state.ts +++ b/pkgs-ts/console/src/prompts/number/session/state.ts @@ -1,7 +1,7 @@ -import { applyTypedKey } from '#tui/typed-value'; -import { steppedNumberValue } from '#tui/prompts/number/step'; -import type { NumberInputOptions } from '#tui/prompts/number/types'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { applyTypedKey } from '#console/typed-value'; +import { steppedNumberValue } from '#console/prompts/number/step'; +import type { NumberInputOptions } from '#console/prompts/number/types'; +import type { TypedValueState } from '#console/typed-value/types'; export type NumberReaderState = TypedValueState; diff --git a/packages/tui/src/prompts/number/step.ts b/pkgs-ts/console/src/prompts/number/step.ts similarity index 78% rename from packages/tui/src/prompts/number/step.ts rename to pkgs-ts/console/src/prompts/number/step.ts index d1e3e284..83a09565 100644 --- a/packages/tui/src/prompts/number/step.ts +++ b/pkgs-ts/console/src/prompts/number/step.ts @@ -1,6 +1,6 @@ -import { parseNumberStep } from '#tui/prompts/number/validators/step'; -import { parseNumericValue } from '#tui/prompts/number/validators/value'; -import type { NumberInputOptions } from '#tui/prompts/number/types'; +import { parseNumberStep } from '#console/prompts/number/validators/step'; +import { parseNumericValue } from '#console/prompts/number/validators/value'; +import type { NumberInputOptions } from '#console/prompts/number/types'; const clamp = (value: number, min?: number, max?: number): number => { const clampedMin = min === undefined ? value : Math.max(min, value); diff --git a/packages/tui/src/prompts/number/types.ts b/pkgs-ts/console/src/prompts/number/types.ts similarity index 100% rename from packages/tui/src/prompts/number/types.ts rename to pkgs-ts/console/src/prompts/number/types.ts diff --git a/packages/tui/src/prompts/number/validators/overload.ts b/pkgs-ts/console/src/prompts/number/validators/overload.ts similarity index 100% rename from packages/tui/src/prompts/number/validators/overload.ts rename to pkgs-ts/console/src/prompts/number/validators/overload.ts diff --git a/packages/tui/src/prompts/number/validators/step.ts b/pkgs-ts/console/src/prompts/number/validators/step.ts similarity index 100% rename from packages/tui/src/prompts/number/validators/step.ts rename to pkgs-ts/console/src/prompts/number/validators/step.ts diff --git a/packages/tui/src/prompts/number/validators/value.ts b/pkgs-ts/console/src/prompts/number/validators/value.ts similarity index 95% rename from packages/tui/src/prompts/number/validators/value.ts rename to pkgs-ts/console/src/prompts/number/validators/value.ts index bcd260e7..c14e1f5c 100644 --- a/packages/tui/src/prompts/number/validators/value.ts +++ b/pkgs-ts/console/src/prompts/number/validators/value.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { NumberPromptOptions } from '#tui/types'; +import type { NumberPromptOptions } from '#console/types'; export type NumberPromptValue = number | string; diff --git a/packages/tui/src/prompts/password.ts b/pkgs-ts/console/src/prompts/password.ts similarity index 77% rename from packages/tui/src/prompts/password.ts rename to pkgs-ts/console/src/prompts/password.ts index 8d67e82d..8c681c36 100644 --- a/packages/tui/src/prompts/password.ts +++ b/pkgs-ts/console/src/prompts/password.ts @@ -1,6 +1,6 @@ -import { normalizePasswordPromptOptions } from '#tui/prompts/password/options'; -import { runPasswordPrompt } from '#tui/prompts/password/run'; -import type { TextPromptOptions } from '#tui/types'; +import { normalizePasswordPromptOptions } from '#console/prompts/password/options'; +import { runPasswordPrompt } from '#console/prompts/password/run'; +import type { TextPromptOptions } from '#console/types'; export function password(options: TextPromptOptions): Promise; diff --git a/packages/tui/src/prompts/password/fallback.ts b/pkgs-ts/console/src/prompts/password/fallback.ts similarity index 74% rename from packages/tui/src/prompts/password/fallback.ts rename to pkgs-ts/console/src/prompts/password/fallback.ts index 9fb8ca71..ba875371 100644 --- a/packages/tui/src/prompts/password/fallback.ts +++ b/pkgs-ts/console/src/prompts/password/fallback.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { PromptValidationError } from '#tui/prompt'; -import { renderQuestion } from '#tui/theme'; -import type { PasswordInputOptions, PasswordReadResult } from '#tui/prompts/password/types'; +import { promptEnvironment } from '#console/environment'; +import { PromptValidationError } from '#console/prompt'; +import { renderQuestion } from '#console/theme'; +import type { PasswordInputOptions, PasswordReadResult } from '#console/prompts/password/types'; export const readPasswordFallbackValue = async (message: string, options: PasswordInputOptions): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompts/password/input.ts b/pkgs-ts/console/src/prompts/password/input.ts similarity index 74% rename from packages/tui/src/prompts/password/input.ts rename to pkgs-ts/console/src/prompts/password/input.ts index c8090815..fbbbfc35 100644 --- a/packages/tui/src/prompts/password/input.ts +++ b/pkgs-ts/console/src/prompts/password/input.ts @@ -1,8 +1,8 @@ -import { promptEnvironment } from '#tui/environment'; -import { cancelPrompt } from '#tui/prompt'; -import { readPasswordFallbackValue } from '#tui/prompts/password/fallback'; -import { createPasswordReaderSession } from '#tui/prompts/password/session'; -import type { PasswordInputOptions, PasswordReadResult } from '#tui/prompts/password/types'; +import { promptEnvironment } from '#console/environment'; +import { cancelPrompt } from '#console/prompt'; +import { readPasswordFallbackValue } from '#console/prompts/password/fallback'; +import { createPasswordReaderSession } from '#console/prompts/password/session'; +import type { PasswordInputOptions, PasswordReadResult } from '#console/prompts/password/types'; export const readPasswordValue = async (message: string, options: PasswordInputOptions = {}): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompts/password/options.ts b/pkgs-ts/console/src/prompts/password/options.ts similarity index 77% rename from packages/tui/src/prompts/password/options.ts rename to pkgs-ts/console/src/prompts/password/options.ts index 6752a3eb..3f4fe4e3 100644 --- a/packages/tui/src/prompts/password/options.ts +++ b/pkgs-ts/console/src/prompts/password/options.ts @@ -1,6 +1,6 @@ -import { textOptions } from '#tui/concerns/text-options'; -import { isTextPromptLabel } from '#tui/concerns/validators/text-options'; -import type { TextPromptOptions } from '#tui/types'; +import { textOptions } from '#console/concerns/text-options'; +import { isTextPromptLabel } from '#console/concerns/validators/text-options'; +import type { TextPromptOptions } from '#console/types'; export type PasswordPromptArgumentOptions = { hint: string; diff --git a/packages/tui/src/prompts/password/render.ts b/pkgs-ts/console/src/prompts/password/render.ts similarity index 80% rename from packages/tui/src/prompts/password/render.ts rename to pkgs-ts/console/src/prompts/password/render.ts index 2d9bd378..ba80c3fa 100644 --- a/packages/tui/src/prompts/password/render.ts +++ b/pkgs-ts/console/src/prompts/password/render.ts @@ -1,8 +1,8 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red, strikethrough } from '#tui/theme/styles'; -import { valueWithCursor } from '#tui/typed-value/cursor'; -import type { PasswordInputOptions } from '#tui/prompts/password/types'; +import { promptEnvironment } from '#console/environment'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red, strikethrough } from '#console/theme/styles'; +import { valueWithCursor } from '#console/typed-value/cursor'; +import type { PasswordInputOptions } from '#console/prompts/password/types'; export const maskPassword = (value: string): string => '•'.repeat([...value].length); diff --git a/packages/tui/src/prompts/password/run.ts b/pkgs-ts/console/src/prompts/password/run.ts similarity index 70% rename from packages/tui/src/prompts/password/run.ts rename to pkgs-ts/console/src/prompts/password/run.ts index 6c2c51a5..52ed5b65 100644 --- a/packages/tui/src/prompts/password/run.ts +++ b/pkgs-ts/console/src/prompts/password/run.ts @@ -1,10 +1,10 @@ -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { readPasswordValue } from '#tui/prompts/password/input'; -import { renderSubmittedPasswordValue } from '#tui/prompts/password/render'; -import { transformedTextDefault } from '#tui/prompts/text-default'; -import type { TextPromptOptions } from '#tui/types'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { readPasswordValue } from '#console/prompts/password/input'; +import { renderSubmittedPasswordValue } from '#console/prompts/password/render'; +import { transformedTextDefault } from '#console/prompts/text-default'; +import type { TextPromptOptions } from '#console/types'; export const runPasswordPrompt = async (options: TextPromptOptions): Promise => { const validationOptions: TextPromptOptions = { diff --git a/packages/tui/src/prompts/password/session.ts b/pkgs-ts/console/src/prompts/password/session.ts similarity index 83% rename from packages/tui/src/prompts/password/session.ts rename to pkgs-ts/console/src/prompts/password/session.ts index 146c5140..3cd3530b 100644 --- a/packages/tui/src/prompts/password/session.ts +++ b/pkgs-ts/console/src/prompts/password/session.ts @@ -1,7 +1,7 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { applyTypedKey } from '#tui/typed-value'; -import { passwordLength, renderCancelledPasswordValue, renderPasswordValue } from '#tui/prompts/password/render'; -import type { PasswordInputOptions } from '#tui/prompts/password/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { applyTypedKey } from '#console/typed-value'; +import { passwordLength, renderCancelledPasswordValue, renderPasswordValue } from '#console/prompts/password/render'; +import type { PasswordInputOptions } from '#console/prompts/password/types'; export type PasswordReaderSession = { applyTypedInput(key: string): { cancelled: boolean; submitted: boolean }; diff --git a/packages/tui/src/prompts/password/types.ts b/pkgs-ts/console/src/prompts/password/types.ts similarity index 100% rename from packages/tui/src/prompts/password/types.ts rename to pkgs-ts/console/src/prompts/password/types.ts diff --git a/packages/tui/src/prompts/pause.ts b/pkgs-ts/console/src/prompts/pause.ts similarity index 60% rename from packages/tui/src/prompts/pause.ts rename to pkgs-ts/console/src/prompts/pause.ts index 84533ea7..fb718bc6 100644 --- a/packages/tui/src/prompts/pause.ts +++ b/pkgs-ts/console/src/prompts/pause.ts @@ -1,5 +1,5 @@ -import { promptWithFallback } from '#tui/prompt'; -import { readPauseConfirmation } from '#tui/prompts/pause/read'; +import { promptWithFallback } from '#console/prompt'; +import { readPauseConfirmation } from '#console/prompts/pause/read'; export const pause = async (message = 'Press enter to continue...'): Promise => { return promptWithFallback('pause', { message }, async () => readPauseConfirmation(message)); diff --git a/packages/tui/src/prompts/pause/read.ts b/pkgs-ts/console/src/prompts/pause/read.ts similarity index 73% rename from packages/tui/src/prompts/pause/read.ts rename to pkgs-ts/console/src/prompts/pause/read.ts index 6f09a2c9..8d5cbcbb 100644 --- a/packages/tui/src/prompts/pause/read.ts +++ b/pkgs-ts/console/src/prompts/pause/read.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { Key } from '#tui/key'; -import { ask, cancelPrompt } from '#tui/prompt'; -import { renderPause } from '#tui/prompts/pause/render'; +import { promptEnvironment } from '#console/environment'; +import { Key } from '#console/key'; +import { ask, cancelPrompt } from '#console/prompt'; +import { renderPause } from '#console/prompts/pause/render'; export const readPauseConfirmation = async (message: string): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompts/pause/render.ts b/pkgs-ts/console/src/prompts/pause/render.ts similarity index 59% rename from packages/tui/src/prompts/pause/render.ts rename to pkgs-ts/console/src/prompts/pause/render.ts index e78fb23b..a6ec7832 100644 --- a/packages/tui/src/prompts/pause/render.ts +++ b/pkgs-ts/console/src/prompts/pause/render.ts @@ -1,5 +1,5 @@ -import { renderBox } from '#tui/theme/box'; -import { cyan } from '#tui/theme/styles'; +import { renderBox } from '#console/theme/box'; +import { cyan } from '#console/theme/styles'; export const renderPause = (message: string): string => { return renderBox({ body: '', borderStyle: cyan, title: cyan(message) }); diff --git a/packages/tui/src/prompts/search/body/render.ts b/pkgs-ts/console/src/prompts/search/body/render.ts similarity index 70% rename from packages/tui/src/prompts/search/body/render.ts rename to pkgs-ts/console/src/prompts/search/body/render.ts index fc790bbd..35d134b2 100644 --- a/packages/tui/src/prompts/search/body/render.ts +++ b/pkgs-ts/console/src/prompts/search/body/render.ts @@ -1,7 +1,7 @@ -import { renderSearchRows } from '#tui/prompts/search/body/rows'; -import { dim } from '#tui/theme/styles'; -import { placeholderWithCursor, valueWithCursor } from '#tui/typed-value/cursor'; -import type { Choice } from '#tui/types'; +import { renderSearchRows } from '#console/prompts/search/body/rows'; +import { dim } from '#console/theme/styles'; +import { placeholderWithCursor, valueWithCursor } from '#console/typed-value/cursor'; +import type { Choice } from '#console/types'; export const renderSearchBody = ( query: string, diff --git a/packages/tui/src/prompts/search/body/rows.ts b/pkgs-ts/console/src/prompts/search/body/rows.ts similarity index 80% rename from packages/tui/src/prompts/search/body/rows.ts rename to pkgs-ts/console/src/prompts/search/body/rows.ts index c668c977..51dbe4ce 100644 --- a/packages/tui/src/prompts/search/body/rows.ts +++ b/pkgs-ts/console/src/prompts/search/body/rows.ts @@ -1,8 +1,8 @@ -import { choiceWindow } from '#tui/concerns/choices'; -import { choiceLabel } from '#tui/concerns/choice-label'; -import { renderScrollbarRows } from '#tui/concerns/scrollbar'; -import { cyan, dim } from '#tui/theme/styles'; -import type { Choice } from '#tui/types'; +import { choiceWindow } from '#console/concerns/choices'; +import { choiceLabel } from '#console/concerns/choice-label'; +import { renderScrollbarRows } from '#console/concerns/scrollbar'; +import { cyan, dim } from '#console/theme/styles'; +import type { Choice } from '#console/types'; export const renderSearchRows = (choices: Array>, highlighted: number | null, marked: Set, scroll: number | undefined, multiple: boolean): string => { const window = choiceWindow(choices.length, highlighted ?? 0, scroll); diff --git a/packages/tui/src/prompts/search/choices.ts b/pkgs-ts/console/src/prompts/search/choices.ts similarity index 72% rename from packages/tui/src/prompts/search/choices.ts rename to pkgs-ts/console/src/prompts/search/choices.ts index 883c18c2..b836fcfc 100644 --- a/packages/tui/src/prompts/search/choices.ts +++ b/pkgs-ts/console/src/prompts/search/choices.ts @@ -1,6 +1,6 @@ -import { normalizeSearchChoices } from '#tui/concerns/choices'; -import { resolveSearchChoiceSourceOptions } from '#tui/prompts/search/validators/source'; -import type { Choice, SearchPromptOptions } from '#tui/types'; +import { normalizeSearchChoices } from '#console/concerns/choices'; +import { resolveSearchChoiceSourceOptions } from '#console/prompts/search/validators/source'; +import type { Choice, SearchPromptOptions } from '#console/types'; export const resolveSearchChoices = async (source: SearchPromptOptions['options'], query: string): Promise>> => { const options = await resolveSearchChoiceSourceOptions(source, query); diff --git a/packages/tui/src/prompts/search/defaults.ts b/pkgs-ts/console/src/prompts/search/defaults.ts similarity index 93% rename from packages/tui/src/prompts/search/defaults.ts rename to pkgs-ts/console/src/prompts/search/defaults.ts index d604a929..812cc074 100644 --- a/packages/tui/src/prompts/search/defaults.ts +++ b/pkgs-ts/console/src/prompts/search/defaults.ts @@ -1,5 +1,5 @@ -import { parsePromptDefault } from '#tui/validators/default'; -import type { MultiSearchPromptOptions, SearchPromptOptions } from '#tui/types'; +import { parsePromptDefault } from '#console/validators/default'; +import type { MultiSearchPromptOptions, SearchPromptOptions } from '#console/types'; export type NormalizedSearchPromptOptions = SearchPromptOptions & { hasDefault: boolean; diff --git a/pkgs-ts/console/src/prompts/search/index.ts b/pkgs-ts/console/src/prompts/search/index.ts new file mode 100644 index 00000000..ba6bb9c9 --- /dev/null +++ b/pkgs-ts/console/src/prompts/search/index.ts @@ -0,0 +1,2 @@ +export { multisearch } from '#console/prompts/search/multisearch'; +export { search } from '#console/prompts/search/search'; diff --git a/pkgs-ts/console/src/prompts/search/keys.ts b/pkgs-ts/console/src/prompts/search/keys.ts new file mode 100644 index 00000000..e3926ebe --- /dev/null +++ b/pkgs-ts/console/src/prompts/search/keys.ts @@ -0,0 +1,4 @@ +export { clearsSearchHighlight, moveSearchHighlight } from '#console/prompts/search/keys/highlight'; +export type { MoveSearchHighlightOptions } from '#console/prompts/search/keys/highlight'; +export { searchNavigationAction } from '#console/prompts/search/keys/navigation'; +export type { SearchNavigationAction, SearchNavigationOptions } from '#console/prompts/search/keys/navigation'; diff --git a/packages/tui/src/prompts/search/keys/highlight.ts b/pkgs-ts/console/src/prompts/search/keys/highlight.ts similarity index 84% rename from packages/tui/src/prompts/search/keys/highlight.ts rename to pkgs-ts/console/src/prompts/search/keys/highlight.ts index de9a8672..a1587738 100644 --- a/packages/tui/src/prompts/search/keys/highlight.ts +++ b/pkgs-ts/console/src/prompts/search/keys/highlight.ts @@ -1,7 +1,7 @@ -import { Key, oneOf } from '#tui/key'; -import { firstSearchHighlight, lastSearchHighlight, nextRetriedSearchHighlight, nextSearchHighlight, pageSearchHighlight } from '#tui/prompts/search/navigation'; -import type { SearchNavigationAction } from '#tui/prompts/search/keys/navigation'; -import type { Choice } from '#tui/types'; +import { Key, oneOf } from '#console/key'; +import { firstSearchHighlight, lastSearchHighlight, nextRetriedSearchHighlight, nextSearchHighlight, pageSearchHighlight } from '#console/prompts/search/navigation'; +import type { SearchNavigationAction } from '#console/prompts/search/keys/navigation'; +import type { Choice } from '#console/types'; export type MoveSearchHighlightOptions = { attempt?: number; diff --git a/packages/tui/src/prompts/search/keys/navigation.ts b/pkgs-ts/console/src/prompts/search/keys/navigation.ts similarity index 95% rename from packages/tui/src/prompts/search/keys/navigation.ts rename to pkgs-ts/console/src/prompts/search/keys/navigation.ts index ad1eeff9..026fcb3b 100644 --- a/packages/tui/src/prompts/search/keys/navigation.ts +++ b/pkgs-ts/console/src/prompts/search/keys/navigation.ts @@ -1,4 +1,4 @@ -import { Key, oneOf } from '#tui/key'; +import { Key, oneOf } from '#console/key'; export type SearchNavigationAction = 'first' | 'last' | 'next' | 'page-next' | 'page-previous' | 'previous'; diff --git a/packages/tui/src/prompts/search/line-mode.ts b/pkgs-ts/console/src/prompts/search/line-mode.ts similarity index 83% rename from packages/tui/src/prompts/search/line-mode.ts rename to pkgs-ts/console/src/prompts/search/line-mode.ts index a17fb5c9..2a7e1433 100644 --- a/packages/tui/src/prompts/search/line-mode.ts +++ b/pkgs-ts/console/src/prompts/search/line-mode.ts @@ -1,8 +1,8 @@ -import { choiceByValue, choiceValueEquals, findChoice } from '#tui/concerns/choices'; -import { parseChoiceAnswerList } from '#tui/concerns/validators/choice-answer'; -import { PromptValidationError } from '#tui/prompt'; -import { resolveSearchChoices } from '#tui/prompts/search/choices'; -import type { Choice, MultiSearchPromptOptions, SearchPromptOptions } from '#tui/types'; +import { choiceByValue, choiceValueEquals, findChoice } from '#console/concerns/choices'; +import { parseChoiceAnswerList } from '#console/concerns/validators/choice-answer'; +import { PromptValidationError } from '#console/prompt'; +import { resolveSearchChoices } from '#console/prompts/search/choices'; +import type { Choice, MultiSearchPromptOptions, SearchPromptOptions } from '#console/types'; type SearchLineOptions = SearchPromptOptions & { hasDefault?: boolean; diff --git a/packages/tui/src/prompts/search/multi-options.ts b/pkgs-ts/console/src/prompts/search/multi-options.ts similarity index 74% rename from packages/tui/src/prompts/search/multi-options.ts rename to pkgs-ts/console/src/prompts/search/multi-options.ts index ff957983..eb098e90 100644 --- a/packages/tui/src/prompts/search/multi-options.ts +++ b/pkgs-ts/console/src/prompts/search/multi-options.ts @@ -1,7 +1,7 @@ -import { isSearchPromptLabel } from '#tui/prompts/search/validators/overload'; -import { parseMultiSearchDefault } from '#tui/prompts/search/validators/defaults'; -import { parseSearchChoiceSource } from '#tui/prompts/search/validators/source'; -import type { ChoiceOptions, MultiSearchPromptOptions } from '#tui/types'; +import { isSearchPromptLabel } from '#console/prompts/search/validators/overload'; +import { parseMultiSearchDefault } from '#console/prompts/search/validators/defaults'; +import { parseSearchChoiceSource } from '#console/prompts/search/validators/source'; +import type { ChoiceOptions, MultiSearchPromptOptions } from '#console/types'; export type NormalizedMultiSearchPromptOptions = MultiSearchPromptOptions & { default: T[]; diff --git a/packages/tui/src/prompts/search/multi-run.ts b/pkgs-ts/console/src/prompts/search/multi-run.ts similarity index 65% rename from packages/tui/src/prompts/search/multi-run.ts rename to pkgs-ts/console/src/prompts/search/multi-run.ts index 616876f8..7cc4b890 100644 --- a/packages/tui/src/prompts/search/multi-run.ts +++ b/pkgs-ts/console/src/prompts/search/multi-run.ts @@ -1,11 +1,11 @@ -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { preserveMultiSearchRetryDefault, transformedMultiSearchDefault } from '#tui/prompts/search/defaults'; -import { readMultiSearchChoices } from '#tui/prompts/search/read-multi'; -import { renderSubmittedSearchChoices } from '#tui/prompts/search/render'; -import type { NormalizedMultiSearchPromptOptions } from '#tui/prompts/search/multi-options'; -import type { MultiSearchPromptOptions } from '#tui/types'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { preserveMultiSearchRetryDefault, transformedMultiSearchDefault } from '#console/prompts/search/defaults'; +import { readMultiSearchChoices } from '#console/prompts/search/read-multi'; +import { renderSubmittedSearchChoices } from '#console/prompts/search/render'; +import type { NormalizedMultiSearchPromptOptions } from '#console/prompts/search/multi-options'; +import type { MultiSearchPromptOptions } from '#console/types'; export const runMultiSearchPrompt = async (options: NormalizedMultiSearchPromptOptions): Promise => { const validationOptions: MultiSearchPromptOptions = { diff --git a/packages/tui/src/prompts/search/multisearch.ts b/pkgs-ts/console/src/prompts/search/multisearch.ts similarity index 82% rename from packages/tui/src/prompts/search/multisearch.ts rename to pkgs-ts/console/src/prompts/search/multisearch.ts index 7f65e15d..a9134338 100644 --- a/packages/tui/src/prompts/search/multisearch.ts +++ b/pkgs-ts/console/src/prompts/search/multisearch.ts @@ -1,6 +1,6 @@ -import { normalizeMultiSearchPromptOptions } from '#tui/prompts/search/multi-options'; -import { runMultiSearchPrompt } from '#tui/prompts/search/multi-run'; -import type { ChoiceOptions, MultiSearchPromptOptions } from '#tui/types'; +import { normalizeMultiSearchPromptOptions } from '#console/prompts/search/multi-options'; +import { runMultiSearchPrompt } from '#console/prompts/search/multi-run'; +import type { ChoiceOptions, MultiSearchPromptOptions } from '#console/types'; export function multisearch(options: MultiSearchPromptOptions): Promise; diff --git a/packages/tui/src/prompts/search/navigation.ts b/pkgs-ts/console/src/prompts/search/navigation.ts similarity index 85% rename from packages/tui/src/prompts/search/navigation.ts rename to pkgs-ts/console/src/prompts/search/navigation.ts index bee523dd..f2551e17 100644 --- a/packages/tui/src/prompts/search/navigation.ts +++ b/pkgs-ts/console/src/prompts/search/navigation.ts @@ -1,7 +1,7 @@ -import { firstEnabledIndex, nextEnabledIndex } from '#tui/concerns/choices'; -import { lastEnabledIndex } from '#tui/prompts/search/choices'; -import { pageEnabledChoiceIndex } from '#tui/prompts/select/navigation'; -import type { Choice } from '#tui/types'; +import { firstEnabledIndex, nextEnabledIndex } from '#console/concerns/choices'; +import { lastEnabledIndex } from '#console/prompts/search/choices'; +import { pageEnabledChoiceIndex } from '#console/prompts/select/navigation'; +import type { Choice } from '#console/types'; export const firstSearchHighlight = (choices: Array>): number | null => { return choices.length === 0 ? null : firstEnabledIndex(choices); diff --git a/packages/tui/src/prompts/search/options.ts b/pkgs-ts/console/src/prompts/search/options.ts similarity index 67% rename from packages/tui/src/prompts/search/options.ts rename to pkgs-ts/console/src/prompts/search/options.ts index 4d4e966a..db463e9f 100644 --- a/packages/tui/src/prompts/search/options.ts +++ b/pkgs-ts/console/src/prompts/search/options.ts @@ -1,9 +1,9 @@ -import { assertSearchOptions } from '#tui/prompts/search/validators/options'; -import { isSearchPromptLabel } from '#tui/prompts/search/validators/overload'; -import { parseSearchChoiceSource } from '#tui/prompts/search/validators/source'; -import { hasPromptDefault } from '#tui/validators/default'; -import type { NormalizedSearchPromptOptions } from '#tui/prompts/search/defaults'; -import type { ChoiceOptions, SearchPromptOptions } from '#tui/types'; +import { assertSearchOptions } from '#console/prompts/search/validators/options'; +import { isSearchPromptLabel } from '#console/prompts/search/validators/overload'; +import { parseSearchChoiceSource } from '#console/prompts/search/validators/source'; +import { hasPromptDefault } from '#console/validators/default'; +import type { NormalizedSearchPromptOptions } from '#console/prompts/search/defaults'; +import type { ChoiceOptions, SearchPromptOptions } from '#console/types'; export const normalizeSearchPromptOptions = ( optionsOrLabel: SearchPromptOptions | string, diff --git a/packages/tui/src/prompts/search/read-multi.ts b/pkgs-ts/console/src/prompts/search/read-multi.ts similarity index 63% rename from packages/tui/src/prompts/search/read-multi.ts rename to pkgs-ts/console/src/prompts/search/read-multi.ts index 0c3d9af9..893dc9b5 100644 --- a/packages/tui/src/prompts/search/read-multi.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi.ts @@ -1,12 +1,12 @@ -import { promptEnvironment } from '#tui/environment'; -import { Key } from '#tui/key'; -import { cancelMultiSearchChoices } from '#tui/prompts/search/read-multi/cancel'; -import { applyMultiSearchKey } from '#tui/prompts/search/read-multi/keys'; -import { lineMultiSearchValues, selectedSearchValues } from '#tui/prompts/search/read-multi/result'; -import type { MultiSearchChoicesReadResult } from '#tui/prompts/search/read-multi/result'; -import { createMultiSearchReaderSession } from '#tui/prompts/search/read-multi/session'; -import type { MultiSearchReaderSession } from '#tui/prompts/search/read-multi/session'; -import type { MultiSearchPromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { Key } from '#console/key'; +import { cancelMultiSearchChoices } from '#console/prompts/search/read-multi/cancel'; +import { applyMultiSearchKey } from '#console/prompts/search/read-multi/keys'; +import { lineMultiSearchValues, selectedSearchValues } from '#console/prompts/search/read-multi/result'; +import type { MultiSearchChoicesReadResult } from '#console/prompts/search/read-multi/result'; +import { createMultiSearchReaderSession } from '#console/prompts/search/read-multi/session'; +import type { MultiSearchReaderSession } from '#console/prompts/search/read-multi/session'; +import type { MultiSearchPromptOptions } from '#console/types'; const multiSearchSelectionResult = (session: MultiSearchReaderSession, submitted: boolean): MultiSearchChoicesReadResult => ({ cancelled: false, diff --git a/pkgs-ts/console/src/prompts/search/read-multi/cancel.ts b/pkgs-ts/console/src/prompts/search/read-multi/cancel.ts new file mode 100644 index 00000000..ba222d06 --- /dev/null +++ b/pkgs-ts/console/src/prompts/search/read-multi/cancel.ts @@ -0,0 +1,21 @@ +import { cancelPrompt } from '#console/prompt'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderCancelledSearch } from '#console/prompts/search/render'; +import { selectedSearchValues } from '#console/prompts/search/read-multi/result'; +import type { MultiSearchChoicesReadResult } from '#console/prompts/search/read-multi/result'; +import type { MultiSearchReaderSession } from '#console/prompts/search/read-multi/session'; +import type { MultiSearchPromptOptions } from '#console/types'; + +export const cancelMultiSearchChoices = async (options: MultiSearchPromptOptions, session: MultiSearchReaderSession): Promise> => { + eraseRenderedFrame(session.frame()); + renderCancelledSearch(options.message, session.query().value, options.placeholder); + + const value = selectedSearchValues(session.selected()); + + return { + cancelled: true, + submitted: false, + submittedLabels: session.selectedLabels(), + value: await cancelPrompt(value), + }; +}; diff --git a/packages/tui/src/prompts/search/read-multi/choice-query.ts b/pkgs-ts/console/src/prompts/search/read-multi/choice-query.ts similarity index 71% rename from packages/tui/src/prompts/search/read-multi/choice-query.ts rename to pkgs-ts/console/src/prompts/search/read-multi/choice-query.ts index 924b6899..1ce970b8 100644 --- a/packages/tui/src/prompts/search/read-multi/choice-query.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/choice-query.ts @@ -1,9 +1,9 @@ -import { applyTypedKey } from '#tui/typed-value'; -import { resolveSearchChoices } from '#tui/prompts/search/choices'; -import { displayedSearchChoices } from '#tui/prompts/search/selection'; -import type { SearchSelection } from '#tui/prompts/search/selection'; -import type { TypedValueState } from '#tui/typed-value/types'; -import type { Choice, MultiSearchPromptOptions } from '#tui/types'; +import { applyTypedKey } from '#console/typed-value'; +import { resolveSearchChoices } from '#console/prompts/search/choices'; +import { displayedSearchChoices } from '#console/prompts/search/selection'; +import type { SearchSelection } from '#console/prompts/search/selection'; +import type { TypedValueState } from '#console/typed-value/types'; +import type { Choice, MultiSearchPromptOptions } from '#console/types'; export type MultiSearchChoiceQuery = { applyTypedInput(key: string): Promise<{ cancelled: boolean }>; diff --git a/packages/tui/src/prompts/search/read-multi/frame.ts b/pkgs-ts/console/src/prompts/search/read-multi/frame.ts similarity index 71% rename from packages/tui/src/prompts/search/read-multi/frame.ts rename to pkgs-ts/console/src/prompts/search/read-multi/frame.ts index 9fb3f17f..8a7d4b87 100644 --- a/packages/tui/src/prompts/search/read-multi/frame.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/frame.ts @@ -1,7 +1,7 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderSearchChoices } from '#tui/prompts/search/render'; -import type { MultiSearchReaderState } from '#tui/prompts/search/read-multi/state'; -import type { MultiSearchPromptOptions } from '#tui/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderSearchChoices } from '#console/prompts/search/render'; +import type { MultiSearchReaderState } from '#console/prompts/search/read-multi/state'; +import type { MultiSearchPromptOptions } from '#console/types'; export type MultiSearchFrameRenderer = { current(): string; diff --git a/packages/tui/src/prompts/search/read-multi/keys.ts b/pkgs-ts/console/src/prompts/search/read-multi/keys.ts similarity index 77% rename from packages/tui/src/prompts/search/read-multi/keys.ts rename to pkgs-ts/console/src/prompts/search/read-multi/keys.ts index 9c6ffecc..f76ba4ef 100644 --- a/packages/tui/src/prompts/search/read-multi/keys.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/keys.ts @@ -1,6 +1,6 @@ -import { Key } from '#tui/key'; -import { searchNavigationAction } from '#tui/prompts/search/keys'; -import type { MultiSearchReaderSession } from '#tui/prompts/search/read-multi/session'; +import { Key } from '#console/key'; +import { searchNavigationAction } from '#console/prompts/search/keys'; +import type { MultiSearchReaderSession } from '#console/prompts/search/read-multi/session'; export const applyMultiSearchKey = async (key: string, session: MultiSearchReaderSession): Promise => { const action = searchNavigationAction(key); diff --git a/packages/tui/src/prompts/search/read-multi/result.ts b/pkgs-ts/console/src/prompts/search/read-multi/result.ts similarity index 69% rename from packages/tui/src/prompts/search/read-multi/result.ts rename to pkgs-ts/console/src/prompts/search/read-multi/result.ts index 8ea86580..147418fc 100644 --- a/packages/tui/src/prompts/search/read-multi/result.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/result.ts @@ -1,8 +1,8 @@ -import { ask } from '#tui/prompt'; -import { resolveLineMultiSearchChoices } from '#tui/prompts/search/line-mode'; -import { toggleSearchChoice } from '#tui/prompts/search/selection'; -import type { SearchSelection } from '#tui/prompts/search/selection'; -import type { Choice, MultiSearchPromptOptions } from '#tui/types'; +import { ask } from '#console/prompt'; +import { resolveLineMultiSearchChoices } from '#console/prompts/search/line-mode'; +import { toggleSearchChoice } from '#console/prompts/search/selection'; +import type { SearchSelection } from '#console/prompts/search/selection'; +import type { Choice, MultiSearchPromptOptions } from '#console/types'; export type MultiSearchChoicesReadResult = { cancelled: boolean; diff --git a/packages/tui/src/prompts/search/read-multi/session.ts b/pkgs-ts/console/src/prompts/search/read-multi/session.ts similarity index 73% rename from packages/tui/src/prompts/search/read-multi/session.ts rename to pkgs-ts/console/src/prompts/search/read-multi/session.ts index 09fde679..9a41635f 100644 --- a/packages/tui/src/prompts/search/read-multi/session.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/session.ts @@ -1,16 +1,16 @@ -import { createMultiSearchFrameRenderer } from '#tui/prompts/search/read-multi/frame'; -import { createMultiSearchReaderState } from '#tui/prompts/search/read-multi/state'; -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { SearchSelection } from '#tui/prompts/search/selection'; -import type { TypedValueState } from '#tui/typed-value/types'; -import type { MultiSearchPromptOptions } from '#tui/types'; +import { createMultiSearchFrameRenderer } from '#console/prompts/search/read-multi/frame'; +import { createMultiSearchReaderState } from '#console/prompts/search/read-multi/state'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { SearchSelection } from '#console/prompts/search/selection'; +import type { TypedValueState } from '#console/typed-value/types'; +import type { MultiSearchPromptOptions } from '#console/types'; import { applyMultiSearchSessionTypedInput, moveMultiSearchSessionHighlight, toggleAllMultiSearchSessionDisplayed, toggleMultiSearchSessionHighlighted, -} from '#tui/prompts/search/read-multi/session/actions'; +} from '#console/prompts/search/read-multi/session/actions'; export type MultiSearchReaderSession = { applyTypedInput(key: string): Promise<{ cancelled: boolean }>; diff --git a/packages/tui/src/prompts/search/read-multi/session/actions.ts b/pkgs-ts/console/src/prompts/search/read-multi/session/actions.ts similarity index 77% rename from packages/tui/src/prompts/search/read-multi/session/actions.ts rename to pkgs-ts/console/src/prompts/search/read-multi/session/actions.ts index 7e156cfd..ed418f76 100644 --- a/packages/tui/src/prompts/search/read-multi/session/actions.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/session/actions.ts @@ -1,6 +1,6 @@ -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { MultiSearchFrameRenderer } from '#tui/prompts/search/read-multi/frame'; -import type { MultiSearchReaderState } from '#tui/prompts/search/read-multi/state'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { MultiSearchFrameRenderer } from '#console/prompts/search/read-multi/frame'; +import type { MultiSearchReaderState } from '#console/prompts/search/read-multi/state'; export const applyMultiSearchSessionTypedInput = async (state: MultiSearchReaderState, frame: MultiSearchFrameRenderer, key: string): Promise<{ cancelled: boolean }> => { const next = await state.applyTypedInput(key); diff --git a/packages/tui/src/prompts/search/read-multi/state.ts b/pkgs-ts/console/src/prompts/search/read-multi/state.ts similarity index 72% rename from packages/tui/src/prompts/search/read-multi/state.ts rename to pkgs-ts/console/src/prompts/search/read-multi/state.ts index aa7c12eb..1bb30f89 100644 --- a/packages/tui/src/prompts/search/read-multi/state.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/state.ts @@ -1,10 +1,10 @@ -import { createMultiSearchReaderStateContext } from '#tui/prompts/search/read-multi/state/context'; -import { applyMultiSearchTypedInput } from '#tui/prompts/search/read-multi/state/input'; -import { selectedMultiSearchLabels } from '#tui/prompts/search/read-multi/state/labels'; -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { SearchSelection } from '#tui/prompts/search/selection'; -import type { TypedValueState } from '#tui/typed-value/types'; -import type { Choice, MultiSearchPromptOptions } from '#tui/types'; +import { createMultiSearchReaderStateContext } from '#console/prompts/search/read-multi/state/context'; +import { applyMultiSearchTypedInput } from '#console/prompts/search/read-multi/state/input'; +import { selectedMultiSearchLabels } from '#console/prompts/search/read-multi/state/labels'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { SearchSelection } from '#console/prompts/search/selection'; +import type { TypedValueState } from '#console/typed-value/types'; +import type { Choice, MultiSearchPromptOptions } from '#console/types'; import { displayedMultiSearchChoices, @@ -12,7 +12,7 @@ import { moveDisplayedMultiSearchHighlight, toggleAllDisplayedMultiSearchSelection, toggleHighlightedDisplayedMultiSearchSelection, -} from '#tui/prompts/search/read-multi/state/displayed'; +} from '#console/prompts/search/read-multi/state/displayed'; export type MultiSearchReaderState = { applyTypedInput(key: string): Promise<{ cancelled: boolean }>; diff --git a/pkgs-ts/console/src/prompts/search/read-multi/state/context.ts b/pkgs-ts/console/src/prompts/search/read-multi/state/context.ts new file mode 100644 index 00000000..70f3366f --- /dev/null +++ b/pkgs-ts/console/src/prompts/search/read-multi/state/context.ts @@ -0,0 +1,26 @@ +import { resolveSearchChoices } from '#console/prompts/search/choices'; +import { createMultiSearchChoiceQuery } from '#console/prompts/search/read-multi/choice-query'; +import { createMultiSearchHighlightState } from '#console/prompts/search/read-multi/state/highlight'; +import { createMultiSearchSelection } from '#console/prompts/search/read-multi/state/selection'; +import type { MultiSearchChoiceQuery } from '#console/prompts/search/read-multi/choice-query'; +import type { MultiSearchHighlightState } from '#console/prompts/search/read-multi/state/highlight'; +import type { SearchSelection } from '#console/prompts/search/selection'; +import type { MultiSearchPromptOptions } from '#console/types'; + +export type MultiSearchReaderStateContext = { + highlighted: MultiSearchHighlightState; + query: MultiSearchChoiceQuery; + selected: SearchSelection; +}; + +export const createMultiSearchReaderStateContext = async (options: MultiSearchPromptOptions): Promise> => { + const initialChoices = await resolveSearchChoices(options.options, ''); + + const selected = createMultiSearchSelection(initialChoices, options.default); + + return { + highlighted: createMultiSearchHighlightState(options.scroll), + query: createMultiSearchChoiceQuery(options, selected, initialChoices), + selected, + }; +}; diff --git a/packages/tui/src/prompts/search/read-multi/state/displayed.ts b/pkgs-ts/console/src/prompts/search/read-multi/state/displayed.ts similarity index 71% rename from packages/tui/src/prompts/search/read-multi/state/displayed.ts rename to pkgs-ts/console/src/prompts/search/read-multi/state/displayed.ts index 8f6a7bb2..c22d5bc8 100644 --- a/packages/tui/src/prompts/search/read-multi/state/displayed.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/state/displayed.ts @@ -1,10 +1,10 @@ -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { MultiSearchChoiceQuery } from '#tui/prompts/search/read-multi/choice-query'; -import type { MultiSearchHighlightState } from '#tui/prompts/search/read-multi/state/highlight'; -import type { SearchSelection } from '#tui/prompts/search/selection'; -import type { Choice } from '#tui/types'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { MultiSearchChoiceQuery } from '#console/prompts/search/read-multi/choice-query'; +import type { MultiSearchHighlightState } from '#console/prompts/search/read-multi/state/highlight'; +import type { SearchSelection } from '#console/prompts/search/selection'; +import type { Choice } from '#console/types'; -import { markedMultiSearchChoiceIndexes, toggleAllDisplayedMultiSearchChoices, toggleHighlightedMultiSearchChoice } from '#tui/prompts/search/read-multi/state/selection'; +import { markedMultiSearchChoiceIndexes, toggleAllDisplayedMultiSearchChoices, toggleHighlightedMultiSearchChoice } from '#console/prompts/search/read-multi/state/selection'; export const displayedMultiSearchChoices = (query: MultiSearchChoiceQuery): Array> => { return query.displayedChoices(); diff --git a/packages/tui/src/prompts/search/read-multi/state/highlight.ts b/pkgs-ts/console/src/prompts/search/read-multi/state/highlight.ts similarity index 72% rename from packages/tui/src/prompts/search/read-multi/state/highlight.ts rename to pkgs-ts/console/src/prompts/search/read-multi/state/highlight.ts index 0a7abae6..aef6d94d 100644 --- a/packages/tui/src/prompts/search/read-multi/state/highlight.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/state/highlight.ts @@ -1,6 +1,6 @@ -import { moveSearchHighlight } from '#tui/prompts/search/keys'; -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { Choice, MultiSearchPromptOptions } from '#tui/types'; +import { moveSearchHighlight } from '#console/prompts/search/keys'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { Choice, MultiSearchPromptOptions } from '#console/types'; export type MultiSearchHighlightState = { clear(): void; diff --git a/packages/tui/src/prompts/search/read-multi/state/input.ts b/pkgs-ts/console/src/prompts/search/read-multi/state/input.ts similarity index 57% rename from packages/tui/src/prompts/search/read-multi/state/input.ts rename to pkgs-ts/console/src/prompts/search/read-multi/state/input.ts index 9812beb1..4aea86bf 100644 --- a/packages/tui/src/prompts/search/read-multi/state/input.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/state/input.ts @@ -1,5 +1,5 @@ -import type { MultiSearchChoiceQuery } from '#tui/prompts/search/read-multi/choice-query'; -import type { MultiSearchHighlightState } from '#tui/prompts/search/read-multi/state/highlight'; +import type { MultiSearchChoiceQuery } from '#console/prompts/search/read-multi/choice-query'; +import type { MultiSearchHighlightState } from '#console/prompts/search/read-multi/state/highlight'; export const applyMultiSearchTypedInput = async (query: MultiSearchChoiceQuery, highlighted: MultiSearchHighlightState, key: string): Promise<{ cancelled: boolean }> => { const next = await query.applyTypedInput(key); diff --git a/pkgs-ts/console/src/prompts/search/read-multi/state/labels.ts b/pkgs-ts/console/src/prompts/search/read-multi/state/labels.ts new file mode 100644 index 00000000..3845465c --- /dev/null +++ b/pkgs-ts/console/src/prompts/search/read-multi/state/labels.ts @@ -0,0 +1,6 @@ +import { multiSearchSelectedLabels } from '#console/prompts/search/read-multi/state/selection'; +import type { SearchSelection } from '#console/prompts/search/selection'; + +export const selectedMultiSearchLabels = (selected: SearchSelection): string[] => { + return multiSearchSelectedLabels(selected); +}; diff --git a/packages/tui/src/prompts/search/read-multi/state/selection.ts b/pkgs-ts/console/src/prompts/search/read-multi/state/selection.ts similarity index 77% rename from packages/tui/src/prompts/search/read-multi/state/selection.ts rename to pkgs-ts/console/src/prompts/search/read-multi/state/selection.ts index b372db2e..62d6d745 100644 --- a/packages/tui/src/prompts/search/read-multi/state/selection.ts +++ b/pkgs-ts/console/src/prompts/search/read-multi/state/selection.ts @@ -1,7 +1,7 @@ -import { createInitialSearchSelection, markedSearchChoiceIndexes, toggleSearchChoices } from '#tui/prompts/search/selection'; -import { toggleHighlightedSearchChoice } from '#tui/prompts/search/read-multi/result'; -import type { SearchSelection } from '#tui/prompts/search/selection'; -import type { Choice } from '#tui/types'; +import { createInitialSearchSelection, markedSearchChoiceIndexes, toggleSearchChoices } from '#console/prompts/search/selection'; +import { toggleHighlightedSearchChoice } from '#console/prompts/search/read-multi/result'; +import type { SearchSelection } from '#console/prompts/search/selection'; +import type { Choice } from '#console/types'; export const createMultiSearchSelection = (choices: Array>, defaults: T[] | undefined): SearchSelection => { return createInitialSearchSelection(choices, defaults); diff --git a/pkgs-ts/console/src/prompts/search/read-single.ts b/pkgs-ts/console/src/prompts/search/read-single.ts new file mode 100644 index 00000000..6dfddcdd --- /dev/null +++ b/pkgs-ts/console/src/prompts/search/read-single.ts @@ -0,0 +1,15 @@ +import { promptEnvironment } from '#console/environment'; +import { readSearchChoiceInteractive } from '#console/prompts/search/read-single/interactive'; +import { lineSearchValue } from '#console/prompts/search/read-single/result'; +import type { SearchChoiceReadResult } from '#console/prompts/search/read-single/result'; +import type { SearchReadOptions } from '#console/prompts/search/read-single/types'; + +export const readSearchChoice = async (options: SearchReadOptions, attempt = 0): Promise> => { + const environment = promptEnvironment(); + + if (!environment.input.readKey) { + return { cancelled: false, submitted: false, submittedLabel: '', value: await lineSearchValue(options) }; + } + + return readSearchChoiceInteractive(environment.input.readKey, options, attempt); +}; diff --git a/packages/tui/src/prompts/search/read-single/choice-query.ts b/pkgs-ts/console/src/prompts/search/read-single/choice-query.ts similarity index 74% rename from packages/tui/src/prompts/search/read-single/choice-query.ts rename to pkgs-ts/console/src/prompts/search/read-single/choice-query.ts index caa257c9..c6f5f5e5 100644 --- a/packages/tui/src/prompts/search/read-single/choice-query.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/choice-query.ts @@ -1,8 +1,8 @@ -import { applyTypedKey } from '#tui/typed-value'; -import { resolveSearchChoices } from '#tui/prompts/search/choices'; -import type { SearchReadOptions } from '#tui/prompts/search/read-single/types'; -import type { TypedValueState } from '#tui/typed-value/types'; -import type { Choice } from '#tui/types'; +import { applyTypedKey } from '#console/typed-value'; +import { resolveSearchChoices } from '#console/prompts/search/choices'; +import type { SearchReadOptions } from '#console/prompts/search/read-single/types'; +import type { TypedValueState } from '#console/typed-value/types'; +import type { Choice } from '#console/types'; export type SingleSearchChoiceQuery = { applyTypedInput(key: string): Promise<{ cancelled: boolean }>; diff --git a/packages/tui/src/prompts/search/read-single/interactive.ts b/pkgs-ts/console/src/prompts/search/read-single/interactive.ts similarity index 73% rename from packages/tui/src/prompts/search/read-single/interactive.ts rename to pkgs-ts/console/src/prompts/search/read-single/interactive.ts index de104b9e..aa5d4c7a 100644 --- a/packages/tui/src/prompts/search/read-single/interactive.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/interactive.ts @@ -1,11 +1,11 @@ -import { Key } from '#tui/key'; -import { clearsSearchHighlight, searchNavigationAction } from '#tui/prompts/search/keys'; -import { cancelInteractiveSearchChoice, cancelInteractiveSearchInput } from '#tui/prompts/search/read-single/interactive/cancel'; -import { defaultInteractiveSearchChoice, exhaustedInteractiveSearchChoice, highlightedInteractiveSearchChoice } from '#tui/prompts/search/read-single/interactive/result'; -import { createSearchReaderSession } from '#tui/prompts/search/read-single/session'; -import type { SearchChoiceReadResult } from '#tui/prompts/search/read-single/result'; -import type { SearchReadOptions } from '#tui/prompts/search/read-single/types'; -import type { PromptInput } from '#tui/types'; +import { Key } from '#console/key'; +import { clearsSearchHighlight, searchNavigationAction } from '#console/prompts/search/keys'; +import { cancelInteractiveSearchChoice, cancelInteractiveSearchInput } from '#console/prompts/search/read-single/interactive/cancel'; +import { defaultInteractiveSearchChoice, exhaustedInteractiveSearchChoice, highlightedInteractiveSearchChoice } from '#console/prompts/search/read-single/interactive/result'; +import { createSearchReaderSession } from '#console/prompts/search/read-single/session'; +import type { SearchChoiceReadResult } from '#console/prompts/search/read-single/result'; +import type { SearchReadOptions } from '#console/prompts/search/read-single/types'; +import type { PromptInput } from '#console/types'; export const readSearchChoiceInteractive = async (readKey: NonNullable, options: SearchReadOptions, attempt: number): Promise> => { const session = await createSearchReaderSession(options, attempt); diff --git a/packages/tui/src/prompts/search/read-single/interactive/cancel.ts b/pkgs-ts/console/src/prompts/search/read-single/interactive/cancel.ts similarity index 60% rename from packages/tui/src/prompts/search/read-single/interactive/cancel.ts rename to pkgs-ts/console/src/prompts/search/read-single/interactive/cancel.ts index 20c26473..2f00116b 100644 --- a/packages/tui/src/prompts/search/read-single/interactive/cancel.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/interactive/cancel.ts @@ -1,11 +1,11 @@ -import { cancelPrompt } from '#tui/prompt'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderCancelledSearch } from '#tui/prompts/search/render'; -import { cancelledSearchValue } from '#tui/prompts/search/read-single/result'; -import { fallbackSearchDefault } from '#tui/prompts/search/read-single/interactive/result'; -import type { SearchReaderSession } from '#tui/prompts/search/read-single/session'; -import type { SearchChoiceReadResult } from '#tui/prompts/search/read-single/result'; -import type { SearchReadOptions } from '#tui/prompts/search/read-single/types'; +import { cancelPrompt } from '#console/prompt'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderCancelledSearch } from '#console/prompts/search/render'; +import { cancelledSearchValue } from '#console/prompts/search/read-single/result'; +import { fallbackSearchDefault } from '#console/prompts/search/read-single/interactive/result'; +import type { SearchReaderSession } from '#console/prompts/search/read-single/session'; +import type { SearchChoiceReadResult } from '#console/prompts/search/read-single/result'; +import type { SearchReadOptions } from '#console/prompts/search/read-single/types'; const cancelInteractiveSearch = async (session: SearchReaderSession, options: SearchReadOptions, value: T | undefined): Promise> => { eraseRenderedFrame(session.frame()); diff --git a/packages/tui/src/prompts/search/read-single/interactive/result.ts b/pkgs-ts/console/src/prompts/search/read-single/interactive/result.ts similarity index 85% rename from packages/tui/src/prompts/search/read-single/interactive/result.ts rename to pkgs-ts/console/src/prompts/search/read-single/interactive/result.ts index 66d6fc97..8eff4394 100644 --- a/packages/tui/src/prompts/search/read-single/interactive/result.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/interactive/result.ts @@ -1,6 +1,6 @@ -import type { SearchReaderSession } from '#tui/prompts/search/read-single/session'; -import type { SearchChoiceReadResult } from '#tui/prompts/search/read-single/result'; -import type { SearchReadOptions } from '#tui/prompts/search/read-single/types'; +import type { SearchReaderSession } from '#console/prompts/search/read-single/session'; +import type { SearchChoiceReadResult } from '#console/prompts/search/read-single/result'; +import type { SearchReadOptions } from '#console/prompts/search/read-single/types'; export const fallbackSearchDefault = (options: SearchReadOptions): T | undefined => { return options.hasDefault === true ? options.default : undefined; diff --git a/packages/tui/src/prompts/search/read-single/result.ts b/pkgs-ts/console/src/prompts/search/read-single/result.ts similarity index 81% rename from packages/tui/src/prompts/search/read-single/result.ts rename to pkgs-ts/console/src/prompts/search/read-single/result.ts index 198e0fb2..0cf0fd23 100644 --- a/packages/tui/src/prompts/search/read-single/result.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/result.ts @@ -1,7 +1,7 @@ -import { ask } from '#tui/prompt'; -import { choiceByValue } from '#tui/concerns/choices'; -import { resolveLineSearchChoice } from '#tui/prompts/search/line-mode'; -import type { Choice, SearchPromptOptions } from '#tui/types'; +import { ask } from '#console/prompt'; +import { choiceByValue } from '#console/concerns/choices'; +import { resolveLineSearchChoice } from '#console/prompts/search/line-mode'; +import type { Choice, SearchPromptOptions } from '#console/types'; export type SearchChoiceReadResult = { cancelled: boolean; diff --git a/packages/tui/src/prompts/search/read-single/session.ts b/pkgs-ts/console/src/prompts/search/read-single/session.ts similarity index 73% rename from packages/tui/src/prompts/search/read-single/session.ts rename to pkgs-ts/console/src/prompts/search/read-single/session.ts index 8994dad9..67e19a80 100644 --- a/packages/tui/src/prompts/search/read-single/session.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/session.ts @@ -1,11 +1,11 @@ -import { createSearchReaderSessionFrame } from '#tui/prompts/search/read-single/session/frame'; -import { createSingleSearchReaderState } from '#tui/prompts/search/read-single/state'; -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { SearchReaderSelection, SearchReadOptions } from '#tui/prompts/search/read-single/types'; -import type { TypedValueState } from '#tui/typed-value/types'; -import type { Choice } from '#tui/types'; +import { createSearchReaderSessionFrame } from '#console/prompts/search/read-single/session/frame'; +import { createSingleSearchReaderState } from '#console/prompts/search/read-single/state'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { SearchReaderSelection, SearchReadOptions } from '#console/prompts/search/read-single/types'; +import type { TypedValueState } from '#console/typed-value/types'; +import type { Choice } from '#console/types'; -import { applySearchSessionTypedInput, clearSearchSessionHighlight, moveSearchSessionHighlight } from '#tui/prompts/search/read-single/session/actions'; +import { applySearchSessionTypedInput, clearSearchSessionHighlight, moveSearchSessionHighlight } from '#console/prompts/search/read-single/session/actions'; export type SearchReaderSession = { applyTypedInput(key: string): Promise<{ cancelled: boolean }>; diff --git a/packages/tui/src/prompts/search/read-single/session/actions.ts b/pkgs-ts/console/src/prompts/search/read-single/session/actions.ts similarity index 71% rename from packages/tui/src/prompts/search/read-single/session/actions.ts rename to pkgs-ts/console/src/prompts/search/read-single/session/actions.ts index 2d60f6a8..fe05d32f 100644 --- a/packages/tui/src/prompts/search/read-single/session/actions.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/session/actions.ts @@ -1,6 +1,6 @@ -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { SearchReaderSessionFrame } from '#tui/prompts/search/read-single/session/frame'; -import type { SingleSearchReaderState } from '#tui/prompts/search/read-single/state'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { SearchReaderSessionFrame } from '#console/prompts/search/read-single/session/frame'; +import type { SingleSearchReaderState } from '#console/prompts/search/read-single/state'; export const applySearchSessionTypedInput = async (state: SingleSearchReaderState, frame: SearchReaderSessionFrame, key: string): Promise<{ cancelled: boolean }> => { const next = await state.applyTypedInput(key); diff --git a/packages/tui/src/prompts/search/read-single/session/frame.ts b/pkgs-ts/console/src/prompts/search/read-single/session/frame.ts similarity index 66% rename from packages/tui/src/prompts/search/read-single/session/frame.ts rename to pkgs-ts/console/src/prompts/search/read-single/session/frame.ts index 62895009..beacb8f5 100644 --- a/packages/tui/src/prompts/search/read-single/session/frame.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/session/frame.ts @@ -1,7 +1,7 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderSearchChoices } from '#tui/prompts/search/render'; -import type { SingleSearchReaderState } from '#tui/prompts/search/read-single/state'; -import type { SearchReadOptions } from '#tui/prompts/search/read-single/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderSearchChoices } from '#console/prompts/search/render'; +import type { SingleSearchReaderState } from '#console/prompts/search/read-single/state'; +import type { SearchReadOptions } from '#console/prompts/search/read-single/types'; export type SearchReaderSessionFrame = { render(): void; diff --git a/packages/tui/src/prompts/search/read-single/state.ts b/pkgs-ts/console/src/prompts/search/read-single/state.ts similarity index 72% rename from packages/tui/src/prompts/search/read-single/state.ts rename to pkgs-ts/console/src/prompts/search/read-single/state.ts index e9ee2506..5bd16454 100644 --- a/packages/tui/src/prompts/search/read-single/state.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/state.ts @@ -1,11 +1,11 @@ -import { resolveSearchChoices } from '#tui/prompts/search/choices'; -import { createSingleSearchChoiceQuery } from '#tui/prompts/search/read-single/choice-query'; -import { createSingleSearchHighlightState } from '#tui/prompts/search/read-single/state/highlight'; -import { defaultSingleSearchSelection, selectedSingleSearchSelection } from '#tui/prompts/search/read-single/state/selection'; -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { SearchReaderSelection, SearchReadOptions } from '#tui/prompts/search/read-single/types'; -import type { TypedValueState } from '#tui/typed-value/types'; -import type { Choice } from '#tui/types'; +import { resolveSearchChoices } from '#console/prompts/search/choices'; +import { createSingleSearchChoiceQuery } from '#console/prompts/search/read-single/choice-query'; +import { createSingleSearchHighlightState } from '#console/prompts/search/read-single/state/highlight'; +import { defaultSingleSearchSelection, selectedSingleSearchSelection } from '#console/prompts/search/read-single/state/selection'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { SearchReaderSelection, SearchReadOptions } from '#console/prompts/search/read-single/types'; +import type { TypedValueState } from '#console/typed-value/types'; +import type { Choice } from '#console/types'; export type SingleSearchReaderState = { applyTypedInput(key: string): Promise<{ cancelled: boolean }>; diff --git a/packages/tui/src/prompts/search/read-single/state/highlight.ts b/pkgs-ts/console/src/prompts/search/read-single/state/highlight.ts similarity index 70% rename from packages/tui/src/prompts/search/read-single/state/highlight.ts rename to pkgs-ts/console/src/prompts/search/read-single/state/highlight.ts index 9e62b368..0e43aff0 100644 --- a/packages/tui/src/prompts/search/read-single/state/highlight.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/state/highlight.ts @@ -1,7 +1,7 @@ -import { moveSearchHighlight } from '#tui/prompts/search/keys'; -import { initialRetriedSearchHighlight } from '#tui/prompts/search/navigation'; -import type { SearchNavigationAction } from '#tui/prompts/search/keys'; -import type { Choice } from '#tui/types'; +import { moveSearchHighlight } from '#console/prompts/search/keys'; +import { initialRetriedSearchHighlight } from '#console/prompts/search/navigation'; +import type { SearchNavigationAction } from '#console/prompts/search/keys'; +import type { Choice } from '#console/types'; export type SingleSearchHighlightState = { clear(): void; diff --git a/packages/tui/src/prompts/search/read-single/state/selection.ts b/pkgs-ts/console/src/prompts/search/read-single/state/selection.ts similarity index 76% rename from packages/tui/src/prompts/search/read-single/state/selection.ts rename to pkgs-ts/console/src/prompts/search/read-single/state/selection.ts index 390824da..9d4bc3ba 100644 --- a/packages/tui/src/prompts/search/read-single/state/selection.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/state/selection.ts @@ -1,8 +1,8 @@ -import { choiceValueEquals } from '#tui/concerns/choices'; -import { defaultSearchChoice, selectedSearchValue } from '#tui/prompts/search/read-single/result'; -import type { SingleSearchChoiceQuery } from '#tui/prompts/search/read-single/choice-query'; -import type { SearchReaderSelection, SearchReadOptions } from '#tui/prompts/search/read-single/types'; -import type { Choice } from '#tui/types'; +import { choiceValueEquals } from '#console/concerns/choices'; +import { defaultSearchChoice, selectedSearchValue } from '#console/prompts/search/read-single/result'; +import type { SingleSearchChoiceQuery } from '#console/prompts/search/read-single/choice-query'; +import type { SearchReaderSelection, SearchReadOptions } from '#console/prompts/search/read-single/types'; +import type { Choice } from '#console/types'; export const defaultSingleSearchSelection = async (options: SearchReadOptions, query: SingleSearchChoiceQuery): Promise> => { await query.resolveChoices(); diff --git a/packages/tui/src/prompts/search/read-single/types.ts b/pkgs-ts/console/src/prompts/search/read-single/types.ts similarity index 76% rename from packages/tui/src/prompts/search/read-single/types.ts rename to pkgs-ts/console/src/prompts/search/read-single/types.ts index 867bde40..95ec11eb 100644 --- a/packages/tui/src/prompts/search/read-single/types.ts +++ b/pkgs-ts/console/src/prompts/search/read-single/types.ts @@ -1,4 +1,4 @@ -import type { SearchPromptOptions } from '#tui/types'; +import type { SearchPromptOptions } from '#console/types'; export type SearchReadOptions = SearchPromptOptions & { hasDefault?: boolean; diff --git a/pkgs-ts/console/src/prompts/search/render-body.ts b/pkgs-ts/console/src/prompts/search/render-body.ts new file mode 100644 index 00000000..26c6864c --- /dev/null +++ b/pkgs-ts/console/src/prompts/search/render-body.ts @@ -0,0 +1 @@ +export { renderSearchBody } from '#console/prompts/search/body/render'; diff --git a/packages/tui/src/prompts/search/render.ts b/pkgs-ts/console/src/prompts/search/render.ts similarity index 84% rename from packages/tui/src/prompts/search/render.ts rename to pkgs-ts/console/src/prompts/search/render.ts index fe112f2f..f74683d7 100644 --- a/packages/tui/src/prompts/search/render.ts +++ b/pkgs-ts/console/src/prompts/search/render.ts @@ -1,9 +1,9 @@ -import { promptEnvironment } from '#tui/environment'; -import { joinedInfoDetails, resolveInfo } from '#tui/concerns/info'; -import { renderSearchBody } from '#tui/prompts/search/render-body'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red, strikethrough } from '#tui/theme/styles'; -import type { Choice, MultiSearchPromptOptions, SearchPromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { joinedInfoDetails, resolveInfo } from '#console/concerns/info'; +import { renderSearchBody } from '#console/prompts/search/render-body'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red, strikethrough } from '#console/theme/styles'; +import type { Choice, MultiSearchPromptOptions, SearchPromptOptions } from '#console/types'; export const renderSearchChoices = ( message: string, diff --git a/packages/tui/src/prompts/search/run.ts b/pkgs-ts/console/src/prompts/search/run.ts similarity index 70% rename from packages/tui/src/prompts/search/run.ts rename to pkgs-ts/console/src/prompts/search/run.ts index 5da5bf25..0ca7ba89 100644 --- a/packages/tui/src/prompts/search/run.ts +++ b/pkgs-ts/console/src/prompts/search/run.ts @@ -1,11 +1,11 @@ -import { promptUntilValid, promptWithFallback, PromptValidationError } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { preserveSearchRetryDefault, transformSearchValue, transformedSearchDefault } from '#tui/prompts/search/defaults'; -import { readSearchChoice } from '#tui/prompts/search/read-single'; -import { renderSubmittedSearchChoice } from '#tui/prompts/search/render'; -import type { NormalizedSearchPromptOptions } from '#tui/prompts/search/defaults'; -import type { SearchPromptOptions } from '#tui/types'; +import { promptUntilValid, promptWithFallback, PromptValidationError } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { preserveSearchRetryDefault, transformSearchValue, transformedSearchDefault } from '#console/prompts/search/defaults'; +import { readSearchChoice } from '#console/prompts/search/read-single'; +import { renderSubmittedSearchChoice } from '#console/prompts/search/render'; +import type { NormalizedSearchPromptOptions } from '#console/prompts/search/defaults'; +import type { SearchPromptOptions } from '#console/types'; export const runSearchPrompt = async (options: NormalizedSearchPromptOptions): Promise => { const validationOptions: SearchPromptOptions = { diff --git a/packages/tui/src/prompts/search/search.ts b/pkgs-ts/console/src/prompts/search/search.ts similarity index 82% rename from packages/tui/src/prompts/search/search.ts rename to pkgs-ts/console/src/prompts/search/search.ts index 8c70533e..09e98b56 100644 --- a/packages/tui/src/prompts/search/search.ts +++ b/pkgs-ts/console/src/prompts/search/search.ts @@ -1,6 +1,6 @@ -import { normalizeSearchPromptOptions } from '#tui/prompts/search/options'; -import { runSearchPrompt } from '#tui/prompts/search/run'; -import type { ChoiceOptions, SearchPromptOptions } from '#tui/types'; +import { normalizeSearchPromptOptions } from '#console/prompts/search/options'; +import { runSearchPrompt } from '#console/prompts/search/run'; +import type { ChoiceOptions, SearchPromptOptions } from '#console/types'; export function search(options: SearchPromptOptions): Promise; diff --git a/packages/tui/src/prompts/search/selection.ts b/pkgs-ts/console/src/prompts/search/selection.ts similarity index 95% rename from packages/tui/src/prompts/search/selection.ts rename to pkgs-ts/console/src/prompts/search/selection.ts index b9906c7b..cdc92835 100644 --- a/packages/tui/src/prompts/search/selection.ts +++ b/pkgs-ts/console/src/prompts/search/selection.ts @@ -1,5 +1,5 @@ -import { choiceValueEquals } from '#tui/concerns/choices'; -import type { Choice } from '#tui/types'; +import { choiceValueEquals } from '#console/concerns/choices'; +import type { Choice } from '#console/types'; export type SearchSelection = Map; diff --git a/packages/tui/src/prompts/search/validators/defaults.ts b/pkgs-ts/console/src/prompts/search/validators/defaults.ts similarity index 100% rename from packages/tui/src/prompts/search/validators/defaults.ts rename to pkgs-ts/console/src/prompts/search/validators/defaults.ts diff --git a/packages/tui/src/prompts/search/validators/options.ts b/pkgs-ts/console/src/prompts/search/validators/options.ts similarity index 83% rename from packages/tui/src/prompts/search/validators/options.ts rename to pkgs-ts/console/src/prompts/search/validators/options.ts index 046e1ff3..f5f6be9f 100644 --- a/packages/tui/src/prompts/search/validators/options.ts +++ b/pkgs-ts/console/src/prompts/search/validators/options.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { SearchPromptOptions } from '#tui/types'; +import type { SearchPromptOptions } from '#console/types'; const disallowedRequiredSchema = z.literal(false); diff --git a/packages/tui/src/prompts/search/validators/overload.ts b/pkgs-ts/console/src/prompts/search/validators/overload.ts similarity index 100% rename from packages/tui/src/prompts/search/validators/overload.ts rename to pkgs-ts/console/src/prompts/search/validators/overload.ts diff --git a/packages/tui/src/prompts/search/validators/source.ts b/pkgs-ts/console/src/prompts/search/validators/source.ts similarity index 90% rename from packages/tui/src/prompts/search/validators/source.ts rename to pkgs-ts/console/src/prompts/search/validators/source.ts index a3c40101..d053d8ab 100644 --- a/packages/tui/src/prompts/search/validators/source.ts +++ b/pkgs-ts/console/src/prompts/search/validators/source.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; -import { choiceOptionsSchema } from '#tui/concerns/validators/choice'; -import { functionSchema } from '#tui/validators/function'; -import type { ChoiceOptions, MaybePromise, SearchPromptOptions } from '#tui/types'; +import { choiceOptionsSchema } from '#console/concerns/validators/choice'; +import { functionSchema } from '#console/validators/function'; +import type { ChoiceOptions, MaybePromise, SearchPromptOptions } from '#console/types'; type SearchChoiceSourceCallback = (query: string) => MaybePromise>; diff --git a/packages/tui/src/prompts/select/confirm-options.ts b/pkgs-ts/console/src/prompts/select/confirm-options.ts similarity index 90% rename from packages/tui/src/prompts/select/confirm-options.ts rename to pkgs-ts/console/src/prompts/select/confirm-options.ts index f60f9e74..709e02e2 100644 --- a/packages/tui/src/prompts/select/confirm-options.ts +++ b/pkgs-ts/console/src/prompts/select/confirm-options.ts @@ -1,6 +1,6 @@ -import { hasConfirmDefaultArgument, isSelectPromptLabel, parseConfirmDefault } from '#tui/prompts/select/validators/overload'; -import { hasPromptDefault } from '#tui/validators/default'; -import type { ConfirmPromptOptions } from '#tui/types'; +import { hasConfirmDefaultArgument, isSelectPromptLabel, parseConfirmDefault } from '#console/prompts/select/validators/overload'; +import { hasPromptDefault } from '#console/validators/default'; +import type { ConfirmPromptOptions } from '#console/types'; export type NormalizedConfirmPromptOptions = ConfirmPromptOptions & { default: boolean; diff --git a/packages/tui/src/prompts/select/confirm-run.ts b/pkgs-ts/console/src/prompts/select/confirm-run.ts similarity index 63% rename from packages/tui/src/prompts/select/confirm-run.ts rename to pkgs-ts/console/src/prompts/select/confirm-run.ts index bca1688f..4c1d5230 100644 --- a/packages/tui/src/prompts/select/confirm-run.ts +++ b/pkgs-ts/console/src/prompts/select/confirm-run.ts @@ -1,11 +1,11 @@ -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { preserveConfirmRetryDefault, transformedConfirmDefault, transformConfirmValue } from '#tui/prompts/select/confirm-options'; -import { readConfirm } from '#tui/prompts/select/read-confirm'; -import { renderSubmittedConfirm } from '#tui/prompts/select/render-confirm'; -import type { NormalizedConfirmPromptOptions } from '#tui/prompts/select/confirm-options'; -import type { ConfirmPromptOptions } from '#tui/types'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { preserveConfirmRetryDefault, transformedConfirmDefault, transformConfirmValue } from '#console/prompts/select/confirm-options'; +import { readConfirm } from '#console/prompts/select/read-confirm'; +import { renderSubmittedConfirm } from '#console/prompts/select/render-confirm'; +import type { NormalizedConfirmPromptOptions } from '#console/prompts/select/confirm-options'; +import type { ConfirmPromptOptions } from '#console/types'; export const runConfirmPrompt = async (options: NormalizedConfirmPromptOptions): Promise => { const validationOptions: ConfirmPromptOptions = { diff --git a/packages/tui/src/prompts/select/confirm.ts b/pkgs-ts/console/src/prompts/select/confirm.ts similarity index 83% rename from packages/tui/src/prompts/select/confirm.ts rename to pkgs-ts/console/src/prompts/select/confirm.ts index e95786a7..3287bb3d 100644 --- a/packages/tui/src/prompts/select/confirm.ts +++ b/pkgs-ts/console/src/prompts/select/confirm.ts @@ -1,6 +1,6 @@ -import { confirmHasDefault, normalizeConfirmPromptOptions } from '#tui/prompts/select/confirm-options'; -import { runConfirmPrompt } from '#tui/prompts/select/confirm-run'; -import type { ConfirmPromptOptions } from '#tui/types'; +import { confirmHasDefault, normalizeConfirmPromptOptions } from '#console/prompts/select/confirm-options'; +import { runConfirmPrompt } from '#console/prompts/select/confirm-run'; +import type { ConfirmPromptOptions } from '#console/types'; export function confirm(options: ConfirmPromptOptions): Promise; diff --git a/packages/tui/src/prompts/select/defaults.ts b/pkgs-ts/console/src/prompts/select/defaults.ts similarity index 93% rename from packages/tui/src/prompts/select/defaults.ts rename to pkgs-ts/console/src/prompts/select/defaults.ts index 39502cca..52ecc424 100644 --- a/packages/tui/src/prompts/select/defaults.ts +++ b/pkgs-ts/console/src/prompts/select/defaults.ts @@ -1,5 +1,5 @@ -import { parsePromptDefault } from '#tui/validators/default'; -import type { MultiSelectPromptOptions, SelectPromptOptions } from '#tui/types'; +import { parsePromptDefault } from '#console/validators/default'; +import type { MultiSelectPromptOptions, SelectPromptOptions } from '#console/types'; export type NormalizedSelectPromptOptions = SelectPromptOptions & { hasDefault: boolean; diff --git a/pkgs-ts/console/src/prompts/select/index.ts b/pkgs-ts/console/src/prompts/select/index.ts new file mode 100644 index 00000000..e635f558 --- /dev/null +++ b/pkgs-ts/console/src/prompts/select/index.ts @@ -0,0 +1,3 @@ +export { confirm } from '#console/prompts/select/confirm'; +export { multiselect } from '#console/prompts/select/multiselect'; +export { select } from '#console/prompts/select/select'; diff --git a/packages/tui/src/prompts/select/keys.ts b/pkgs-ts/console/src/prompts/select/keys.ts similarity index 85% rename from packages/tui/src/prompts/select/keys.ts rename to pkgs-ts/console/src/prompts/select/keys.ts index 36a12d9f..ba82017a 100644 --- a/packages/tui/src/prompts/select/keys.ts +++ b/pkgs-ts/console/src/prompts/select/keys.ts @@ -1,7 +1,7 @@ -import { Key, oneOf } from '#tui/key'; -import { firstEnabledIndex, nextEnabledIndex } from '#tui/concerns/choices'; -import { lastEnabledChoiceIndex, nextChoiceKeys, pageEnabledChoiceIndex, previousChoiceKeys } from '#tui/prompts/select/navigation'; -import type { Choice } from '#tui/types'; +import { Key, oneOf } from '#console/key'; +import { firstEnabledIndex, nextEnabledIndex } from '#console/concerns/choices'; +import { lastEnabledChoiceIndex, nextChoiceKeys, pageEnabledChoiceIndex, previousChoiceKeys } from '#console/prompts/select/navigation'; +import type { Choice } from '#console/types'; export type SelectNavigationAction = 'first' | 'last' | 'next' | 'page-next' | 'page-previous' | 'previous'; diff --git a/packages/tui/src/prompts/select/multiple.ts b/pkgs-ts/console/src/prompts/select/multiple.ts similarity index 87% rename from packages/tui/src/prompts/select/multiple.ts rename to pkgs-ts/console/src/prompts/select/multiple.ts index 20d20943..4fbd3f5e 100644 --- a/packages/tui/src/prompts/select/multiple.ts +++ b/pkgs-ts/console/src/prompts/select/multiple.ts @@ -1,7 +1,7 @@ -import { choiceValueEquals, findChoice } from '#tui/concerns/choices'; -import { parseChoiceAnswerList } from '#tui/concerns/validators/choice-answer'; -import { PromptValidationError } from '#tui/prompt'; -import type { Choice } from '#tui/types'; +import { choiceValueEquals, findChoice } from '#console/concerns/choices'; +import { parseChoiceAnswerList } from '#console/concerns/validators/choice-answer'; +import { PromptValidationError } from '#console/prompt'; +import type { Choice } from '#console/types'; export const choicesFromCommaSeparated = (choices: Array>, answer: string): T[] => { const parts = parseChoiceAnswerList(answer); diff --git a/packages/tui/src/prompts/select/multiselect.ts b/pkgs-ts/console/src/prompts/select/multiselect.ts similarity index 80% rename from packages/tui/src/prompts/select/multiselect.ts rename to pkgs-ts/console/src/prompts/select/multiselect.ts index 8de52e50..cf14c7fd 100644 --- a/packages/tui/src/prompts/select/multiselect.ts +++ b/pkgs-ts/console/src/prompts/select/multiselect.ts @@ -1,6 +1,6 @@ -import { normalizeMultiSelectPromptOptions } from '#tui/prompts/select/multiselect/options'; -import { runMultiSelectPrompt } from '#tui/prompts/select/multiselect/run'; -import type { ChoiceOptions, MultiSelectPromptOptions } from '#tui/types'; +import { normalizeMultiSelectPromptOptions } from '#console/prompts/select/multiselect/options'; +import { runMultiSelectPrompt } from '#console/prompts/select/multiselect/run'; +import type { ChoiceOptions, MultiSelectPromptOptions } from '#console/types'; export function multiselect(options: MultiSelectPromptOptions): Promise; diff --git a/packages/tui/src/prompts/select/multiselect/options.ts b/pkgs-ts/console/src/prompts/select/multiselect/options.ts similarity index 81% rename from packages/tui/src/prompts/select/multiselect/options.ts rename to pkgs-ts/console/src/prompts/select/multiselect/options.ts index 8312d77f..a6d1c7b4 100644 --- a/packages/tui/src/prompts/select/multiselect/options.ts +++ b/pkgs-ts/console/src/prompts/select/multiselect/options.ts @@ -1,6 +1,6 @@ -import { isSelectPromptLabel, parseSelectChoiceOptions } from '#tui/prompts/select/validators/overload'; -import { parseMultiSelectDefault } from '#tui/prompts/select/validators/defaults'; -import type { ChoiceOptions, MultiSelectPromptOptions } from '#tui/types'; +import { isSelectPromptLabel, parseSelectChoiceOptions } from '#console/prompts/select/validators/overload'; +import { parseMultiSelectDefault } from '#console/prompts/select/validators/defaults'; +import type { ChoiceOptions, MultiSelectPromptOptions } from '#console/types'; export type NormalizedMultiSelectPromptOptions = MultiSelectPromptOptions & { default: T[]; diff --git a/packages/tui/src/prompts/select/multiselect/run.ts b/pkgs-ts/console/src/prompts/select/multiselect/run.ts similarity index 69% rename from packages/tui/src/prompts/select/multiselect/run.ts rename to pkgs-ts/console/src/prompts/select/multiselect/run.ts index c8e6a01b..392b0e5e 100644 --- a/packages/tui/src/prompts/select/multiselect/run.ts +++ b/pkgs-ts/console/src/prompts/select/multiselect/run.ts @@ -1,11 +1,11 @@ -import { normalizeChoices } from '#tui/concerns/choices'; -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { preserveMultiSelectRetryDefault, transformedMultiSelectDefault } from '#tui/prompts/select/defaults'; -import { readMultipleChoices } from '#tui/prompts/select/read-multiple'; -import { renderSubmittedChoices } from '#tui/prompts/select/render'; -import type { NormalizedMultiSelectPromptOptions } from '#tui/prompts/select/multiselect/options'; +import { normalizeChoices } from '#console/concerns/choices'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { preserveMultiSelectRetryDefault, transformedMultiSelectDefault } from '#console/prompts/select/defaults'; +import { readMultipleChoices } from '#console/prompts/select/read-multiple'; +import { renderSubmittedChoices } from '#console/prompts/select/render'; +import type { NormalizedMultiSelectPromptOptions } from '#console/prompts/select/multiselect/options'; export const runMultiSelectPrompt = async (promptOptions: NormalizedMultiSelectPromptOptions): Promise => { const validationOptions: NormalizedMultiSelectPromptOptions = { diff --git a/packages/tui/src/prompts/select/navigation.ts b/pkgs-ts/console/src/prompts/select/navigation.ts similarity index 87% rename from packages/tui/src/prompts/select/navigation.ts rename to pkgs-ts/console/src/prompts/select/navigation.ts index f8cf57b3..f2f45847 100644 --- a/packages/tui/src/prompts/select/navigation.ts +++ b/pkgs-ts/console/src/prompts/select/navigation.ts @@ -1,7 +1,7 @@ -import { parseChoiceAnswerIndex } from '#tui/concerns/validators/choice-answer'; -import { Key } from '#tui/key'; -import { parseScrollSize } from '#tui/concerns/validators/scroll'; -import type { Choice } from '#tui/types'; +import { parseChoiceAnswerIndex } from '#console/concerns/validators/choice-answer'; +import { Key } from '#console/key'; +import { parseScrollSize } from '#console/concerns/validators/scroll'; +import type { Choice } from '#console/types'; export const parseChoiceIndex = (key: string): number | null => parseChoiceAnswerIndex(key); diff --git a/packages/tui/src/prompts/select/options.ts b/pkgs-ts/console/src/prompts/select/options.ts similarity index 79% rename from packages/tui/src/prompts/select/options.ts rename to pkgs-ts/console/src/prompts/select/options.ts index 083ddddb..76e6f8f0 100644 --- a/packages/tui/src/prompts/select/options.ts +++ b/pkgs-ts/console/src/prompts/select/options.ts @@ -1,7 +1,7 @@ -import { hasSelectDefaultArgument, isSelectPromptLabel, parseSelectChoiceOptions } from '#tui/prompts/select/validators/overload'; -import { hasPromptDefault } from '#tui/validators/default'; -import type { NormalizedSelectPromptOptions } from '#tui/prompts/select/defaults'; -import type { ChoiceOptions, SelectPromptOptions } from '#tui/types'; +import { hasSelectDefaultArgument, isSelectPromptLabel, parseSelectChoiceOptions } from '#console/prompts/select/validators/overload'; +import { hasPromptDefault } from '#console/validators/default'; +import type { NormalizedSelectPromptOptions } from '#console/prompts/select/defaults'; +import type { ChoiceOptions, SelectPromptOptions } from '#console/types'; export const selectHasDefault = (optionsOrLabel: SelectPromptOptions | string, argumentCount: number, defaultValue?: T): boolean => { return isSelectPromptLabel(optionsOrLabel) ? hasSelectDefaultArgument(argumentCount, defaultValue) : hasPromptDefault(optionsOrLabel); diff --git a/packages/tui/src/prompts/select/read-confirm.ts b/pkgs-ts/console/src/prompts/select/read-confirm.ts similarity index 61% rename from packages/tui/src/prompts/select/read-confirm.ts rename to pkgs-ts/console/src/prompts/select/read-confirm.ts index 06ae5201..86a7213f 100644 --- a/packages/tui/src/prompts/select/read-confirm.ts +++ b/pkgs-ts/console/src/prompts/select/read-confirm.ts @@ -1,13 +1,13 @@ -import { promptEnvironment } from '#tui/environment'; -import { Key } from '#tui/key'; -import { cancelPrompt } from '#tui/prompt'; -import { rejectPromptRevert } from '#tui/prompt/revert'; -import { confirmDirectValue, isConfirmToggleKey } from '#tui/prompts/select/read-confirm/keys'; -import { readLineConfirm } from '#tui/prompts/select/read-confirm/line-mode'; -import { createConfirmReaderSession } from '#tui/prompts/select/read-confirm/session'; -import type { ConfirmReadOptions, ConfirmReadResult } from '#tui/prompts/select/read-confirm/types'; - -export type { ConfirmReadOptions, ConfirmReadResult } from '#tui/prompts/select/read-confirm/types'; +import { promptEnvironment } from '#console/environment'; +import { Key } from '#console/key'; +import { cancelPrompt } from '#console/prompt'; +import { rejectPromptRevert } from '#console/prompt/revert'; +import { confirmDirectValue, isConfirmToggleKey } from '#console/prompts/select/read-confirm/keys'; +import { readLineConfirm } from '#console/prompts/select/read-confirm/line-mode'; +import { createConfirmReaderSession } from '#console/prompts/select/read-confirm/session'; +import type { ConfirmReadOptions, ConfirmReadResult } from '#console/prompts/select/read-confirm/types'; + +export type { ConfirmReadOptions, ConfirmReadResult } from '#console/prompts/select/read-confirm/types'; export const readConfirm = async (options: ConfirmReadOptions): Promise => { const environment = promptEnvironment(); diff --git a/packages/tui/src/prompts/select/read-confirm/keys.ts b/pkgs-ts/console/src/prompts/select/read-confirm/keys.ts similarity index 93% rename from packages/tui/src/prompts/select/read-confirm/keys.ts rename to pkgs-ts/console/src/prompts/select/read-confirm/keys.ts index c14bace7..dd8f391c 100644 --- a/packages/tui/src/prompts/select/read-confirm/keys.ts +++ b/pkgs-ts/console/src/prompts/select/read-confirm/keys.ts @@ -1,4 +1,4 @@ -import { Key } from '#tui/key'; +import { Key } from '#console/key'; const confirmToggleKeys = new Set([ Key.tab, diff --git a/packages/tui/src/prompts/select/read-confirm/line-mode.ts b/pkgs-ts/console/src/prompts/select/read-confirm/line-mode.ts similarity index 80% rename from packages/tui/src/prompts/select/read-confirm/line-mode.ts rename to pkgs-ts/console/src/prompts/select/read-confirm/line-mode.ts index 41f49b19..07825b60 100644 --- a/packages/tui/src/prompts/select/read-confirm/line-mode.ts +++ b/pkgs-ts/console/src/prompts/select/read-confirm/line-mode.ts @@ -1,5 +1,5 @@ -import { ask } from '#tui/prompt'; -import type { ConfirmReadOptions, ConfirmReadResult } from '#tui/prompts/select/read-confirm/types'; +import { ask } from '#console/prompt'; +import type { ConfirmReadOptions, ConfirmReadResult } from '#console/prompts/select/read-confirm/types'; const confirmQuestionSuffix = (options: ConfirmReadOptions): string => { return options.hasDefault === true && options.default === false ? ' [y/N]' : ' [Y/n]'; diff --git a/packages/tui/src/prompts/select/read-confirm/session.ts b/pkgs-ts/console/src/prompts/select/read-confirm/session.ts similarity index 77% rename from packages/tui/src/prompts/select/read-confirm/session.ts rename to pkgs-ts/console/src/prompts/select/read-confirm/session.ts index 91861643..75988015 100644 --- a/packages/tui/src/prompts/select/read-confirm/session.ts +++ b/pkgs-ts/console/src/prompts/select/read-confirm/session.ts @@ -1,6 +1,6 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderActiveConfirm, renderCancelledConfirm } from '#tui/prompts/select/render-confirm'; -import type { ConfirmReadOptions } from '#tui/prompts/select/read-confirm/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderActiveConfirm, renderCancelledConfirm } from '#console/prompts/select/render-confirm'; +import type { ConfirmReadOptions } from '#console/prompts/select/read-confirm/types'; export type ConfirmReaderSession = { cancel(): void; diff --git a/packages/tui/src/prompts/select/read-confirm/types.ts b/pkgs-ts/console/src/prompts/select/read-confirm/types.ts similarity index 76% rename from packages/tui/src/prompts/select/read-confirm/types.ts rename to pkgs-ts/console/src/prompts/select/read-confirm/types.ts index 55533143..d54b9a7f 100644 --- a/packages/tui/src/prompts/select/read-confirm/types.ts +++ b/pkgs-ts/console/src/prompts/select/read-confirm/types.ts @@ -1,4 +1,4 @@ -import type { ConfirmPromptOptions } from '#tui/types'; +import type { ConfirmPromptOptions } from '#console/types'; export type ConfirmReadOptions = ConfirmPromptOptions & { hasDefault?: boolean; diff --git a/packages/tui/src/prompts/select/read-multiple.ts b/pkgs-ts/console/src/prompts/select/read-multiple.ts similarity index 50% rename from packages/tui/src/prompts/select/read-multiple.ts rename to pkgs-ts/console/src/prompts/select/read-multiple.ts index c97789c0..7dd96e33 100644 --- a/packages/tui/src/prompts/select/read-multiple.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple.ts @@ -1,10 +1,10 @@ -import { promptEnvironment } from '#tui/environment'; -import { readMultipleChoicesInteractive } from '#tui/prompts/select/read-multiple/interactive'; -import { readLineMultipleChoices } from '#tui/prompts/select/read-multiple/line-mode'; -import type { MultipleChoicesReadResult } from '#tui/prompts/select/read-multiple/types'; -import type { Choice, MultiSelectPromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { readMultipleChoicesInteractive } from '#console/prompts/select/read-multiple/interactive'; +import { readLineMultipleChoices } from '#console/prompts/select/read-multiple/line-mode'; +import type { MultipleChoicesReadResult } from '#console/prompts/select/read-multiple/types'; +import type { Choice, MultiSelectPromptOptions } from '#console/types'; -export type { MultipleChoicesReadResult } from '#tui/prompts/select/read-multiple/types'; +export type { MultipleChoicesReadResult } from '#console/prompts/select/read-multiple/types'; export const readMultipleChoices = async ( message: string, diff --git a/pkgs-ts/console/src/prompts/select/read-multiple/cancel.ts b/pkgs-ts/console/src/prompts/select/read-multiple/cancel.ts new file mode 100644 index 00000000..dba5b3e9 --- /dev/null +++ b/pkgs-ts/console/src/prompts/select/read-multiple/cancel.ts @@ -0,0 +1,17 @@ +import { cancelPrompt } from '#console/prompt'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { markedChoiceValues } from '#console/prompts/select/multiple'; +import { cancelledMultipleChoicesResult } from '#console/prompts/select/read-multiple/result'; +import type { MultipleChoicesReaderSession } from '#console/prompts/select/read-multiple/session'; +import type { MultipleChoicesReadResult } from '#console/prompts/select/read-multiple/types'; +import { renderCancelledChoices } from '#console/prompts/select/render'; +import type { Choice } from '#console/types'; + +export const cancelMultipleChoices = async (message: string, choices: Array>, session: MultipleChoicesReaderSession, scroll?: number): Promise> => { + eraseRenderedFrame(session.frame()); + renderCancelledChoices(message, choices, session.selected(), session.marked(), scroll); + + const value = markedChoiceValues(choices, session.marked()); + + return cancelledMultipleChoicesResult(choices, session.marked(), await cancelPrompt(value)); +}; diff --git a/packages/tui/src/prompts/select/read-multiple/interactive.ts b/pkgs-ts/console/src/prompts/select/read-multiple/interactive.ts similarity index 62% rename from packages/tui/src/prompts/select/read-multiple/interactive.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/interactive.ts index 1a4852b9..f99e3cbd 100644 --- a/packages/tui/src/prompts/select/read-multiple/interactive.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple/interactive.ts @@ -1,10 +1,10 @@ -import { Key } from '#tui/key'; -import { cancelMultipleChoices } from '#tui/prompts/select/read-multiple/cancel'; -import { applyMultipleChoicesKey } from '#tui/prompts/select/read-multiple/keys'; -import { multipleChoicesResult } from '#tui/prompts/select/read-multiple/result'; -import { createMultipleChoicesReaderSession } from '#tui/prompts/select/read-multiple/session'; -import type { MultipleChoicesReadResult } from '#tui/prompts/select/read-multiple/types'; -import type { Choice, MultiSelectPromptOptions } from '#tui/types'; +import { Key } from '#console/key'; +import { cancelMultipleChoices } from '#console/prompts/select/read-multiple/cancel'; +import { applyMultipleChoicesKey } from '#console/prompts/select/read-multiple/keys'; +import { multipleChoicesResult } from '#console/prompts/select/read-multiple/result'; +import { createMultipleChoicesReaderSession } from '#console/prompts/select/read-multiple/session'; +import type { MultipleChoicesReadResult } from '#console/prompts/select/read-multiple/types'; +import type { Choice, MultiSelectPromptOptions } from '#console/types'; export const readMultipleChoicesInteractive = async ( readKey: () => Promise, diff --git a/packages/tui/src/prompts/select/read-multiple/keys.ts b/pkgs-ts/console/src/prompts/select/read-multiple/keys.ts similarity index 60% rename from packages/tui/src/prompts/select/read-multiple/keys.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/keys.ts index 6d34f8c4..dbcf4f23 100644 --- a/packages/tui/src/prompts/select/read-multiple/keys.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple/keys.ts @@ -1,11 +1,11 @@ -import { Key } from '#tui/key'; -import { selectNavigationAction } from '#tui/prompts/select/keys'; -import { choicesFromCommaSeparated } from '#tui/prompts/select/multiple'; -import { parseChoiceIndex } from '#tui/prompts/select/navigation'; -import { multipleChoicesValueResult } from '#tui/prompts/select/read-multiple/result'; -import type { MultipleChoicesReaderSession } from '#tui/prompts/select/read-multiple/session'; -import type { MultipleChoicesReadResult } from '#tui/prompts/select/read-multiple/types'; -import type { Choice } from '#tui/types'; +import { Key } from '#console/key'; +import { selectNavigationAction } from '#console/prompts/select/keys'; +import { choicesFromCommaSeparated } from '#console/prompts/select/multiple'; +import { parseChoiceIndex } from '#console/prompts/select/navigation'; +import { multipleChoicesValueResult } from '#console/prompts/select/read-multiple/result'; +import type { MultipleChoicesReaderSession } from '#console/prompts/select/read-multiple/session'; +import type { MultipleChoicesReadResult } from '#console/prompts/select/read-multiple/types'; +import type { Choice } from '#console/types'; export type MultipleChoicesKeyResult = | { diff --git a/packages/tui/src/prompts/select/read-multiple/line-mode.ts b/pkgs-ts/console/src/prompts/select/read-multiple/line-mode.ts similarity index 59% rename from packages/tui/src/prompts/select/read-multiple/line-mode.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/line-mode.ts index d53c9aa0..8d9b71ca 100644 --- a/packages/tui/src/prompts/select/read-multiple/line-mode.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple/line-mode.ts @@ -1,9 +1,9 @@ -import { ask } from '#tui/prompt'; -import { renderChoices } from '#tui/theme'; -import { choicesFromCommaSeparated, defaultChoiceValues } from '#tui/prompts/select/multiple'; -import { multipleChoicesValueResult } from '#tui/prompts/select/read-multiple/result'; -import type { MultipleChoicesReadResult } from '#tui/prompts/select/read-multiple/types'; -import type { Choice } from '#tui/types'; +import { ask } from '#console/prompt'; +import { renderChoices } from '#console/theme'; +import { choicesFromCommaSeparated, defaultChoiceValues } from '#console/prompts/select/multiple'; +import { multipleChoicesValueResult } from '#console/prompts/select/read-multiple/result'; +import type { MultipleChoicesReadResult } from '#console/prompts/select/read-multiple/types'; +import type { Choice } from '#console/types'; export const readLineMultipleChoices = async (message: string, choices: Array>, defaults: T[] = [], hint?: string): Promise> => { const rendered = renderChoices(choices); diff --git a/packages/tui/src/prompts/select/read-multiple/result.ts b/pkgs-ts/console/src/prompts/select/read-multiple/result.ts similarity index 82% rename from packages/tui/src/prompts/select/read-multiple/result.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/result.ts index d80a0fe0..e13e67d7 100644 --- a/packages/tui/src/prompts/select/read-multiple/result.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple/result.ts @@ -1,6 +1,6 @@ -import { markedChoiceValues } from '#tui/prompts/select/multiple'; -import type { MultipleChoicesReadResult } from '#tui/prompts/select/read-multiple/types'; -import type { Choice } from '#tui/types'; +import { markedChoiceValues } from '#console/prompts/select/multiple'; +import type { MultipleChoicesReadResult } from '#console/prompts/select/read-multiple/types'; +import type { Choice } from '#console/types'; export const markedChoiceLabels = (choices: Array>, marked: Set): string[] => { return [...marked] diff --git a/packages/tui/src/prompts/select/read-multiple/session.ts b/pkgs-ts/console/src/prompts/select/read-multiple/session.ts similarity index 76% rename from packages/tui/src/prompts/select/read-multiple/session.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/session.ts index d7c6b3f5..f51fac95 100644 --- a/packages/tui/src/prompts/select/read-multiple/session.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple/session.ts @@ -1,7 +1,7 @@ -import { createMultipleChoicesSessionFrame } from '#tui/prompts/select/read-multiple/session/frame'; -import { createMultipleChoicesSessionState } from '#tui/prompts/select/read-multiple/session/state'; -import type { SelectNavigationAction } from '#tui/prompts/select/keys'; -import type { Choice, MultiSelectPromptOptions } from '#tui/types'; +import { createMultipleChoicesSessionFrame } from '#console/prompts/select/read-multiple/session/frame'; +import { createMultipleChoicesSessionState } from '#console/prompts/select/read-multiple/session/state'; +import type { SelectNavigationAction } from '#console/prompts/select/keys'; +import type { Choice, MultiSelectPromptOptions } from '#console/types'; export type MultipleChoicesReaderSession = { frame(): string; diff --git a/packages/tui/src/prompts/select/read-multiple/session/frame.ts b/pkgs-ts/console/src/prompts/select/read-multiple/session/frame.ts similarity index 73% rename from packages/tui/src/prompts/select/read-multiple/session/frame.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/session/frame.ts index d9788092..c441cded 100644 --- a/packages/tui/src/prompts/select/read-multiple/session/frame.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple/session/frame.ts @@ -1,6 +1,6 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderMultipleChoices } from '#tui/prompts/select/render'; -import type { Choice, MultiSelectPromptOptions } from '#tui/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderMultipleChoices } from '#console/prompts/select/render'; +import type { Choice, MultiSelectPromptOptions } from '#console/types'; export type MultipleChoicesSessionFrame = { render(selected: number, marked: Set): void; diff --git a/packages/tui/src/prompts/select/read-multiple/session/state.ts b/pkgs-ts/console/src/prompts/select/read-multiple/session/state.ts similarity index 77% rename from packages/tui/src/prompts/select/read-multiple/session/state.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/session/state.ts index 5cd6dbfb..9e02480e 100644 --- a/packages/tui/src/prompts/select/read-multiple/session/state.ts +++ b/pkgs-ts/console/src/prompts/select/read-multiple/session/state.ts @@ -1,8 +1,8 @@ -import { firstEnabledIndex } from '#tui/concerns/choices'; -import { moveSelectHighlight } from '#tui/prompts/select/keys'; -import { markedChoiceIndexes, toggleAllEnabledChoices, toggleMarkedChoice } from '#tui/prompts/select/multiple'; -import type { SelectNavigationAction } from '#tui/prompts/select/keys'; -import type { Choice } from '#tui/types'; +import { firstEnabledIndex } from '#console/concerns/choices'; +import { moveSelectHighlight } from '#console/prompts/select/keys'; +import { markedChoiceIndexes, toggleAllEnabledChoices, toggleMarkedChoice } from '#console/prompts/select/multiple'; +import type { SelectNavigationAction } from '#console/prompts/select/keys'; +import type { Choice } from '#console/types'; export type MultipleChoicesSessionState = { marked(): Set; diff --git a/packages/tui/src/prompts/select/read-multiple/types.ts b/pkgs-ts/console/src/prompts/select/read-multiple/types.ts similarity index 100% rename from packages/tui/src/prompts/select/read-multiple/types.ts rename to pkgs-ts/console/src/prompts/select/read-multiple/types.ts diff --git a/packages/tui/src/prompts/select/read-selected.ts b/pkgs-ts/console/src/prompts/select/read-selected.ts similarity index 52% rename from packages/tui/src/prompts/select/read-selected.ts rename to pkgs-ts/console/src/prompts/select/read-selected.ts index 6de56ce6..441dfae4 100644 --- a/packages/tui/src/prompts/select/read-selected.ts +++ b/pkgs-ts/console/src/prompts/select/read-selected.ts @@ -1,10 +1,10 @@ -import { promptEnvironment } from '#tui/environment'; -import { readSelectedChoiceInteractive } from '#tui/prompts/select/read-selected/interactive'; -import { readSelectedChoiceLineMode } from '#tui/prompts/select/read-selected/line-mode'; -import type { SelectedChoiceReadResult } from '#tui/prompts/select/read-selected/types'; -import type { Choice, SelectPromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { readSelectedChoiceInteractive } from '#console/prompts/select/read-selected/interactive'; +import { readSelectedChoiceLineMode } from '#console/prompts/select/read-selected/line-mode'; +import type { SelectedChoiceReadResult } from '#console/prompts/select/read-selected/types'; +import type { Choice, SelectPromptOptions } from '#console/types'; -export type { SelectedChoiceReadResult } from '#tui/prompts/select/read-selected/types'; +export type { SelectedChoiceReadResult } from '#console/prompts/select/read-selected/types'; export const readSelectedChoice = async ( message: string, diff --git a/packages/tui/src/prompts/select/read-selected/interactive.ts b/pkgs-ts/console/src/prompts/select/read-selected/interactive.ts similarity index 68% rename from packages/tui/src/prompts/select/read-selected/interactive.ts rename to pkgs-ts/console/src/prompts/select/read-selected/interactive.ts index 794f8e7f..6b8b44fb 100644 --- a/packages/tui/src/prompts/select/read-selected/interactive.ts +++ b/pkgs-ts/console/src/prompts/select/read-selected/interactive.ts @@ -1,11 +1,11 @@ -import { Key } from '#tui/key'; -import { selectNavigationAction } from '#tui/prompts/select/keys'; -import { parseChoiceIndex } from '#tui/prompts/select/navigation'; -import { cancelSelectedChoice } from '#tui/prompts/select/read-selected/interactive/cancel'; -import { exhaustedSelectedChoice, indexedSelectedChoice, submittedSelectedChoice } from '#tui/prompts/select/read-selected/interactive/result'; -import { createSelectedChoiceReaderSession } from '#tui/prompts/select/read-selected/session'; -import type { SelectedChoiceReadResult } from '#tui/prompts/select/read-selected/types'; -import type { Choice, PromptInput, SelectPromptOptions } from '#tui/types'; +import { Key } from '#console/key'; +import { selectNavigationAction } from '#console/prompts/select/keys'; +import { parseChoiceIndex } from '#console/prompts/select/navigation'; +import { cancelSelectedChoice } from '#console/prompts/select/read-selected/interactive/cancel'; +import { exhaustedSelectedChoice, indexedSelectedChoice, submittedSelectedChoice } from '#console/prompts/select/read-selected/interactive/result'; +import { createSelectedChoiceReaderSession } from '#console/prompts/select/read-selected/session'; +import type { SelectedChoiceReadResult } from '#console/prompts/select/read-selected/types'; +import type { Choice, PromptInput, SelectPromptOptions } from '#console/types'; export const readSelectedChoiceInteractive = async ( readKey: NonNullable, diff --git a/pkgs-ts/console/src/prompts/select/read-selected/interactive/cancel.ts b/pkgs-ts/console/src/prompts/select/read-selected/interactive/cancel.ts new file mode 100644 index 00000000..a1f1d922 --- /dev/null +++ b/pkgs-ts/console/src/prompts/select/read-selected/interactive/cancel.ts @@ -0,0 +1,26 @@ +import { cancelPrompt } from '#console/prompt'; +import { parseChoiceValue } from '#console/concerns/validators/choice'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { cancelledSelectedChoiceResult } from '#console/prompts/select/read-selected/result'; +import { renderCancelledChoice } from '#console/prompts/select/render'; +import type { SelectedChoiceReaderSession } from '#console/prompts/select/read-selected/session'; +import type { SelectedChoiceReadResult } from '#console/prompts/select/read-selected/types'; +import type { Choice } from '#console/types'; + +export const cancelSelectedChoice = async ( + message: string, + choices: Array>, + session: SelectedChoiceReaderSession, + defaultValue?: T, + scroll?: number, +): Promise> => { + eraseRenderedFrame(session.frame()); + renderCancelledChoice(message, choices, session.selected(), scroll); + + const choice = choices[session.selected()]; + const fallback = choice?.value ?? defaultValue; + + const value = parseChoiceValue(await cancelPrompt(fallback)); + + return cancelledSelectedChoiceResult(choice, value); +}; diff --git a/packages/tui/src/prompts/select/read-selected/interactive/result.ts b/pkgs-ts/console/src/prompts/select/read-selected/interactive/result.ts similarity index 68% rename from packages/tui/src/prompts/select/read-selected/interactive/result.ts rename to pkgs-ts/console/src/prompts/select/read-selected/interactive/result.ts index 970ecef1..e2f2d522 100644 --- a/packages/tui/src/prompts/select/read-selected/interactive/result.ts +++ b/pkgs-ts/console/src/prompts/select/read-selected/interactive/result.ts @@ -1,7 +1,7 @@ -import { selectedChoiceAt, selectedChoiceResult } from '#tui/prompts/select/read-selected/result'; -import type { SelectedChoiceReaderSession } from '#tui/prompts/select/read-selected/session'; -import type { SelectedChoiceReadResult } from '#tui/prompts/select/read-selected/types'; -import type { Choice } from '#tui/types'; +import { selectedChoiceAt, selectedChoiceResult } from '#console/prompts/select/read-selected/result'; +import type { SelectedChoiceReaderSession } from '#console/prompts/select/read-selected/session'; +import type { SelectedChoiceReadResult } from '#console/prompts/select/read-selected/types'; +import type { Choice } from '#console/types'; export const exhaustedSelectedChoice = (choices: Array>, selected: number): SelectedChoiceReadResult => { const choice = selectedChoiceAt(choices, selected); diff --git a/packages/tui/src/prompts/select/read-selected/line-mode.ts b/pkgs-ts/console/src/prompts/select/read-selected/line-mode.ts similarity index 67% rename from packages/tui/src/prompts/select/read-selected/line-mode.ts rename to pkgs-ts/console/src/prompts/select/read-selected/line-mode.ts index 3f98fd77..eec9a9ba 100644 --- a/packages/tui/src/prompts/select/read-selected/line-mode.ts +++ b/pkgs-ts/console/src/prompts/select/read-selected/line-mode.ts @@ -1,9 +1,9 @@ -import { ask } from '#tui/prompt'; -import { renderChoices } from '#tui/theme'; -import { findChoice } from '#tui/concerns/choices'; -import { invalidSelectedChoice, selectedChoiceByDefault, selectedChoiceResult } from '#tui/prompts/select/read-selected/result'; -import type { SelectedChoiceReadResult } from '#tui/prompts/select/read-selected/types'; -import type { Choice } from '#tui/types'; +import { ask } from '#console/prompt'; +import { renderChoices } from '#console/theme'; +import { findChoice } from '#console/concerns/choices'; +import { invalidSelectedChoice, selectedChoiceByDefault, selectedChoiceResult } from '#console/prompts/select/read-selected/result'; +import type { SelectedChoiceReadResult } from '#console/prompts/select/read-selected/types'; +import type { Choice } from '#console/types'; export const readSelectedChoiceLineMode = async ( message: string, diff --git a/packages/tui/src/prompts/select/read-selected/result.ts b/pkgs-ts/console/src/prompts/select/read-selected/result.ts similarity index 86% rename from packages/tui/src/prompts/select/read-selected/result.ts rename to pkgs-ts/console/src/prompts/select/read-selected/result.ts index 4b86ef9a..03b7f65c 100644 --- a/packages/tui/src/prompts/select/read-selected/result.ts +++ b/pkgs-ts/console/src/prompts/select/read-selected/result.ts @@ -1,7 +1,7 @@ -import { PromptValidationError } from '#tui/prompt'; -import { choiceByValue, choiceValueEquals, firstEnabledIndex } from '#tui/concerns/choices'; -import type { SelectedChoiceReadResult } from '#tui/prompts/select/read-selected/types'; -import type { Choice } from '#tui/types'; +import { PromptValidationError } from '#console/prompt'; +import { choiceByValue, choiceValueEquals, firstEnabledIndex } from '#console/concerns/choices'; +import type { SelectedChoiceReadResult } from '#console/prompts/select/read-selected/types'; +import type { Choice } from '#console/types'; export const invalidSelectedChoice = (): PromptValidationError => new PromptValidationError('Please select a valid option.'); diff --git a/packages/tui/src/prompts/select/read-selected/session.ts b/pkgs-ts/console/src/prompts/select/read-selected/session.ts similarity index 67% rename from packages/tui/src/prompts/select/read-selected/session.ts rename to pkgs-ts/console/src/prompts/select/read-selected/session.ts index 648ba064..11da6a61 100644 --- a/packages/tui/src/prompts/select/read-selected/session.ts +++ b/pkgs-ts/console/src/prompts/select/read-selected/session.ts @@ -1,9 +1,9 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { moveSelectHighlight } from '#tui/prompts/select/keys'; -import { defaultChoiceIndex } from '#tui/prompts/select/read-selected/result'; -import { renderSelectedChoice } from '#tui/prompts/select/render'; -import type { SelectNavigationAction } from '#tui/prompts/select/keys'; -import type { Choice, SelectPromptOptions } from '#tui/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { moveSelectHighlight } from '#console/prompts/select/keys'; +import { defaultChoiceIndex } from '#console/prompts/select/read-selected/result'; +import { renderSelectedChoice } from '#console/prompts/select/render'; +import type { SelectNavigationAction } from '#console/prompts/select/keys'; +import type { Choice, SelectPromptOptions } from '#console/types'; export type SelectedChoiceReaderSession = { frame(): string; diff --git a/packages/tui/src/prompts/select/read-selected/types.ts b/pkgs-ts/console/src/prompts/select/read-selected/types.ts similarity index 100% rename from packages/tui/src/prompts/select/read-selected/types.ts rename to pkgs-ts/console/src/prompts/select/read-selected/types.ts diff --git a/packages/tui/src/prompts/select/render-confirm.ts b/pkgs-ts/console/src/prompts/select/render-confirm.ts similarity index 87% rename from packages/tui/src/prompts/select/render-confirm.ts rename to pkgs-ts/console/src/prompts/select/render-confirm.ts index f4e46a26..fb976a4d 100644 --- a/packages/tui/src/prompts/select/render-confirm.ts +++ b/pkgs-ts/console/src/prompts/select/render-confirm.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, green, red } from '#tui/theme/styles'; -import type { ConfirmPromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, green, red } from '#console/theme/styles'; +import type { ConfirmPromptOptions } from '#console/types'; const confirmLabel = (options: ConfirmPromptOptions, confirmed: boolean): string => { return confirmed ? (options.yes ?? 'Yes') : (options.no ?? 'No'); diff --git a/packages/tui/src/prompts/select/render-rows.ts b/pkgs-ts/console/src/prompts/select/render-rows.ts similarity index 87% rename from packages/tui/src/prompts/select/render-rows.ts rename to pkgs-ts/console/src/prompts/select/render-rows.ts index fc619816..abdd5006 100644 --- a/packages/tui/src/prompts/select/render-rows.ts +++ b/pkgs-ts/console/src/prompts/select/render-rows.ts @@ -1,7 +1,7 @@ -import { choiceLabel } from '#tui/concerns/choice-label'; -import { renderChoiceWindowRows } from '#tui/prompts/select/render-rows/window'; -import { cyan, dim, strikethrough } from '#tui/theme/styles'; -import type { Choice } from '#tui/types'; +import { choiceLabel } from '#console/concerns/choice-label'; +import { renderChoiceWindowRows } from '#console/prompts/select/render-rows/window'; +import { cyan, dim, strikethrough } from '#console/theme/styles'; +import type { Choice } from '#console/types'; export const renderActiveChoiceRows = (choices: Array>, selected: number, scroll?: number): string => { return renderChoiceWindowRows(choices, selected, scroll, (choice, index) => { diff --git a/packages/tui/src/prompts/select/render-rows/window.ts b/pkgs-ts/console/src/prompts/select/render-rows/window.ts similarity index 73% rename from packages/tui/src/prompts/select/render-rows/window.ts rename to pkgs-ts/console/src/prompts/select/render-rows/window.ts index 13214a2f..269e2dd5 100644 --- a/packages/tui/src/prompts/select/render-rows/window.ts +++ b/pkgs-ts/console/src/prompts/select/render-rows/window.ts @@ -1,6 +1,6 @@ -import { choiceWindow } from '#tui/concerns/choices'; -import { renderScrollbarRows } from '#tui/concerns/scrollbar'; -import type { Choice } from '#tui/types'; +import { choiceWindow } from '#console/concerns/choices'; +import { renderScrollbarRows } from '#console/concerns/scrollbar'; +import type { Choice } from '#console/types'; export const renderChoiceWindowRows = (choices: Array>, selected: number, scroll: number | undefined, renderRow: (choice: Choice, index: number) => string): string => { const window = choiceWindow(choices.length, selected, scroll); diff --git a/packages/tui/src/prompts/select/render.ts b/pkgs-ts/console/src/prompts/select/render.ts similarity index 86% rename from packages/tui/src/prompts/select/render.ts rename to pkgs-ts/console/src/prompts/select/render.ts index a002fc66..58d6673d 100644 --- a/packages/tui/src/prompts/select/render.ts +++ b/pkgs-ts/console/src/prompts/select/render.ts @@ -1,9 +1,9 @@ -import { promptEnvironment } from '#tui/environment'; -import { joinedInfoDetails, resolveInfo } from '#tui/concerns/info'; -import { renderActiveChecklistRows, renderActiveChoiceRows, renderCancelledChecklistRows, renderCancelledChoiceRows } from '#tui/prompts/select/render-rows'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red } from '#tui/theme/styles'; -import type { Choice, MultiSelectPromptOptions, SelectPromptOptions } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { joinedInfoDetails, resolveInfo } from '#console/concerns/info'; +import { renderActiveChecklistRows, renderActiveChoiceRows, renderCancelledChecklistRows, renderCancelledChoiceRows } from '#console/prompts/select/render-rows'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red } from '#console/theme/styles'; +import type { Choice, MultiSelectPromptOptions, SelectPromptOptions } from '#console/types'; export const renderSelectedChoice = (message: string, choices: Array>, selected: number, scroll: number | undefined, info: SelectPromptOptions['info']): string => { const text = resolveInfo(info, choices[selected]?.value ?? null); diff --git a/packages/tui/src/prompts/select/run.ts b/pkgs-ts/console/src/prompts/select/run.ts similarity index 67% rename from packages/tui/src/prompts/select/run.ts rename to pkgs-ts/console/src/prompts/select/run.ts index d4e81847..883240f9 100644 --- a/packages/tui/src/prompts/select/run.ts +++ b/pkgs-ts/console/src/prompts/select/run.ts @@ -1,13 +1,13 @@ -import { normalizeChoices } from '#tui/concerns/choices'; -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { preserveSelectRetryDefault, transformSelectValue, transformedSelectDefault } from '#tui/prompts/select/defaults'; -import { readSelectedChoice } from '#tui/prompts/select/read-selected'; -import { renderSubmittedChoice } from '#tui/prompts/select/render'; -import { assertSelectOptions } from '#tui/prompts/select/validators/options'; -import type { NormalizedSelectPromptOptions } from '#tui/prompts/select/defaults'; -import type { SelectPromptOptions } from '#tui/types'; +import { normalizeChoices } from '#console/concerns/choices'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { preserveSelectRetryDefault, transformSelectValue, transformedSelectDefault } from '#console/prompts/select/defaults'; +import { readSelectedChoice } from '#console/prompts/select/read-selected'; +import { renderSubmittedChoice } from '#console/prompts/select/render'; +import { assertSelectOptions } from '#console/prompts/select/validators/options'; +import type { NormalizedSelectPromptOptions } from '#console/prompts/select/defaults'; +import type { SelectPromptOptions } from '#console/types'; export const runSelectPrompt = async (options: NormalizedSelectPromptOptions): Promise => { assertSelectOptions(options); diff --git a/packages/tui/src/prompts/select/select.ts b/pkgs-ts/console/src/prompts/select/select.ts similarity index 86% rename from packages/tui/src/prompts/select/select.ts rename to pkgs-ts/console/src/prompts/select/select.ts index 8c1ea79d..8dc15da0 100644 --- a/packages/tui/src/prompts/select/select.ts +++ b/pkgs-ts/console/src/prompts/select/select.ts @@ -1,6 +1,6 @@ -import { normalizeSelectPromptOptions, selectHasDefault } from '#tui/prompts/select/options'; -import { runSelectPrompt } from '#tui/prompts/select/run'; -import type { ChoiceOptions, SelectPromptOptions } from '#tui/types'; +import { normalizeSelectPromptOptions, selectHasDefault } from '#console/prompts/select/options'; +import { runSelectPrompt } from '#console/prompts/select/run'; +import type { ChoiceOptions, SelectPromptOptions } from '#console/types'; export function select(options: SelectPromptOptions): Promise; diff --git a/packages/tui/src/prompts/select/validators/defaults.ts b/pkgs-ts/console/src/prompts/select/validators/defaults.ts similarity index 100% rename from packages/tui/src/prompts/select/validators/defaults.ts rename to pkgs-ts/console/src/prompts/select/validators/defaults.ts diff --git a/packages/tui/src/prompts/select/validators/options.ts b/pkgs-ts/console/src/prompts/select/validators/options.ts similarity index 83% rename from packages/tui/src/prompts/select/validators/options.ts rename to pkgs-ts/console/src/prompts/select/validators/options.ts index c109c45b..a01316be 100644 --- a/packages/tui/src/prompts/select/validators/options.ts +++ b/pkgs-ts/console/src/prompts/select/validators/options.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { SelectPromptOptions } from '#tui/types'; +import type { SelectPromptOptions } from '#console/types'; const disallowedRequiredSchema = z.literal(false); diff --git a/packages/tui/src/prompts/select/validators/overload.ts b/pkgs-ts/console/src/prompts/select/validators/overload.ts similarity index 89% rename from packages/tui/src/prompts/select/validators/overload.ts rename to pkgs-ts/console/src/prompts/select/validators/overload.ts index 470f42d2..916bf94e 100644 --- a/packages/tui/src/prompts/select/validators/overload.ts +++ b/pkgs-ts/console/src/prompts/select/validators/overload.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { choiceOptionsSchema } from '#tui/concerns/validators/choice'; -import type { ChoiceOptions } from '#tui/types'; +import { choiceOptionsSchema } from '#console/concerns/validators/choice'; +import type { ChoiceOptions } from '#console/types'; const selectPromptLabelSchema = z.string(); const confirmDefaultSchema = z.boolean(); diff --git a/packages/tui/src/prompts/suggest/autocomplete-prompt.ts b/pkgs-ts/console/src/prompts/suggest/autocomplete-prompt.ts similarity index 67% rename from packages/tui/src/prompts/suggest/autocomplete-prompt.ts rename to pkgs-ts/console/src/prompts/suggest/autocomplete-prompt.ts index 6ad1202f..3fea335d 100644 --- a/packages/tui/src/prompts/suggest/autocomplete-prompt.ts +++ b/pkgs-ts/console/src/prompts/suggest/autocomplete-prompt.ts @@ -1,10 +1,10 @@ -import { runTextSuggestionPrompt } from '#tui/prompts/suggest/lifecycle'; -import { readAutocompleteValue } from '#tui/prompts/suggest/read-autocomplete'; -import { renderSubmittedAutocomplete } from '#tui/prompts/suggest/render-autocomplete'; -import { suggestOptions } from '#tui/prompts/suggest/options'; -import { isSuggestPromptLabel } from '#tui/prompts/suggest/validators/overload'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { MaybePromise, TextPromptOptions } from '#tui/types'; +import { runTextSuggestionPrompt } from '#console/prompts/suggest/lifecycle'; +import { readAutocompleteValue } from '#console/prompts/suggest/read-autocomplete'; +import { renderSubmittedAutocomplete } from '#console/prompts/suggest/render-autocomplete'; +import { suggestOptions } from '#console/prompts/suggest/options'; +import { isSuggestPromptLabel } from '#console/prompts/suggest/validators/overload'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { MaybePromise, TextPromptOptions } from '#console/types'; export function autocomplete(options: SuggestOptions): Promise; diff --git a/packages/tui/src/prompts/suggest/autocomplete.ts b/pkgs-ts/console/src/prompts/suggest/autocomplete.ts similarity index 77% rename from packages/tui/src/prompts/suggest/autocomplete.ts rename to pkgs-ts/console/src/prompts/suggest/autocomplete.ts index c0c5976e..0ebc9196 100644 --- a/packages/tui/src/prompts/suggest/autocomplete.ts +++ b/pkgs-ts/console/src/prompts/suggest/autocomplete.ts @@ -1,7 +1,7 @@ -import { Key } from '#tui/key'; -import { characterLength } from '#tui/typed-value/characters'; -import { nextAutocompleteHighlight } from '#tui/prompts/suggest/navigation'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { Key } from '#console/key'; +import { characterLength } from '#console/typed-value/characters'; +import { nextAutocompleteHighlight } from '#console/prompts/suggest/navigation'; +import type { TypedValueState } from '#console/typed-value/types'; export const autocompleteNavigationDirection = (key: string): 1 | -1 | null => { if (key === Key.up || key === Key.upArrow) { diff --git a/packages/tui/src/prompts/suggest/ghost-text.ts b/pkgs-ts/console/src/prompts/suggest/ghost-text.ts similarity index 79% rename from packages/tui/src/prompts/suggest/ghost-text.ts rename to pkgs-ts/console/src/prompts/suggest/ghost-text.ts index 5b77a6e1..5a405fb7 100644 --- a/packages/tui/src/prompts/suggest/ghost-text.ts +++ b/pkgs-ts/console/src/prompts/suggest/ghost-text.ts @@ -1,7 +1,7 @@ -import { dim, inverse } from '#tui/theme/styles'; -import { characterLength, characters, fromCharacters } from '#tui/typed-value/characters'; -import { valueWithCursor } from '#tui/typed-value/cursor'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { dim, inverse } from '#console/theme/styles'; +import { characterLength, characters, fromCharacters } from '#console/typed-value/characters'; +import { valueWithCursor } from '#console/typed-value/cursor'; +import type { TypedValueState } from '#console/typed-value/types'; const startsWithInput = (match: string, value: string): boolean => { const normalizedValue = value.toLowerCase(); diff --git a/pkgs-ts/console/src/prompts/suggest/index.ts b/pkgs-ts/console/src/prompts/suggest/index.ts new file mode 100644 index 00000000..83770a6c --- /dev/null +++ b/pkgs-ts/console/src/prompts/suggest/index.ts @@ -0,0 +1,3 @@ +export { autocomplete } from '#console/prompts/suggest/autocomplete-prompt'; +export { suggest } from '#console/prompts/suggest/suggest'; +export type { SuggestOptions } from '#console/prompts/suggest/options'; diff --git a/packages/tui/src/prompts/suggest/keys.ts b/pkgs-ts/console/src/prompts/suggest/keys.ts similarity index 92% rename from packages/tui/src/prompts/suggest/keys.ts rename to pkgs-ts/console/src/prompts/suggest/keys.ts index e9b644fb..11222e46 100644 --- a/packages/tui/src/prompts/suggest/keys.ts +++ b/pkgs-ts/console/src/prompts/suggest/keys.ts @@ -1,5 +1,5 @@ -import { Key, oneOf } from '#tui/key'; -import { firstSuggestionHighlight, lastSuggestionHighlight, nextSuggestionHighlight, pageSuggestionHighlight } from '#tui/prompts/suggest/navigation'; +import { Key, oneOf } from '#console/key'; +import { firstSuggestionHighlight, lastSuggestionHighlight, nextSuggestionHighlight, pageSuggestionHighlight } from '#console/prompts/suggest/navigation'; export type SuggestNavigationAction = 'first' | 'last' | 'next' | 'page-next' | 'page-previous' | 'previous'; diff --git a/packages/tui/src/prompts/suggest/lifecycle.ts b/pkgs-ts/console/src/prompts/suggest/lifecycle.ts similarity index 75% rename from packages/tui/src/prompts/suggest/lifecycle.ts rename to pkgs-ts/console/src/prompts/suggest/lifecycle.ts index e389e847..d2769082 100644 --- a/packages/tui/src/prompts/suggest/lifecycle.ts +++ b/pkgs-ts/console/src/prompts/suggest/lifecycle.ts @@ -1,9 +1,9 @@ -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { transformedTextDefault } from '#tui/prompts/text-default'; -import type { TextSuggestionReadResult } from '#tui/prompts/suggest/read-result'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { transformedTextDefault } from '#console/prompts/text-default'; +import type { TextSuggestionReadResult } from '#console/prompts/suggest/read-result'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; export type TextSuggestionPromptName = 'autocomplete' | 'suggest'; diff --git a/packages/tui/src/prompts/suggest/navigation.ts b/pkgs-ts/console/src/prompts/suggest/navigation.ts similarity index 94% rename from packages/tui/src/prompts/suggest/navigation.ts rename to pkgs-ts/console/src/prompts/suggest/navigation.ts index 0394f6a4..67c35c1d 100644 --- a/packages/tui/src/prompts/suggest/navigation.ts +++ b/pkgs-ts/console/src/prompts/suggest/navigation.ts @@ -1,4 +1,4 @@ -import { pageIndex } from '#tui/prompts/select/navigation'; +import { pageIndex } from '#console/prompts/select/navigation'; export const nextSuggestionHighlight = (matches: string[], highlighted: number | null, direction: 1 | -1): number | null => { if (matches.length === 0) { diff --git a/packages/tui/src/prompts/suggest/options.ts b/pkgs-ts/console/src/prompts/suggest/options.ts similarity index 84% rename from packages/tui/src/prompts/suggest/options.ts rename to pkgs-ts/console/src/prompts/suggest/options.ts index 0b58028b..cc123899 100644 --- a/packages/tui/src/prompts/suggest/options.ts +++ b/pkgs-ts/console/src/prompts/suggest/options.ts @@ -1,5 +1,5 @@ -import { isSuggestPromptLabel } from '#tui/prompts/suggest/validators/overload'; -import type { MaybePromise, TextPromptOptions } from '#tui/types'; +import { isSuggestPromptLabel } from '#console/prompts/suggest/validators/overload'; +import type { MaybePromise, TextPromptOptions } from '#console/types'; export type SuggestOptions = TextPromptOptions & { options: string[] | ((query: string) => MaybePromise); diff --git a/packages/tui/src/prompts/suggest/read-autocomplete.ts b/pkgs-ts/console/src/prompts/suggest/read-autocomplete.ts similarity index 64% rename from packages/tui/src/prompts/suggest/read-autocomplete.ts rename to pkgs-ts/console/src/prompts/suggest/read-autocomplete.ts index e1d8b282..c7012b3b 100644 --- a/packages/tui/src/prompts/suggest/read-autocomplete.ts +++ b/pkgs-ts/console/src/prompts/suggest/read-autocomplete.ts @@ -1,13 +1,13 @@ -import { promptEnvironment } from '#tui/environment'; -import { Key } from '#tui/key'; -import { ask } from '#tui/prompt'; -import { autocompleteNavigationDirection, canAcceptAutocomplete } from '#tui/prompts/suggest/autocomplete'; -import { cancelAutocompleteValue } from '#tui/prompts/suggest/read-autocomplete/cancel'; -import { suggestionReadResult } from '#tui/prompts/suggest/read-result'; -import { createAutocompleteReaderSession } from '#tui/prompts/suggest/read-autocomplete/session'; -import { currentAutocompleteValue } from '#tui/prompts/suggest/read-autocomplete/submission'; -import type { TextSuggestionReadResult } from '#tui/prompts/suggest/read-result'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; +import { promptEnvironment } from '#console/environment'; +import { Key } from '#console/key'; +import { ask } from '#console/prompt'; +import { autocompleteNavigationDirection, canAcceptAutocomplete } from '#console/prompts/suggest/autocomplete'; +import { cancelAutocompleteValue } from '#console/prompts/suggest/read-autocomplete/cancel'; +import { suggestionReadResult } from '#console/prompts/suggest/read-result'; +import { createAutocompleteReaderSession } from '#console/prompts/suggest/read-autocomplete/session'; +import { currentAutocompleteValue } from '#console/prompts/suggest/read-autocomplete/submission'; +import type { TextSuggestionReadResult } from '#console/prompts/suggest/read-result'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; export type AutocompleteReadResult = TextSuggestionReadResult; diff --git a/pkgs-ts/console/src/prompts/suggest/read-autocomplete/cancel.ts b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/cancel.ts new file mode 100644 index 00000000..5412cf4a --- /dev/null +++ b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/cancel.ts @@ -0,0 +1,16 @@ +import { cancelPrompt } from '#console/prompt'; +import { renderCancelledAutocomplete } from '#console/prompts/suggest/render-autocomplete'; +import { suggestionReadResult } from '#console/prompts/suggest/read-result'; +import { eraseRenderedFrame } from '#console/status/frame'; +import type { AutocompleteReaderSession } from '#console/prompts/suggest/read-autocomplete/session'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TextSuggestionReadResult } from '#console/prompts/suggest/read-result'; + +export const cancelAutocompleteValue = async (options: SuggestOptions, session: AutocompleteReaderSession): Promise => { + const value = session.state().value; + + eraseRenderedFrame(session.frame()); + renderCancelledAutocomplete(options.message, value, options.placeholder); + + return suggestionReadResult(await cancelPrompt(value), true, true); +}; diff --git a/packages/tui/src/prompts/suggest/read-autocomplete/frame.ts b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/frame.ts similarity index 69% rename from packages/tui/src/prompts/suggest/read-autocomplete/frame.ts rename to pkgs-ts/console/src/prompts/suggest/read-autocomplete/frame.ts index a8848a2c..1f764cce 100644 --- a/packages/tui/src/prompts/suggest/read-autocomplete/frame.ts +++ b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/frame.ts @@ -1,7 +1,7 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderAutocomplete } from '#tui/prompts/suggest/render-autocomplete'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderAutocomplete } from '#console/prompts/suggest/render-autocomplete'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TypedValueState } from '#console/typed-value/types'; type AutocompleteFrameRenderOptions = { highlighted: number; diff --git a/packages/tui/src/prompts/suggest/read-autocomplete/session.ts b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/session.ts similarity index 77% rename from packages/tui/src/prompts/suggest/read-autocomplete/session.ts rename to pkgs-ts/console/src/prompts/suggest/read-autocomplete/session.ts index 9a9529b6..4e2302a0 100644 --- a/packages/tui/src/prompts/suggest/read-autocomplete/session.ts +++ b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/session.ts @@ -1,7 +1,7 @@ -import { createAutocompleteFrameRenderer } from '#tui/prompts/suggest/read-autocomplete/frame'; -import { createAutocompleteReaderState } from '#tui/prompts/suggest/read-autocomplete/state'; -import type { TypedValueState } from '#tui/typed-value/types'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; +import { createAutocompleteFrameRenderer } from '#console/prompts/suggest/read-autocomplete/frame'; +import { createAutocompleteReaderState } from '#console/prompts/suggest/read-autocomplete/state'; +import type { TypedValueState } from '#console/typed-value/types'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; export type AutocompleteReaderSession = { acceptHighlighted(requireGrowth: boolean): Promise; diff --git a/packages/tui/src/prompts/suggest/read-autocomplete/state.ts b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/state.ts similarity index 77% rename from packages/tui/src/prompts/suggest/read-autocomplete/state.ts rename to pkgs-ts/console/src/prompts/suggest/read-autocomplete/state.ts index e00748c4..c08cdbf1 100644 --- a/packages/tui/src/prompts/suggest/read-autocomplete/state.ts +++ b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/state.ts @@ -1,8 +1,8 @@ -import { acceptAutocompleteMatch } from '#tui/prompts/suggest/autocomplete'; -import { createAutocompleteHighlightState } from '#tui/prompts/suggest/read-autocomplete/state/highlight'; -import { createSuggestQueryState } from '#tui/prompts/suggest/state/query'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { acceptAutocompleteMatch } from '#console/prompts/suggest/autocomplete'; +import { createAutocompleteHighlightState } from '#console/prompts/suggest/read-autocomplete/state/highlight'; +import { createSuggestQueryState } from '#console/prompts/suggest/state/query'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TypedValueState } from '#console/typed-value/types'; export type AutocompleteReaderState = { acceptHighlighted(requireGrowth: boolean): Promise; diff --git a/packages/tui/src/prompts/suggest/read-autocomplete/state/highlight.ts b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/state/highlight.ts similarity index 84% rename from packages/tui/src/prompts/suggest/read-autocomplete/state/highlight.ts rename to pkgs-ts/console/src/prompts/suggest/read-autocomplete/state/highlight.ts index eb3ca479..01778ae1 100644 --- a/packages/tui/src/prompts/suggest/read-autocomplete/state/highlight.ts +++ b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/state/highlight.ts @@ -1,4 +1,4 @@ -import { moveAutocompleteHighlight } from '#tui/prompts/suggest/autocomplete'; +import { moveAutocompleteHighlight } from '#console/prompts/suggest/autocomplete'; export type AutocompleteHighlightState = { move(matches: string[], direction: 1 | -1): void; diff --git a/pkgs-ts/console/src/prompts/suggest/read-autocomplete/submission.ts b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/submission.ts new file mode 100644 index 00000000..e5b8f216 --- /dev/null +++ b/pkgs-ts/console/src/prompts/suggest/read-autocomplete/submission.ts @@ -0,0 +1,7 @@ +import { suggestionReadResult } from '#console/prompts/suggest/read-result'; +import type { AutocompleteReaderSession } from '#console/prompts/suggest/read-autocomplete/session'; +import type { TextSuggestionReadResult } from '#console/prompts/suggest/read-result'; + +export const currentAutocompleteValue = (session: AutocompleteReaderSession): TextSuggestionReadResult => { + return suggestionReadResult(session.state().value, true, false, session.frame()); +}; diff --git a/packages/tui/src/prompts/suggest/read-result.ts b/pkgs-ts/console/src/prompts/suggest/read-result.ts similarity index 76% rename from packages/tui/src/prompts/suggest/read-result.ts rename to pkgs-ts/console/src/prompts/suggest/read-result.ts index 9472c8e3..18623aa2 100644 --- a/packages/tui/src/prompts/suggest/read-result.ts +++ b/pkgs-ts/console/src/prompts/suggest/read-result.ts @@ -1,5 +1,5 @@ -import { characterLength } from '#tui/typed-value/characters'; -import type { TypedValueState } from '#tui/typed-value'; +import { characterLength } from '#console/typed-value/characters'; +import type { TypedValueState } from '#console/typed-value'; export type TextSuggestionReadResult = { cancelled: boolean; diff --git a/packages/tui/src/prompts/suggest/read.ts b/pkgs-ts/console/src/prompts/suggest/read.ts similarity index 68% rename from packages/tui/src/prompts/suggest/read.ts rename to pkgs-ts/console/src/prompts/suggest/read.ts index b02ba5b6..19b665df 100644 --- a/packages/tui/src/prompts/suggest/read.ts +++ b/pkgs-ts/console/src/prompts/suggest/read.ts @@ -1,13 +1,13 @@ -import { promptEnvironment } from '#tui/environment'; -import { Key } from '#tui/key'; -import { ask } from '#tui/prompt'; -import { clearsSuggestionHighlight, suggestNavigationAction } from '#tui/prompts/suggest/keys'; -import { cancelSuggestionValue } from '#tui/prompts/suggest/read/cancel'; -import { currentSuggestionValue, highlightedSuggestionValue } from '#tui/prompts/suggest/read/submission'; -import { suggestionReadResult } from '#tui/prompts/suggest/read-result'; -import { createSuggestReaderSession } from '#tui/prompts/suggest/read/session'; -import type { TextSuggestionReadResult } from '#tui/prompts/suggest/read-result'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; +import { promptEnvironment } from '#console/environment'; +import { Key } from '#console/key'; +import { ask } from '#console/prompt'; +import { clearsSuggestionHighlight, suggestNavigationAction } from '#console/prompts/suggest/keys'; +import { cancelSuggestionValue } from '#console/prompts/suggest/read/cancel'; +import { currentSuggestionValue, highlightedSuggestionValue } from '#console/prompts/suggest/read/submission'; +import { suggestionReadResult } from '#console/prompts/suggest/read-result'; +import { createSuggestReaderSession } from '#console/prompts/suggest/read/session'; +import type { TextSuggestionReadResult } from '#console/prompts/suggest/read-result'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; export type SuggestReadResult = TextSuggestionReadResult; diff --git a/pkgs-ts/console/src/prompts/suggest/read/cancel.ts b/pkgs-ts/console/src/prompts/suggest/read/cancel.ts new file mode 100644 index 00000000..b3639c4d --- /dev/null +++ b/pkgs-ts/console/src/prompts/suggest/read/cancel.ts @@ -0,0 +1,16 @@ +import { cancelPrompt } from '#console/prompt'; +import { renderCancelledSuggestion } from '#console/prompts/suggest/render'; +import { suggestionReadResult } from '#console/prompts/suggest/read-result'; +import { eraseRenderedFrame } from '#console/status/frame'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TextSuggestionReadResult } from '#console/prompts/suggest/read-result'; +import type { SuggestReaderSession } from '#console/prompts/suggest/read/session'; + +export const cancelSuggestionValue = async (options: SuggestOptions, session: SuggestReaderSession): Promise => { + const value = session.state().value; + + eraseRenderedFrame(session.frame()); + renderCancelledSuggestion(options.message, value, options.placeholder); + + return suggestionReadResult(await cancelPrompt(value), true, true); +}; diff --git a/packages/tui/src/prompts/suggest/read/frame.ts b/pkgs-ts/console/src/prompts/suggest/read/frame.ts similarity index 70% rename from packages/tui/src/prompts/suggest/read/frame.ts rename to pkgs-ts/console/src/prompts/suggest/read/frame.ts index f77f3aa6..7b052265 100644 --- a/packages/tui/src/prompts/suggest/read/frame.ts +++ b/pkgs-ts/console/src/prompts/suggest/read/frame.ts @@ -1,7 +1,7 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderSuggestions } from '#tui/prompts/suggest/render'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderSuggestions } from '#console/prompts/suggest/render'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TypedValueState } from '#console/typed-value/types'; type SuggestFrameRenderOptions = { highlighted: number | null; diff --git a/packages/tui/src/prompts/suggest/read/session.ts b/pkgs-ts/console/src/prompts/suggest/read/session.ts similarity index 76% rename from packages/tui/src/prompts/suggest/read/session.ts rename to pkgs-ts/console/src/prompts/suggest/read/session.ts index 40282405..c9b7621a 100644 --- a/packages/tui/src/prompts/suggest/read/session.ts +++ b/pkgs-ts/console/src/prompts/suggest/read/session.ts @@ -1,8 +1,8 @@ -import { createSuggestFrameRenderer } from '#tui/prompts/suggest/read/frame'; -import { createSuggestReaderState } from '#tui/prompts/suggest/read/state'; -import type { SuggestNavigationAction } from '#tui/prompts/suggest/keys'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { createSuggestFrameRenderer } from '#console/prompts/suggest/read/frame'; +import { createSuggestReaderState } from '#console/prompts/suggest/read/state'; +import type { SuggestNavigationAction } from '#console/prompts/suggest/keys'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TypedValueState } from '#console/typed-value/types'; export type SuggestReaderSession = { applyTypedInput(key: string): Promise<{ cancelled: boolean; submitted: boolean }>; diff --git a/packages/tui/src/prompts/suggest/read/state.ts b/pkgs-ts/console/src/prompts/suggest/read/state.ts similarity index 74% rename from packages/tui/src/prompts/suggest/read/state.ts rename to pkgs-ts/console/src/prompts/suggest/read/state.ts index 7fa27137..789319e1 100644 --- a/packages/tui/src/prompts/suggest/read/state.ts +++ b/pkgs-ts/console/src/prompts/suggest/read/state.ts @@ -1,8 +1,8 @@ -import { createSuggestHighlightState } from '#tui/prompts/suggest/read/state/highlight'; -import { createSuggestQueryState } from '#tui/prompts/suggest/state/query'; -import type { SuggestNavigationAction } from '#tui/prompts/suggest/keys'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { createSuggestHighlightState } from '#console/prompts/suggest/read/state/highlight'; +import { createSuggestQueryState } from '#console/prompts/suggest/state/query'; +import type { SuggestNavigationAction } from '#console/prompts/suggest/keys'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TypedValueState } from '#console/typed-value/types'; export type SuggestReaderState = { applyTypedInput(key: string): Promise<{ cancelled: boolean; submitted: boolean }>; diff --git a/packages/tui/src/prompts/suggest/read/state/highlight.ts b/pkgs-ts/console/src/prompts/suggest/read/state/highlight.ts similarity index 76% rename from packages/tui/src/prompts/suggest/read/state/highlight.ts rename to pkgs-ts/console/src/prompts/suggest/read/state/highlight.ts index ddf43524..61d8a349 100644 --- a/packages/tui/src/prompts/suggest/read/state/highlight.ts +++ b/pkgs-ts/console/src/prompts/suggest/read/state/highlight.ts @@ -1,5 +1,5 @@ -import { moveSuggestionHighlight } from '#tui/prompts/suggest/keys'; -import type { SuggestNavigationAction } from '#tui/prompts/suggest/keys'; +import { moveSuggestionHighlight } from '#console/prompts/suggest/keys'; +import type { SuggestNavigationAction } from '#console/prompts/suggest/keys'; export type SuggestHighlightState = { clear(): void; diff --git a/packages/tui/src/prompts/suggest/read/submission.ts b/pkgs-ts/console/src/prompts/suggest/read/submission.ts similarity index 67% rename from packages/tui/src/prompts/suggest/read/submission.ts rename to pkgs-ts/console/src/prompts/suggest/read/submission.ts index 64233990..3ec71fbc 100644 --- a/packages/tui/src/prompts/suggest/read/submission.ts +++ b/pkgs-ts/console/src/prompts/suggest/read/submission.ts @@ -1,6 +1,6 @@ -import { suggestionReadResult } from '#tui/prompts/suggest/read-result'; -import type { TextSuggestionReadResult } from '#tui/prompts/suggest/read-result'; -import type { SuggestReaderSession } from '#tui/prompts/suggest/read/session'; +import { suggestionReadResult } from '#console/prompts/suggest/read-result'; +import type { TextSuggestionReadResult } from '#console/prompts/suggest/read-result'; +import type { SuggestReaderSession } from '#console/prompts/suggest/read/session'; export const currentSuggestionValue = (session: SuggestReaderSession): TextSuggestionReadResult => { return suggestionReadResult(session.state().value, true, false, session.frame()); diff --git a/packages/tui/src/prompts/suggest/render-autocomplete.ts b/pkgs-ts/console/src/prompts/suggest/render-autocomplete.ts similarity index 71% rename from packages/tui/src/prompts/suggest/render-autocomplete.ts rename to pkgs-ts/console/src/prompts/suggest/render-autocomplete.ts index 5634957d..dd9c461e 100644 --- a/packages/tui/src/prompts/suggest/render-autocomplete.ts +++ b/pkgs-ts/console/src/prompts/suggest/render-autocomplete.ts @@ -1,10 +1,10 @@ -import { promptEnvironment } from '#tui/environment'; -import { joinedInfoDetails, resolveInfo } from '#tui/concerns/info'; -import { autocompleteDisplayValue } from '#tui/prompts/suggest/ghost-text'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red, strikethrough } from '#tui/theme/styles'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { promptEnvironment } from '#console/environment'; +import { joinedInfoDetails, resolveInfo } from '#console/concerns/info'; +import { autocompleteDisplayValue } from '#console/prompts/suggest/ghost-text'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red, strikethrough } from '#console/theme/styles'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TypedValueState } from '#console/typed-value/types'; export const renderAutocomplete = (message: string, state: TypedValueState, matches: string[], highlighted: number, hint = '', placeholder = '', info?: SuggestOptions['info']): string => { const value = state.value.length === 0 ? dim(placeholder) : autocompleteDisplayValue(state, matches[highlighted], placeholder); diff --git a/packages/tui/src/prompts/suggest/render.ts b/pkgs-ts/console/src/prompts/suggest/render.ts similarity index 74% rename from packages/tui/src/prompts/suggest/render.ts rename to pkgs-ts/console/src/prompts/suggest/render.ts index 5213ece6..921c5cbb 100644 --- a/packages/tui/src/prompts/suggest/render.ts +++ b/pkgs-ts/console/src/prompts/suggest/render.ts @@ -1,9 +1,9 @@ -import { promptEnvironment } from '#tui/environment'; -import { resolveInfo } from '#tui/concerns/info'; -import { renderSuggestBody } from '#tui/prompts/suggest/render/body'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red, strikethrough } from '#tui/theme/styles'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; +import { promptEnvironment } from '#console/environment'; +import { resolveInfo } from '#console/concerns/info'; +import { renderSuggestBody } from '#console/prompts/suggest/render/body'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red, strikethrough } from '#console/theme/styles'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; export const renderSuggestions = ( message: string, diff --git a/packages/tui/src/prompts/suggest/render/body.ts b/pkgs-ts/console/src/prompts/suggest/render/body.ts similarity index 71% rename from packages/tui/src/prompts/suggest/render/body.ts rename to pkgs-ts/console/src/prompts/suggest/render/body.ts index 089bc87e..ba5cef8d 100644 --- a/packages/tui/src/prompts/suggest/render/body.ts +++ b/pkgs-ts/console/src/prompts/suggest/render/body.ts @@ -1,6 +1,6 @@ -import { dim } from '#tui/theme/styles'; -import { valueWithCursor } from '#tui/typed-value/cursor'; -import { renderSuggestRows } from '#tui/prompts/suggest/render/rows'; +import { dim } from '#console/theme/styles'; +import { valueWithCursor } from '#console/typed-value/cursor'; +import { renderSuggestRows } from '#console/prompts/suggest/render/rows'; export const renderSuggestBody = (value: string, cursor: number, placeholder: string, matches: string[], highlighted: number | null, scroll?: number): string => { const query = value.length > 0 ? valueWithCursor(value, cursor) : dim(placeholder); diff --git a/packages/tui/src/prompts/suggest/render/rows.ts b/pkgs-ts/console/src/prompts/suggest/render/rows.ts similarity index 74% rename from packages/tui/src/prompts/suggest/render/rows.ts rename to pkgs-ts/console/src/prompts/suggest/render/rows.ts index 4e6748d5..c6e7a1bb 100644 --- a/packages/tui/src/prompts/suggest/render/rows.ts +++ b/pkgs-ts/console/src/prompts/suggest/render/rows.ts @@ -1,6 +1,6 @@ -import { choiceWindow } from '#tui/concerns/choices'; -import { renderScrollbarRows } from '#tui/concerns/scrollbar'; -import { cyan, dim } from '#tui/theme/styles'; +import { choiceWindow } from '#console/concerns/choices'; +import { renderScrollbarRows } from '#console/concerns/scrollbar'; +import { cyan, dim } from '#console/theme/styles'; export const renderSuggestRows = (matches: string[], highlighted: number | null, scroll?: number): string => { const window = choiceWindow(matches.length, highlighted ?? 0, scroll); diff --git a/packages/tui/src/prompts/suggest/resolve.ts b/pkgs-ts/console/src/prompts/suggest/resolve.ts similarity index 71% rename from packages/tui/src/prompts/suggest/resolve.ts rename to pkgs-ts/console/src/prompts/suggest/resolve.ts index aae7f4b6..5dbc519a 100644 --- a/packages/tui/src/prompts/suggest/resolve.ts +++ b/pkgs-ts/console/src/prompts/suggest/resolve.ts @@ -1,5 +1,5 @@ -import { resolveSuggestionSource } from '#tui/prompts/suggest/validators/source'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; +import { resolveSuggestionSource } from '#console/prompts/suggest/validators/source'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; export const resolveSuggestions = async (source: SuggestOptions['options'], query: string): Promise => { const resolved = await resolveSuggestionSource(source, query); diff --git a/packages/tui/src/prompts/suggest/state/query.ts b/pkgs-ts/console/src/prompts/suggest/state/query.ts similarity index 78% rename from packages/tui/src/prompts/suggest/state/query.ts rename to pkgs-ts/console/src/prompts/suggest/state/query.ts index aad2a208..da6424d7 100644 --- a/packages/tui/src/prompts/suggest/state/query.ts +++ b/pkgs-ts/console/src/prompts/suggest/state/query.ts @@ -1,8 +1,8 @@ -import { applyTypedKey } from '#tui/typed-value'; -import { initialSuggestionState } from '#tui/prompts/suggest/read-result'; -import { resolveSuggestions } from '#tui/prompts/suggest/resolve'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { TypedValueState } from '#tui/typed-value/types'; +import { applyTypedKey } from '#console/typed-value'; +import { initialSuggestionState } from '#console/prompts/suggest/read-result'; +import { resolveSuggestions } from '#console/prompts/suggest/resolve'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { TypedValueState } from '#console/typed-value/types'; export type SuggestQueryInputResult = { cancelled: boolean; diff --git a/packages/tui/src/prompts/suggest/suggest.ts b/pkgs-ts/console/src/prompts/suggest/suggest.ts similarity index 71% rename from packages/tui/src/prompts/suggest/suggest.ts rename to pkgs-ts/console/src/prompts/suggest/suggest.ts index fe624723..1331f9d8 100644 --- a/packages/tui/src/prompts/suggest/suggest.ts +++ b/pkgs-ts/console/src/prompts/suggest/suggest.ts @@ -1,9 +1,9 @@ -import { runTextSuggestionPrompt } from '#tui/prompts/suggest/lifecycle'; -import { readSuggestionValue } from '#tui/prompts/suggest/read'; -import { renderSubmittedSuggestion } from '#tui/prompts/suggest/render'; -import { suggestOptions } from '#tui/prompts/suggest/options'; -import type { SuggestOptions } from '#tui/prompts/suggest/options'; -import type { MaybePromise, TextPromptOptions } from '#tui/types'; +import { runTextSuggestionPrompt } from '#console/prompts/suggest/lifecycle'; +import { readSuggestionValue } from '#console/prompts/suggest/read'; +import { renderSubmittedSuggestion } from '#console/prompts/suggest/render'; +import { suggestOptions } from '#console/prompts/suggest/options'; +import type { SuggestOptions } from '#console/prompts/suggest/options'; +import type { MaybePromise, TextPromptOptions } from '#console/types'; export function suggest(options: SuggestOptions): Promise; diff --git a/packages/tui/src/prompts/suggest/validators/overload.ts b/pkgs-ts/console/src/prompts/suggest/validators/overload.ts similarity index 100% rename from packages/tui/src/prompts/suggest/validators/overload.ts rename to pkgs-ts/console/src/prompts/suggest/validators/overload.ts diff --git a/packages/tui/src/prompts/suggest/validators/source.ts b/pkgs-ts/console/src/prompts/suggest/validators/source.ts similarity index 92% rename from packages/tui/src/prompts/suggest/validators/source.ts rename to pkgs-ts/console/src/prompts/suggest/validators/source.ts index 2d757c3a..56cdccba 100644 --- a/packages/tui/src/prompts/suggest/validators/source.ts +++ b/pkgs-ts/console/src/prompts/suggest/validators/source.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; -import type { MaybePromise } from '#tui/types'; +import { functionSchema } from '#console/validators/function'; +import type { MaybePromise } from '#console/types'; type SuggestionSourceCallback = (query: string) => MaybePromise; diff --git a/packages/tui/src/prompts/text-default.ts b/pkgs-ts/console/src/prompts/text-default.ts similarity index 82% rename from packages/tui/src/prompts/text-default.ts rename to pkgs-ts/console/src/prompts/text-default.ts index 4d1a5710..66d56113 100644 --- a/packages/tui/src/prompts/text-default.ts +++ b/pkgs-ts/console/src/prompts/text-default.ts @@ -1,4 +1,4 @@ -import type { TextPromptOptions } from '#tui/types'; +import type { TextPromptOptions } from '#console/types'; export const transformedTextDefault = async (options: Pick): Promise => { const value = options.default ?? ''; diff --git a/packages/tui/src/prompts/text.ts b/pkgs-ts/console/src/prompts/text.ts similarity index 79% rename from packages/tui/src/prompts/text.ts rename to pkgs-ts/console/src/prompts/text.ts index 28311c71..65676bc0 100644 --- a/packages/tui/src/prompts/text.ts +++ b/pkgs-ts/console/src/prompts/text.ts @@ -1,6 +1,6 @@ -import { normalizeTextPromptOptions } from '#tui/prompts/text/options'; -import { runTextPrompt } from '#tui/prompts/text/run'; -import type { TextPromptOptions } from '#tui/types'; +import { normalizeTextPromptOptions } from '#console/prompts/text/options'; +import { runTextPrompt } from '#console/prompts/text/run'; +import type { TextPromptOptions } from '#console/types'; export function text(options: TextPromptOptions): Promise; diff --git a/packages/tui/src/prompts/text/options.ts b/pkgs-ts/console/src/prompts/text/options.ts similarity index 78% rename from packages/tui/src/prompts/text/options.ts rename to pkgs-ts/console/src/prompts/text/options.ts index 18620151..3e6a1987 100644 --- a/packages/tui/src/prompts/text/options.ts +++ b/pkgs-ts/console/src/prompts/text/options.ts @@ -1,6 +1,6 @@ -import { textOptions } from '#tui/concerns/text-options'; -import { isTextPromptLabel } from '#tui/concerns/validators/text-options'; -import type { TextPromptOptions } from '#tui/types'; +import { textOptions } from '#console/concerns/text-options'; +import { isTextPromptLabel } from '#console/concerns/validators/text-options'; +import type { TextPromptOptions } from '#console/types'; export type TextPromptArgumentOptions = { defaultValue: string; diff --git a/packages/tui/src/prompts/text/run.ts b/pkgs-ts/console/src/prompts/text/run.ts similarity index 70% rename from packages/tui/src/prompts/text/run.ts rename to pkgs-ts/console/src/prompts/text/run.ts index 80d6094e..63245ab7 100644 --- a/packages/tui/src/prompts/text/run.ts +++ b/pkgs-ts/console/src/prompts/text/run.ts @@ -1,10 +1,10 @@ -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { transformedTextDefault } from '#tui/prompts/text-default'; -import { readTypedValue } from '#tui/typed-value'; -import { renderSubmittedTypedValue } from '#tui/typed-value/render'; -import type { TextPromptOptions } from '#tui/types'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { transformedTextDefault } from '#console/prompts/text-default'; +import { readTypedValue } from '#console/typed-value'; +import { renderSubmittedTypedValue } from '#console/typed-value/render'; +import type { TextPromptOptions } from '#console/types'; export const runTextPrompt = async (options: TextPromptOptions): Promise => { const validationOptions: TextPromptOptions = { diff --git a/packages/tui/src/prompts/textarea.ts b/pkgs-ts/console/src/prompts/textarea.ts similarity index 80% rename from packages/tui/src/prompts/textarea.ts rename to pkgs-ts/console/src/prompts/textarea.ts index 7b91271a..61fafa95 100644 --- a/packages/tui/src/prompts/textarea.ts +++ b/pkgs-ts/console/src/prompts/textarea.ts @@ -1,6 +1,6 @@ -import { normalizeTextareaPromptOptions } from '#tui/prompts/textarea/options'; -import { runTextareaPrompt } from '#tui/prompts/textarea/run'; -import type { TextareaPromptOptions } from '#tui/types'; +import { normalizeTextareaPromptOptions } from '#console/prompts/textarea/options'; +import { runTextareaPrompt } from '#console/prompts/textarea/run'; +import type { TextareaPromptOptions } from '#console/types'; export function textarea(options: TextareaPromptOptions): Promise; diff --git a/packages/tui/src/prompts/textarea/options.ts b/pkgs-ts/console/src/prompts/textarea/options.ts similarity index 86% rename from packages/tui/src/prompts/textarea/options.ts rename to pkgs-ts/console/src/prompts/textarea/options.ts index 103b1985..99042223 100644 --- a/packages/tui/src/prompts/textarea/options.ts +++ b/pkgs-ts/console/src/prompts/textarea/options.ts @@ -1,5 +1,5 @@ -import { isTextPromptLabel } from '#tui/concerns/validators/text-options'; -import type { TextareaPromptOptions } from '#tui/types'; +import { isTextPromptLabel } from '#console/concerns/validators/text-options'; +import type { TextareaPromptOptions } from '#console/types'; export type TextareaPromptArgumentOptions = { defaultValue: string; diff --git a/packages/tui/src/prompts/textarea/run.ts b/pkgs-ts/console/src/prompts/textarea/run.ts similarity index 72% rename from packages/tui/src/prompts/textarea/run.ts rename to pkgs-ts/console/src/prompts/textarea/run.ts index 1fd0fbf1..aa35484d 100644 --- a/packages/tui/src/prompts/textarea/run.ts +++ b/pkgs-ts/console/src/prompts/textarea/run.ts @@ -1,10 +1,10 @@ -import { promptUntilValid, promptWithFallback } from '#tui/prompt'; -import { activePromptFrame } from '#tui/prompt/active-frame'; -import { createPromptSubmissionState } from '#tui/prompt/submission'; -import { transformedTextDefault } from '#tui/prompts/text-default'; -import { readTypedValue } from '#tui/typed-value'; -import { renderSubmittedTextareaFrame } from '#tui/typed-value/textarea-frame'; -import type { TextareaPromptOptions } from '#tui/types'; +import { promptUntilValid, promptWithFallback } from '#console/prompt'; +import { activePromptFrame } from '#console/prompt/active-frame'; +import { createPromptSubmissionState } from '#console/prompt/submission'; +import { transformedTextDefault } from '#console/prompts/text-default'; +import { readTypedValue } from '#console/typed-value'; +import { renderSubmittedTextareaFrame } from '#console/typed-value/textarea-frame'; +import type { TextareaPromptOptions } from '#console/types'; export const runTextareaPrompt = async (options: TextareaPromptOptions, fallbackRows: number): Promise => { const validationOptions: TextareaPromptOptions = { diff --git a/pkgs-ts/console/src/status.ts b/pkgs-ts/console/src/status.ts new file mode 100644 index 00000000..71ecad86 --- /dev/null +++ b/pkgs-ts/console/src/status.ts @@ -0,0 +1,6 @@ +export { progress, Progress } from '#console/status/progress'; +export type { ProgressSignalTarget } from '#console/status/progress'; +export { spin } from '#console/status/spinner'; +export { Logger, task } from '#console/status/task'; +export type { TaskDefinition } from '#console/status/task'; +export { Stream, stream } from '#console/status/stream'; diff --git a/packages/tui/src/status/frame.ts b/pkgs-ts/console/src/status/frame.ts similarity index 85% rename from packages/tui/src/status/frame.ts rename to pkgs-ts/console/src/status/frame.ts index 8949913e..90955533 100644 --- a/packages/tui/src/status/frame.ts +++ b/pkgs-ts/console/src/status/frame.ts @@ -1,4 +1,4 @@ -import { erasePreviousLines } from '#tui/terminal'; +import { erasePreviousLines } from '#console/terminal'; export const renderedFrameLineCount = (frame: string): number => { if (frame.length === 0) { diff --git a/packages/tui/src/status/progress.ts b/pkgs-ts/console/src/status/progress.ts similarity index 71% rename from packages/tui/src/status/progress.ts rename to pkgs-ts/console/src/status/progress.ts index 34c69c71..c3e75376 100644 --- a/packages/tui/src/status/progress.ts +++ b/pkgs-ts/console/src/status/progress.ts @@ -1,12 +1,12 @@ -import { Progress } from '#tui/status/progress/progress'; -import { runProgressSteps } from '#tui/status/progress/run'; -import { progressValues } from '#tui/status/progress/steps'; -import type { MaybePromise } from '#tui/types'; +import { Progress } from '#console/status/progress/progress'; +import { runProgressSteps } from '#console/status/progress/run'; +import { progressValues } from '#console/status/progress/steps'; +import type { MaybePromise } from '#console/types'; -import { isProgressTotalArgument, progressMessageArgument, progressStepsArgument } from '#tui/status/progress/validators/arguments'; +import { isProgressTotalArgument, progressMessageArgument, progressStepsArgument } from '#console/status/progress/validators/arguments'; export { Progress }; -export type { ProgressSignalTarget } from '#tui/status/progress/progress'; +export type { ProgressSignalTarget } from '#console/status/progress/progress'; export function progress(total: number, message?: string): Progress; diff --git a/packages/tui/src/status/progress/controller.ts b/pkgs-ts/console/src/status/progress/controller.ts similarity index 74% rename from packages/tui/src/status/progress/controller.ts rename to pkgs-ts/console/src/status/progress/controller.ts index 42686c51..13fda532 100644 --- a/packages/tui/src/status/progress/controller.ts +++ b/pkgs-ts/console/src/status/progress/controller.ts @@ -1,7 +1,7 @@ -import { ProgressRenderer } from '#tui/status/progress/renderer'; -import { ProgressState } from '#tui/status/progress/state'; -import { ProgressTerminalLifecycle } from '#tui/status/progress/terminal'; -import type { ProgressSignalTarget } from '#tui/status/progress/terminal'; +import { ProgressRenderer } from '#console/status/progress/renderer'; +import { ProgressState } from '#console/status/progress/state'; +import { ProgressTerminalLifecycle } from '#console/status/progress/terminal'; +import type { ProgressSignalTarget } from '#console/status/progress/terminal'; export class ProgressController { readonly renderer: ProgressRenderer; diff --git a/packages/tui/src/status/progress/labels.ts b/pkgs-ts/console/src/status/progress/labels.ts similarity index 76% rename from packages/tui/src/status/progress/labels.ts rename to pkgs-ts/console/src/status/progress/labels.ts index bd1b84a8..49dbf328 100644 --- a/packages/tui/src/status/progress/labels.ts +++ b/pkgs-ts/console/src/status/progress/labels.ts @@ -1,4 +1,4 @@ -import type { ProgressController } from '#tui/status/progress/controller'; +import type { ProgressController } from '#console/status/progress/controller'; export const setProgressLabel = (controller: ProgressController, value: string): void => { controller.state.label(value); diff --git a/packages/tui/src/status/progress/progress.ts b/pkgs-ts/console/src/status/progress/progress.ts similarity index 73% rename from packages/tui/src/status/progress/progress.ts rename to pkgs-ts/console/src/status/progress/progress.ts index 372c1cbe..7cd13fec 100644 --- a/packages/tui/src/status/progress/progress.ts +++ b/pkgs-ts/console/src/status/progress/progress.ts @@ -1,10 +1,10 @@ -import { ProgressController } from '#tui/status/progress/controller'; -import { setProgressHint, setProgressLabel } from '#tui/status/progress/labels'; -import { progressPromptError } from '#tui/status/progress/prompt'; -import { progressCurrent, progressPercentageValue, progressValue } from '#tui/status/progress/readback'; -import type { ProgressSignalTarget } from '#tui/status/progress/terminal'; +import { ProgressController } from '#console/status/progress/controller'; +import { setProgressHint, setProgressLabel } from '#console/status/progress/labels'; +import { progressPromptError } from '#console/status/progress/prompt'; +import { progressCurrent, progressPercentageValue, progressValue } from '#console/status/progress/readback'; +import type { ProgressSignalTarget } from '#console/status/progress/terminal'; -export type { ProgressSignalTarget } from '#tui/status/progress/terminal'; +export type { ProgressSignalTarget } from '#console/status/progress/terminal'; export class Progress { readonly #controller: ProgressController; diff --git a/packages/tui/src/status/progress/prompt.ts b/pkgs-ts/console/src/status/progress/prompt.ts similarity index 100% rename from packages/tui/src/status/progress/prompt.ts rename to pkgs-ts/console/src/status/progress/prompt.ts diff --git a/packages/tui/src/status/progress/readback.ts b/pkgs-ts/console/src/status/progress/readback.ts similarity index 78% rename from packages/tui/src/status/progress/readback.ts rename to pkgs-ts/console/src/status/progress/readback.ts index a658855f..1dcf1249 100644 --- a/packages/tui/src/status/progress/readback.ts +++ b/pkgs-ts/console/src/status/progress/readback.ts @@ -1,4 +1,4 @@ -import type { ProgressController } from '#tui/status/progress/controller'; +import type { ProgressController } from '#console/status/progress/controller'; export const progressCurrent = (controller: ProgressController): number => { return controller.state.current(); diff --git a/packages/tui/src/status/progress/render.ts b/pkgs-ts/console/src/status/progress/render.ts similarity index 83% rename from packages/tui/src/status/progress/render.ts rename to pkgs-ts/console/src/status/progress/render.ts index f6bfe93b..6b682890 100644 --- a/packages/tui/src/status/progress/render.ts +++ b/pkgs-ts/console/src/status/progress/render.ts @@ -1,6 +1,6 @@ -import { renderBox } from '#tui/theme/box'; -import { clampedProgressCurrent, progressRatio } from '#tui/status/progress/state/value'; -import { progressFrameWidth } from '#tui/status/progress/validators/frame'; +import { renderBox } from '#console/theme/box'; +import { clampedProgressCurrent, progressRatio } from '#console/status/progress/state/value'; +import { progressFrameWidth } from '#console/status/progress/validators/frame'; export type ProgressFrameState = 'active' | 'cancel' | 'error' | 'submit'; diff --git a/packages/tui/src/status/progress/renderer.ts b/pkgs-ts/console/src/status/progress/renderer.ts similarity index 52% rename from packages/tui/src/status/progress/renderer.ts rename to pkgs-ts/console/src/status/progress/renderer.ts index ea413cde..b0b1a61f 100644 --- a/packages/tui/src/status/progress/renderer.ts +++ b/pkgs-ts/console/src/status/progress/renderer.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderProgressFrame } from '#tui/status/progress/render'; -import type { ProgressStateSnapshot } from '#tui/status/progress/state'; -import type { ProgressTerminalLifecycle } from '#tui/status/progress/terminal'; +import { promptEnvironment } from '#console/environment'; +import { renderProgressFrame } from '#console/status/progress/render'; +import type { ProgressStateSnapshot } from '#console/status/progress/state'; +import type { ProgressTerminalLifecycle } from '#console/status/progress/terminal'; export class ProgressRenderer { constructor(private readonly terminal: ProgressTerminalLifecycle) {} diff --git a/packages/tui/src/status/progress/run.ts b/pkgs-ts/console/src/status/progress/run.ts similarity index 91% rename from packages/tui/src/status/progress/run.ts rename to pkgs-ts/console/src/status/progress/run.ts index 569599d5..47c5f4e7 100644 --- a/packages/tui/src/status/progress/run.ts +++ b/pkgs-ts/console/src/status/progress/run.ts @@ -1,4 +1,4 @@ -import type { MaybePromise } from '#tui/types'; +import type { MaybePromise } from '#console/types'; type ProgressRunner = { advance(): void; diff --git a/packages/tui/src/status/progress/state.ts b/pkgs-ts/console/src/status/progress/state.ts similarity index 70% rename from packages/tui/src/status/progress/state.ts rename to pkgs-ts/console/src/status/progress/state.ts index 6fd84ea9..bb1ce690 100644 --- a/packages/tui/src/status/progress/state.ts +++ b/pkgs-ts/console/src/status/progress/state.ts @@ -1,10 +1,10 @@ -import { progressStateSnapshot } from '#tui/status/progress/state/snapshot'; -import { clampedProgressCurrent, nextProgressCurrent, progressRatio } from '#tui/status/progress/state/value'; -import { parseProgressTotal } from '#tui/status/validators/progress'; -import type { ProgressFrameState } from '#tui/status/progress/render'; -import type { ProgressStateSnapshot } from '#tui/status/progress/state/snapshot'; +import { progressStateSnapshot } from '#console/status/progress/state/snapshot'; +import { clampedProgressCurrent, nextProgressCurrent, progressRatio } from '#console/status/progress/state/value'; +import { parseProgressTotal } from '#console/status/validators/progress'; +import type { ProgressFrameState } from '#console/status/progress/render'; +import type { ProgressStateSnapshot } from '#console/status/progress/state/snapshot'; -export type { ProgressStateSnapshot } from '#tui/status/progress/state/snapshot'; +export type { ProgressStateSnapshot } from '#console/status/progress/state/snapshot'; export class ProgressState { #current = 0; diff --git a/packages/tui/src/status/progress/state/snapshot.ts b/pkgs-ts/console/src/status/progress/state/snapshot.ts similarity index 81% rename from packages/tui/src/status/progress/state/snapshot.ts rename to pkgs-ts/console/src/status/progress/state/snapshot.ts index 9f7fb04e..b284b1d6 100644 --- a/packages/tui/src/status/progress/state/snapshot.ts +++ b/pkgs-ts/console/src/status/progress/state/snapshot.ts @@ -1,4 +1,4 @@ -import type { ProgressFrameState } from '#tui/status/progress/render'; +import type { ProgressFrameState } from '#console/status/progress/render'; export type ProgressStateSnapshot = { current: number; diff --git a/packages/tui/src/status/progress/state/value.ts b/pkgs-ts/console/src/status/progress/state/value.ts similarity index 86% rename from packages/tui/src/status/progress/state/value.ts rename to pkgs-ts/console/src/status/progress/state/value.ts index 6f80cf9d..e63894a2 100644 --- a/packages/tui/src/status/progress/state/value.ts +++ b/pkgs-ts/console/src/status/progress/state/value.ts @@ -1,4 +1,4 @@ -import { parseProgressStep } from '#tui/status/validators/progress'; +import { parseProgressStep } from '#console/status/validators/progress'; export const nextProgressCurrent = (current: number, total: number, step: number): number => { return Math.max(0, Math.min(current + parseProgressStep(step), total)); diff --git a/packages/tui/src/status/progress/steps.ts b/pkgs-ts/console/src/status/progress/steps.ts similarity index 76% rename from packages/tui/src/status/progress/steps.ts rename to pkgs-ts/console/src/status/progress/steps.ts index d606dc5c..8a2c9c51 100644 --- a/packages/tui/src/status/progress/steps.ts +++ b/pkgs-ts/console/src/status/progress/steps.ts @@ -1,4 +1,4 @@ -import { parseProgressValuesInput } from '#tui/status/validators/progress'; +import { parseProgressValuesInput } from '#console/status/validators/progress'; export const progressValues = (steps: Iterable | number): Array => { const parsed = parseProgressValuesInput(steps); diff --git a/packages/tui/src/status/progress/terminal.ts b/pkgs-ts/console/src/status/progress/terminal.ts similarity index 71% rename from packages/tui/src/status/progress/terminal.ts rename to pkgs-ts/console/src/status/progress/terminal.ts index f1837e6d..22b7bdd2 100644 --- a/packages/tui/src/status/progress/terminal.ts +++ b/pkgs-ts/console/src/status/progress/terminal.ts @@ -1,9 +1,9 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { ProgressSignalHandlers } from '#tui/status/progress/terminal/signals'; -import { hideCursor, showCursor } from '#tui/terminal'; -import type { ProgressSignalTarget } from '#tui/status/progress/terminal/signals'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { ProgressSignalHandlers } from '#console/status/progress/terminal/signals'; +import { hideCursor, showCursor } from '#console/terminal'; +import type { ProgressSignalTarget } from '#console/status/progress/terminal/signals'; -export type { ProgressSignalTarget } from '#tui/status/progress/terminal/signals'; +export type { ProgressSignalTarget } from '#console/status/progress/terminal/signals'; export class ProgressTerminalLifecycle { #cursorHidden = false; diff --git a/packages/tui/src/status/progress/terminal/signals.ts b/pkgs-ts/console/src/status/progress/terminal/signals.ts similarity index 82% rename from packages/tui/src/status/progress/terminal/signals.ts rename to pkgs-ts/console/src/status/progress/terminal/signals.ts index fbcfad72..baa6d372 100644 --- a/packages/tui/src/status/progress/terminal/signals.ts +++ b/pkgs-ts/console/src/status/progress/terminal/signals.ts @@ -1,5 +1,5 @@ -import { parseStatusSignalTarget } from '#tui/status/validators/signal-target'; -import type { StatusSignalTarget } from '#tui/status/validators/signal-target'; +import { parseStatusSignalTarget } from '#console/status/validators/signal-target'; +import type { StatusSignalTarget } from '#console/status/validators/signal-target'; const progressSignals = ['SIGINT', 'SIGTERM'] as const; diff --git a/packages/tui/src/status/progress/validators/arguments.ts b/pkgs-ts/console/src/status/progress/validators/arguments.ts similarity index 94% rename from packages/tui/src/status/progress/validators/arguments.ts rename to pkgs-ts/console/src/status/progress/validators/arguments.ts index 2cf51bbf..50529a2a 100644 --- a/packages/tui/src/status/progress/validators/arguments.ts +++ b/pkgs-ts/console/src/status/progress/validators/arguments.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { iterableSchema } from '#tui/validators/iterable'; +import { iterableSchema } from '#console/validators/iterable'; const progressTotalArgumentSchema = z.union([z.number(), z.literal(Number.POSITIVE_INFINITY), z.literal(Number.NEGATIVE_INFINITY)]); const progressMessageArgumentSchema = z.string(); diff --git a/packages/tui/src/status/progress/validators/frame.ts b/pkgs-ts/console/src/status/progress/validators/frame.ts similarity index 100% rename from packages/tui/src/status/progress/validators/frame.ts rename to pkgs-ts/console/src/status/progress/validators/frame.ts diff --git a/packages/tui/src/status/signals.ts b/pkgs-ts/console/src/status/signals.ts similarity index 85% rename from packages/tui/src/status/signals.ts rename to pkgs-ts/console/src/status/signals.ts index 1190cce3..782140be 100644 --- a/packages/tui/src/status/signals.ts +++ b/pkgs-ts/console/src/status/signals.ts @@ -1,5 +1,5 @@ -import { parseStatusSignalTarget } from '#tui/status/validators/signal-target'; -import type { StatusSignalTarget } from '#tui/status/validators/signal-target'; +import { parseStatusSignalTarget } from '#console/status/validators/signal-target'; +import type { StatusSignalTarget } from '#console/status/validators/signal-target'; const statusSignals = ['SIGINT', 'SIGTERM'] as const; diff --git a/packages/tui/src/status/spinner.ts b/pkgs-ts/console/src/status/spinner.ts similarity index 70% rename from packages/tui/src/status/spinner.ts rename to pkgs-ts/console/src/status/spinner.ts index d0734fdc..154eabca 100644 --- a/packages/tui/src/status/spinner.ts +++ b/pkgs-ts/console/src/status/spinner.ts @@ -1,6 +1,6 @@ -import { resolveSpinnerOptions } from '#tui/status/spinner/options'; -import { runSpinnerLifecycle } from '#tui/status/spinner/lifecycle'; -import type { MaybePromise, StatusOptions } from '#tui/types'; +import { resolveSpinnerOptions } from '#console/status/spinner/options'; +import { runSpinnerLifecycle } from '#console/status/spinner/lifecycle'; +import type { MaybePromise, StatusOptions } from '#console/types'; export function spin(callback: () => MaybePromise, options?: StatusOptions): Promise; diff --git a/packages/tui/src/status/spinner/lifecycle.ts b/pkgs-ts/console/src/status/spinner/lifecycle.ts similarity index 61% rename from packages/tui/src/status/spinner/lifecycle.ts rename to pkgs-ts/console/src/status/spinner/lifecycle.ts index fcda53b2..625d4025 100644 --- a/packages/tui/src/status/spinner/lifecycle.ts +++ b/pkgs-ts/console/src/status/spinner/lifecycle.ts @@ -1,9 +1,9 @@ -import { promptEnvironment } from '#tui/environment'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { StatusSignalCleanup } from '#tui/status/signals'; -import { renderSpinnerFrame } from '#tui/status/spinner/render'; -import { hideCursor, showCursor } from '#tui/terminal'; -import type { MaybePromise } from '#tui/types'; +import { promptEnvironment } from '#console/environment'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { StatusSignalCleanup } from '#console/status/signals'; +import { renderSpinnerFrame } from '#console/status/spinner/render'; +import { hideCursor, showCursor } from '#console/terminal'; +import type { MaybePromise } from '#console/types'; export const runSpinnerLifecycle = async (message: string, callback: () => MaybePromise): Promise => { const frame = renderSpinnerFrame(message); diff --git a/packages/tui/src/status/spinner/options.ts b/pkgs-ts/console/src/status/spinner/options.ts similarity index 82% rename from packages/tui/src/status/spinner/options.ts rename to pkgs-ts/console/src/status/spinner/options.ts index be129f74..21e5938d 100644 --- a/packages/tui/src/status/spinner/options.ts +++ b/pkgs-ts/console/src/status/spinner/options.ts @@ -1,5 +1,5 @@ -import { isSpinnerCallback, isSpinnerMessage, parseSpinnerCallback, parseSpinnerOptions } from '#tui/status/spinner/validators/options'; -import type { MaybePromise, StatusOptions } from '#tui/types'; +import { isSpinnerCallback, isSpinnerMessage, parseSpinnerCallback, parseSpinnerOptions } from '#console/status/spinner/validators/options'; +import type { MaybePromise, StatusOptions } from '#console/types'; export type ResolvedSpinnerOptions = { callback: () => MaybePromise; diff --git a/packages/tui/src/status/spinner/render.ts b/pkgs-ts/console/src/status/spinner/render.ts similarity index 100% rename from packages/tui/src/status/spinner/render.ts rename to pkgs-ts/console/src/status/spinner/render.ts diff --git a/packages/tui/src/status/spinner/validators/options.ts b/pkgs-ts/console/src/status/spinner/validators/options.ts similarity index 91% rename from packages/tui/src/status/spinner/validators/options.ts rename to pkgs-ts/console/src/status/spinner/validators/options.ts index 2799c173..e61c1cf6 100644 --- a/packages/tui/src/status/spinner/validators/options.ts +++ b/pkgs-ts/console/src/status/spinner/validators/options.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; -import type { MaybePromise } from '#tui/types'; +import { functionSchema } from '#console/validators/function'; +import type { MaybePromise } from '#console/types'; const spinnerCallbackSchema = (): z.ZodType<() => MaybePromise> => functionSchema<() => MaybePromise>(); const spinnerMessageSchema = z.string(); diff --git a/packages/tui/src/status/stream.ts b/pkgs-ts/console/src/status/stream.ts similarity index 74% rename from packages/tui/src/status/stream.ts rename to pkgs-ts/console/src/status/stream.ts index a9d14adb..4832ac37 100644 --- a/packages/tui/src/status/stream.ts +++ b/pkgs-ts/console/src/status/stream.ts @@ -1,6 +1,6 @@ -import { Stream } from '#tui/status/stream/output'; +import { Stream } from '#console/status/stream/output'; -export { Stream } from '#tui/status/stream/output'; +export { Stream } from '#console/status/stream/output'; export function stream(): Stream; diff --git a/packages/tui/src/status/stream/buffer.ts b/pkgs-ts/console/src/status/stream/buffer.ts similarity index 89% rename from packages/tui/src/status/stream/buffer.ts rename to pkgs-ts/console/src/status/stream/buffer.ts index 00333915..f9caa3ef 100644 --- a/packages/tui/src/status/stream/buffer.ts +++ b/pkgs-ts/console/src/status/stream/buffer.ts @@ -1,4 +1,4 @@ -import { parseStreamFadeSteps } from '#tui/status/stream/validators/fade'; +import { parseStreamFadeSteps } from '#console/status/stream/validators/fade'; export class StreamBuffer { readonly fading: string[] = []; diff --git a/packages/tui/src/status/stream/fade.ts b/pkgs-ts/console/src/status/stream/fade.ts similarity index 86% rename from packages/tui/src/status/stream/fade.ts rename to pkgs-ts/console/src/status/stream/fade.ts index c97ba7dd..0613f5ef 100644 --- a/packages/tui/src/status/stream/fade.ts +++ b/pkgs-ts/console/src/status/stream/fade.ts @@ -1,7 +1,7 @@ -import { backgroundColor, foregroundColor, supportsTrueColor } from '#tui/terminal'; -import { dim, foregroundRgb } from '#tui/theme/styles'; -import { parseStreamFadeColor, parseStreamFadeSteps, parseStreamFadeTrueColor } from '#tui/status/stream/validators/fade'; -import type { TerminalColor } from '#tui/terminal/capabilities'; +import { backgroundColor, foregroundColor, supportsTrueColor } from '#console/terminal'; +import { dim, foregroundRgb } from '#console/theme/styles'; +import { parseStreamFadeColor, parseStreamFadeSteps, parseStreamFadeTrueColor } from '#console/status/stream/validators/fade'; +import type { TerminalColor } from '#console/terminal/capabilities'; export type StreamFadeOptions = { background?: TerminalColor; diff --git a/packages/tui/src/status/stream/lifecycle.ts b/pkgs-ts/console/src/status/stream/lifecycle.ts similarity index 83% rename from packages/tui/src/status/stream/lifecycle.ts rename to pkgs-ts/console/src/status/stream/lifecycle.ts index 76e1f324..9f84fa2e 100644 --- a/packages/tui/src/status/stream/lifecycle.ts +++ b/pkgs-ts/console/src/status/stream/lifecycle.ts @@ -1,5 +1,5 @@ -import { StatusSignalCleanup } from '#tui/status/signals'; -import { hideCursor, showCursor } from '#tui/terminal'; +import { StatusSignalCleanup } from '#console/status/signals'; +import { hideCursor, showCursor } from '#console/terminal'; export class StreamLifecycle { #closed = false; diff --git a/packages/tui/src/status/stream/output.ts b/pkgs-ts/console/src/status/stream/output.ts similarity index 70% rename from packages/tui/src/status/stream/output.ts rename to pkgs-ts/console/src/status/stream/output.ts index bf60b126..2a11ccce 100644 --- a/packages/tui/src/status/stream/output.ts +++ b/pkgs-ts/console/src/status/stream/output.ts @@ -1,10 +1,10 @@ -import { createStreamOutputContext } from '#tui/status/stream/output/context'; -import { streamClosedError, streamPromptError } from '#tui/status/stream/output/errors'; -import { pipeStreamSource } from '#tui/status/stream/output/pipe'; -import { streamBufferLines, streamBufferValue } from '#tui/status/stream/output/readback'; -import { flushStreamBuffer, renderStreamBuffer, requestStreamBufferRender } from '#tui/status/stream/output/rendering'; -import { parseStreamChunk } from '#tui/status/stream/validators/chunk'; -import type { StreamOutputContext } from '#tui/status/stream/output/context'; +import { createStreamOutputContext } from '#console/status/stream/output/context'; +import { streamClosedError, streamPromptError } from '#console/status/stream/output/errors'; +import { pipeStreamSource } from '#console/status/stream/output/pipe'; +import { streamBufferLines, streamBufferValue } from '#console/status/stream/output/readback'; +import { flushStreamBuffer, renderStreamBuffer, requestStreamBufferRender } from '#console/status/stream/output/rendering'; +import { parseStreamChunk } from '#console/status/stream/validators/chunk'; +import type { StreamOutputContext } from '#console/status/stream/output/context'; export class Stream { readonly #context: StreamOutputContext = createStreamOutputContext(() => { diff --git a/packages/tui/src/status/stream/output/context.ts b/pkgs-ts/console/src/status/stream/output/context.ts similarity index 59% rename from packages/tui/src/status/stream/output/context.ts rename to pkgs-ts/console/src/status/stream/output/context.ts index bcc4d5a5..b2a84099 100644 --- a/packages/tui/src/status/stream/output/context.ts +++ b/pkgs-ts/console/src/status/stream/output/context.ts @@ -1,7 +1,7 @@ -import { StreamBuffer } from '#tui/status/stream/buffer'; -import { StreamLifecycle } from '#tui/status/stream/lifecycle'; -import { StreamRenderer } from '#tui/status/stream/renderer'; -import { StreamRenderScheduler } from '#tui/status/stream/scheduler'; +import { StreamBuffer } from '#console/status/stream/buffer'; +import { StreamLifecycle } from '#console/status/stream/lifecycle'; +import { StreamRenderer } from '#console/status/stream/renderer'; +import { StreamRenderScheduler } from '#console/status/stream/scheduler'; export type StreamOutputContext = { buffer: StreamBuffer; diff --git a/packages/tui/src/status/stream/output/errors.ts b/pkgs-ts/console/src/status/stream/output/errors.ts similarity index 100% rename from packages/tui/src/status/stream/output/errors.ts rename to pkgs-ts/console/src/status/stream/output/errors.ts diff --git a/packages/tui/src/status/stream/output/pipe.ts b/pkgs-ts/console/src/status/stream/output/pipe.ts similarity index 100% rename from packages/tui/src/status/stream/output/pipe.ts rename to pkgs-ts/console/src/status/stream/output/pipe.ts diff --git a/packages/tui/src/status/stream/output/readback.ts b/pkgs-ts/console/src/status/stream/output/readback.ts similarity index 64% rename from packages/tui/src/status/stream/output/readback.ts rename to pkgs-ts/console/src/status/stream/output/readback.ts index 577edbea..c1dd330e 100644 --- a/packages/tui/src/status/stream/output/readback.ts +++ b/pkgs-ts/console/src/status/stream/output/readback.ts @@ -1,5 +1,5 @@ -import { streamLines } from '#tui/status/stream/render'; -import type { StreamBuffer } from '#tui/status/stream/buffer'; +import { streamLines } from '#console/status/stream/render'; +import type { StreamBuffer } from '#console/status/stream/buffer'; export const streamBufferValue = (buffer: StreamBuffer): string => { return buffer.value(); diff --git a/packages/tui/src/status/stream/output/rendering.ts b/pkgs-ts/console/src/status/stream/output/rendering.ts similarity index 83% rename from packages/tui/src/status/stream/output/rendering.ts rename to pkgs-ts/console/src/status/stream/output/rendering.ts index 643c7efb..db4b82f2 100644 --- a/packages/tui/src/status/stream/output/rendering.ts +++ b/pkgs-ts/console/src/status/stream/output/rendering.ts @@ -1,5 +1,5 @@ -import type { StreamBuffer } from '#tui/status/stream/buffer'; -import type { StreamRenderer } from '#tui/status/stream/renderer'; +import type { StreamBuffer } from '#console/status/stream/buffer'; +import type { StreamRenderer } from '#console/status/stream/renderer'; type StreamRenderContext = { buffer: StreamBuffer; diff --git a/packages/tui/src/status/stream/render.ts b/pkgs-ts/console/src/status/stream/render.ts similarity index 75% rename from packages/tui/src/status/stream/render.ts rename to pkgs-ts/console/src/status/stream/render.ts index e148d080..5cbe03d0 100644 --- a/packages/tui/src/status/stream/render.ts +++ b/pkgs-ts/console/src/status/stream/render.ts @@ -1,7 +1,7 @@ -import { wrap } from '#tui/strings'; -import type { StreamFadeStyle } from '#tui/status/stream/fade'; -import { parseStreamChunkLines } from '#tui/status/stream/validators/chunk'; -import { parseStreamFrameWidth } from '#tui/status/stream/validators/fade'; +import { wrap } from '#console/strings'; +import type { StreamFadeStyle } from '#console/status/stream/fade'; +import { parseStreamChunkLines } from '#console/status/stream/validators/chunk'; +import { parseStreamFrameWidth } from '#console/status/stream/validators/fade'; type StreamFrameOptions = { fading?: string[]; diff --git a/packages/tui/src/status/stream/renderer.ts b/pkgs-ts/console/src/status/stream/renderer.ts similarity index 66% rename from packages/tui/src/status/stream/renderer.ts rename to pkgs-ts/console/src/status/stream/renderer.ts index 4b56a00b..37792692 100644 --- a/packages/tui/src/status/stream/renderer.ts +++ b/pkgs-ts/console/src/status/stream/renderer.ts @@ -1,8 +1,8 @@ -import { promptEnvironment } from '#tui/environment'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { streamFadeStyles } from '#tui/status/stream/fade'; -import { renderStreamFrame } from '#tui/status/stream/render'; -import type { StreamFadeStyle } from '#tui/status/stream/fade'; +import { promptEnvironment } from '#console/environment'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { streamFadeStyles } from '#console/status/stream/fade'; +import { renderStreamFrame } from '#console/status/stream/render'; +import type { StreamFadeStyle } from '#console/status/stream/fade'; type StreamRenderOptions = { fading: string[]; diff --git a/packages/tui/src/status/stream/scheduler.ts b/pkgs-ts/console/src/status/stream/scheduler.ts similarity index 100% rename from packages/tui/src/status/stream/scheduler.ts rename to pkgs-ts/console/src/status/stream/scheduler.ts diff --git a/packages/tui/src/status/stream/validators/chunk.ts b/pkgs-ts/console/src/status/stream/validators/chunk.ts similarity index 100% rename from packages/tui/src/status/stream/validators/chunk.ts rename to pkgs-ts/console/src/status/stream/validators/chunk.ts diff --git a/packages/tui/src/status/stream/validators/fade.ts b/pkgs-ts/console/src/status/stream/validators/fade.ts similarity index 88% rename from packages/tui/src/status/stream/validators/fade.ts rename to pkgs-ts/console/src/status/stream/validators/fade.ts index 449d8f0d..6ef6ad46 100644 --- a/packages/tui/src/status/stream/validators/fade.ts +++ b/pkgs-ts/console/src/status/stream/validators/fade.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { parseTerminalColor } from '#tui/terminal/validators/color'; -import type { TerminalColor } from '#tui/terminal/capabilities'; +import { parseTerminalColor } from '#console/terminal/validators/color'; +import type { TerminalColor } from '#console/terminal/capabilities'; const streamFadeStepsSchema = z.number().finite().positive(); const streamFrameWidthSchema = z.number().finite().positive(); diff --git a/packages/tui/src/status/task.ts b/pkgs-ts/console/src/status/task.ts similarity index 59% rename from packages/tui/src/status/task.ts rename to pkgs-ts/console/src/status/task.ts index 787810c4..1c1abd43 100644 --- a/packages/tui/src/status/task.ts +++ b/pkgs-ts/console/src/status/task.ts @@ -1,11 +1,11 @@ -import { resolveTaskDefinition } from '#tui/status/task/definition'; -import { runTaskLifecycle } from '#tui/status/task/lifecycle'; -import { Logger } from '#tui/status/task/logger'; -import type { TaskDefinition } from '#tui/status/task/definition'; -import type { MaybePromise } from '#tui/types'; +import { resolveTaskDefinition } from '#console/status/task/definition'; +import { runTaskLifecycle } from '#console/status/task/lifecycle'; +import { Logger } from '#console/status/task/logger'; +import type { TaskDefinition } from '#console/status/task/definition'; +import type { MaybePromise } from '#console/types'; export { Logger }; -export type { TaskDefinition } from '#tui/status/task/definition'; +export type { TaskDefinition } from '#console/status/task/definition'; export async function task(definition: TaskDefinition): Promise; diff --git a/packages/tui/src/status/task/definition.ts b/pkgs-ts/console/src/status/task/definition.ts similarity index 86% rename from packages/tui/src/status/task/definition.ts rename to pkgs-ts/console/src/status/task/definition.ts index 367d1b25..dc3beb2e 100644 --- a/packages/tui/src/status/task/definition.ts +++ b/pkgs-ts/console/src/status/task/definition.ts @@ -1,6 +1,6 @@ -import { isTaskTitle, parseTaskCallback, parseTaskDefinition } from '#tui/status/task/validators/definition'; -import type { Logger } from '#tui/status/task/logger'; -import type { MaybePromise } from '#tui/types'; +import { isTaskTitle, parseTaskCallback, parseTaskDefinition } from '#console/status/task/validators/definition'; +import type { Logger } from '#console/status/task/logger'; +import type { MaybePromise } from '#console/types'; export type TaskDefinition = { keepSummary?: boolean; diff --git a/packages/tui/src/status/task/frame.ts b/pkgs-ts/console/src/status/task/frame.ts similarity index 81% rename from packages/tui/src/status/task/frame.ts rename to pkgs-ts/console/src/status/task/frame.ts index 8f6b3175..2fcaa259 100644 --- a/packages/tui/src/status/task/frame.ts +++ b/pkgs-ts/console/src/status/task/frame.ts @@ -1,5 +1,5 @@ -import { renderTaskFrame } from '#tui/status/task/render'; -import type { Logger } from '#tui/status/task/logger'; +import { renderTaskFrame } from '#console/status/task/render'; +import type { Logger } from '#console/status/task/logger'; export type LoggerTaskFrameOptions = { finished?: boolean; diff --git a/packages/tui/src/status/task/lifecycle.ts b/pkgs-ts/console/src/status/task/lifecycle.ts similarity index 64% rename from packages/tui/src/status/task/lifecycle.ts rename to pkgs-ts/console/src/status/task/lifecycle.ts index a641399c..a04d600f 100644 --- a/packages/tui/src/status/task/lifecycle.ts +++ b/pkgs-ts/console/src/status/task/lifecycle.ts @@ -1,11 +1,11 @@ -import { eraseRenderedFrame } from '#tui/status/frame'; -import { StatusSignalCleanup } from '#tui/status/signals'; -import { Logger } from '#tui/status/task/logger'; -import { captureTaskProcessOutput } from '#tui/status/task/process-output'; -import { createTaskLifecycleRenderer } from '#tui/status/task/lifecycle/rendering'; -import { hideCursor, showCursor } from '#tui/terminal'; -import type { ResolvedTaskDefinition } from '#tui/status/task/definition'; -import type { TaskLifecycleRenderer } from '#tui/status/task/lifecycle/rendering'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { StatusSignalCleanup } from '#console/status/signals'; +import { Logger } from '#console/status/task/logger'; +import { captureTaskProcessOutput } from '#console/status/task/process-output'; +import { createTaskLifecycleRenderer } from '#console/status/task/lifecycle/rendering'; +import { hideCursor, showCursor } from '#console/terminal'; +import type { ResolvedTaskDefinition } from '#console/status/task/definition'; +import type { TaskLifecycleRenderer } from '#console/status/task/lifecycle/rendering'; export const runTaskLifecycle = async (definition: ResolvedTaskDefinition): Promise => { let renderer: TaskLifecycleRenderer | null = null; diff --git a/packages/tui/src/status/task/lifecycle/rendering.ts b/pkgs-ts/console/src/status/task/lifecycle/rendering.ts similarity index 74% rename from packages/tui/src/status/task/lifecycle/rendering.ts rename to pkgs-ts/console/src/status/task/lifecycle/rendering.ts index 8903ed3e..b2af34df 100644 --- a/packages/tui/src/status/task/lifecycle/rendering.ts +++ b/pkgs-ts/console/src/status/task/lifecycle/rendering.ts @@ -1,7 +1,7 @@ -import { promptEnvironment } from '#tui/environment'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderLoggerTaskFrame } from '#tui/status/task/frame'; -import type { Logger } from '#tui/status/task/logger'; +import { promptEnvironment } from '#console/environment'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderLoggerTaskFrame } from '#console/status/task/frame'; +import type { Logger } from '#console/status/task/logger'; type TaskLifecycleRenderOptions = { finished?: boolean; diff --git a/pkgs-ts/console/src/status/task/logger.ts b/pkgs-ts/console/src/status/task/logger.ts new file mode 100644 index 00000000..ba09e791 --- /dev/null +++ b/pkgs-ts/console/src/status/task/logger.ts @@ -0,0 +1 @@ +export { Logger } from '#console/status/task/logger/logger'; diff --git a/packages/tui/src/status/task/logger/events.ts b/pkgs-ts/console/src/status/task/logger/events.ts similarity index 100% rename from packages/tui/src/status/task/logger/events.ts rename to pkgs-ts/console/src/status/task/logger/events.ts diff --git a/packages/tui/src/status/task/logger/labels.ts b/pkgs-ts/console/src/status/task/logger/labels.ts similarity index 100% rename from packages/tui/src/status/task/logger/labels.ts rename to pkgs-ts/console/src/status/task/logger/labels.ts diff --git a/packages/tui/src/status/task/logger/limits.ts b/pkgs-ts/console/src/status/task/logger/limits.ts similarity index 78% rename from packages/tui/src/status/task/logger/limits.ts rename to pkgs-ts/console/src/status/task/logger/limits.ts index be18f469..f6d7910f 100644 --- a/packages/tui/src/status/task/logger/limits.ts +++ b/pkgs-ts/console/src/status/task/logger/limits.ts @@ -1,4 +1,4 @@ -import { parseLogLimit } from '#tui/status/validators/limit'; +import { parseLogLimit } from '#console/status/validators/limit'; export type TaskLoggerLimits = { line: number; diff --git a/packages/tui/src/status/task/logger/lines.ts b/pkgs-ts/console/src/status/task/logger/lines.ts similarity index 84% rename from packages/tui/src/status/task/logger/lines.ts rename to pkgs-ts/console/src/status/task/logger/lines.ts index a00baa6d..b9af4535 100644 --- a/packages/tui/src/status/task/logger/lines.ts +++ b/pkgs-ts/console/src/status/task/logger/lines.ts @@ -1,6 +1,6 @@ -import { sanitizeTaskLine } from '#tui/status/task/sanitize'; -import { parseTaskLogMessageLines } from '#tui/status/task/logger/validators/message'; -import { parseLogLimit } from '#tui/status/validators/limit'; +import { sanitizeTaskLine } from '#console/status/task/sanitize'; +import { parseTaskLogMessageLines } from '#console/status/task/logger/validators/message'; +import { parseLogLimit } from '#console/status/validators/limit'; export type PartialTaskLogState = { startIndex: number | null; diff --git a/packages/tui/src/status/task/logger/logger.ts b/pkgs-ts/console/src/status/task/logger/logger.ts similarity index 72% rename from packages/tui/src/status/task/logger/logger.ts rename to pkgs-ts/console/src/status/task/logger/logger.ts index 7e79518a..52197fa5 100644 --- a/packages/tui/src/status/task/logger/logger.ts +++ b/pkgs-ts/console/src/status/task/logger/logger.ts @@ -1,14 +1,14 @@ -import { createTaskLoggerLimits } from '#tui/status/task/logger/limits'; -import { createTaskLoggerLabels } from '#tui/status/task/logger/labels'; -import { notifyTaskLoggerChanged } from '#tui/status/task/logger/events'; -import { syncTaskLoggerLabel, syncTaskLoggerSubLabel } from '#tui/status/task/logger/sync'; -import type { TaskLoggerChangeHandler } from '#tui/status/task/logger/events'; -import type { TaskLoggerLimits } from '#tui/status/task/logger/limits'; -import type { PartialTaskLogState } from '#tui/status/task/logger/lines'; -import type { TaskLoggerLabels } from '#tui/status/task/logger/labels'; -import type { StableTaskMessage } from '#tui/status/task/messages'; - -import { clearTaskLoggerPartial, writeStableTaskLoggerMessage, writeTaskLoggerLine, writeTaskLoggerPartial } from '#tui/status/task/logger/methods'; +import { createTaskLoggerLimits } from '#console/status/task/logger/limits'; +import { createTaskLoggerLabels } from '#console/status/task/logger/labels'; +import { notifyTaskLoggerChanged } from '#console/status/task/logger/events'; +import { syncTaskLoggerLabel, syncTaskLoggerSubLabel } from '#console/status/task/logger/sync'; +import type { TaskLoggerChangeHandler } from '#console/status/task/logger/events'; +import type { TaskLoggerLimits } from '#console/status/task/logger/limits'; +import type { PartialTaskLogState } from '#console/status/task/logger/lines'; +import type { TaskLoggerLabels } from '#console/status/task/logger/labels'; +import type { StableTaskMessage } from '#console/status/task/messages'; + +import { clearTaskLoggerPartial, writeStableTaskLoggerMessage, writeTaskLoggerLine, writeTaskLoggerPartial } from '#console/status/task/logger/methods'; export class Logger { labelValue: string; diff --git a/packages/tui/src/status/task/logger/methods.ts b/pkgs-ts/console/src/status/task/logger/methods.ts similarity index 66% rename from packages/tui/src/status/task/logger/methods.ts rename to pkgs-ts/console/src/status/task/logger/methods.ts index 992be70a..2fe87bf4 100644 --- a/packages/tui/src/status/task/logger/methods.ts +++ b/pkgs-ts/console/src/status/task/logger/methods.ts @@ -1,8 +1,8 @@ -import { appendPartialTaskLog, appendTaskLogLines } from '#tui/status/task/logger/lines'; -import { appendStableTaskLoggerOutput } from '#tui/status/task/logger/output'; -import type { TaskLoggerLimits } from '#tui/status/task/logger/limits'; -import type { PartialTaskLogState } from '#tui/status/task/logger/lines'; -import type { StableTaskMessage } from '#tui/status/task/messages'; +import { appendPartialTaskLog, appendTaskLogLines } from '#console/status/task/logger/lines'; +import { appendStableTaskLoggerOutput } from '#console/status/task/logger/output'; +import type { TaskLoggerLimits } from '#console/status/task/logger/limits'; +import type { PartialTaskLogState } from '#console/status/task/logger/lines'; +import type { StableTaskMessage } from '#console/status/task/messages'; export const writeTaskLoggerLine = (lines: string[], message: string, limit: number): void => { appendTaskLogLines(lines, message.trimEnd(), limit); diff --git a/packages/tui/src/status/task/logger/output.ts b/pkgs-ts/console/src/status/task/logger/output.ts similarity index 69% rename from packages/tui/src/status/task/logger/output.ts rename to pkgs-ts/console/src/status/task/logger/output.ts index 7cd7b71d..eca8a32c 100644 --- a/packages/tui/src/status/task/logger/output.ts +++ b/pkgs-ts/console/src/status/task/logger/output.ts @@ -1,5 +1,5 @@ -import { appendStableTaskMessage } from '#tui/status/task/logger/stable'; -import type { StableTaskMessage } from '#tui/status/task/messages'; +import { appendStableTaskMessage } from '#console/status/task/logger/stable'; +import type { StableTaskMessage } from '#console/status/task/messages'; export const resetTaskLoggerLines = (lines: string[]): void => { lines.splice(0); diff --git a/packages/tui/src/status/task/logger/stable.ts b/pkgs-ts/console/src/status/task/logger/stable.ts similarity index 68% rename from packages/tui/src/status/task/logger/stable.ts rename to pkgs-ts/console/src/status/task/logger/stable.ts index 2d7c53d2..3fe88326 100644 --- a/packages/tui/src/status/task/logger/stable.ts +++ b/pkgs-ts/console/src/status/task/logger/stable.ts @@ -1,5 +1,5 @@ -import { parseLogLimit } from '#tui/status/validators/limit'; -import type { StableTaskMessage } from '#tui/status/task/messages'; +import { parseLogLimit } from '#console/status/validators/limit'; +import type { StableTaskMessage } from '#console/status/task/messages'; export const appendStableTaskMessage = (messages: StableTaskMessage[], type: StableTaskMessage['type'], message: string, limit: number): void => { const stableLimit = parseLogLimit(limit, 10); diff --git a/packages/tui/src/status/task/logger/sync.ts b/pkgs-ts/console/src/status/task/logger/sync.ts similarity index 78% rename from packages/tui/src/status/task/logger/sync.ts rename to pkgs-ts/console/src/status/task/logger/sync.ts index 82596665..8bc997f2 100644 --- a/packages/tui/src/status/task/logger/sync.ts +++ b/pkgs-ts/console/src/status/task/logger/sync.ts @@ -1,5 +1,5 @@ -import { setTaskLoggerLabel, setTaskLoggerSubLabel } from '#tui/status/task/logger/labels'; -import type { TaskLoggerLabels } from '#tui/status/task/logger/labels'; +import { setTaskLoggerLabel, setTaskLoggerSubLabel } from '#console/status/task/logger/labels'; +import type { TaskLoggerLabels } from '#console/status/task/logger/labels'; export type TaskLoggerLabelSync = { labelValue: string; diff --git a/packages/tui/src/status/task/logger/validators/message.ts b/pkgs-ts/console/src/status/task/logger/validators/message.ts similarity index 100% rename from packages/tui/src/status/task/logger/validators/message.ts rename to pkgs-ts/console/src/status/task/logger/validators/message.ts diff --git a/packages/tui/src/status/task/messages.ts b/pkgs-ts/console/src/status/task/messages.ts similarity index 100% rename from packages/tui/src/status/task/messages.ts rename to pkgs-ts/console/src/status/task/messages.ts diff --git a/packages/tui/src/status/task/process-output.ts b/pkgs-ts/console/src/status/task/process-output.ts similarity index 74% rename from packages/tui/src/status/task/process-output.ts rename to pkgs-ts/console/src/status/task/process-output.ts index c37efb38..c7e1dfd2 100644 --- a/packages/tui/src/status/task/process-output.ts +++ b/pkgs-ts/console/src/status/task/process-output.ts @@ -1,7 +1,7 @@ -import { ProcessOutputBuffer } from '#tui/status/task/process-output/buffer'; -import { parseProcessOutputWrite, parseWritableProcessStream } from '#tui/status/task/process-output/validators/writer'; -import { processOutputWriter } from '#tui/status/task/process-output/writer'; -import type { Logger } from '#tui/status/task/logger'; +import { ProcessOutputBuffer } from '#console/status/task/process-output/buffer'; +import { parseProcessOutputWrite, parseWritableProcessStream } from '#console/status/task/process-output/validators/writer'; +import { processOutputWriter } from '#console/status/task/process-output/writer'; +import type { Logger } from '#console/status/task/logger'; type TaskProcessOutputCapture = { stop(): void; diff --git a/packages/tui/src/status/task/process-output/buffer.ts b/pkgs-ts/console/src/status/task/process-output/buffer.ts similarity index 76% rename from packages/tui/src/status/task/process-output/buffer.ts rename to pkgs-ts/console/src/status/task/process-output/buffer.ts index 9bef4ae7..de32d1c1 100644 --- a/packages/tui/src/status/task/process-output/buffer.ts +++ b/pkgs-ts/console/src/status/task/process-output/buffer.ts @@ -1,5 +1,5 @@ -import type { Logger } from '#tui/status/task/logger'; -import { parseProcessOutputChunkLines } from '#tui/status/task/process-output/validators/chunk'; +import type { Logger } from '#console/status/task/logger'; +import { parseProcessOutputChunkLines } from '#console/status/task/process-output/validators/chunk'; export class ProcessOutputBuffer { #pending = ''; diff --git a/packages/tui/src/status/task/process-output/validators/chunk.ts b/pkgs-ts/console/src/status/task/process-output/validators/chunk.ts similarity index 100% rename from packages/tui/src/status/task/process-output/validators/chunk.ts rename to pkgs-ts/console/src/status/task/process-output/validators/chunk.ts diff --git a/pkgs-ts/console/src/status/task/process-output/validators/writer.ts b/pkgs-ts/console/src/status/task/process-output/validators/writer.ts new file mode 100644 index 00000000..22e0f32d --- /dev/null +++ b/pkgs-ts/console/src/status/task/process-output/validators/writer.ts @@ -0,0 +1,6 @@ +export { parseProcessOutputCallback, parseProcessOutputEncoding } from '#console/status/task/process-output/validators/writer/callback'; +export type { ProcessOutputCallback } from '#console/status/task/process-output/validators/writer/callback'; +export { parseProcessOutputChunk, resolveProcessOutputWrite } from '#console/status/task/process-output/validators/writer/chunk'; +export type { ResolvedProcessOutputWrite } from '#console/status/task/process-output/validators/writer/chunk'; +export { parseProcessOutputWrite, parseWritableProcessStream } from '#console/status/task/process-output/validators/writer/stream'; +export type { WritableProcessStream } from '#console/status/task/process-output/validators/writer/stream'; diff --git a/packages/tui/src/status/task/process-output/validators/writer/callback.ts b/pkgs-ts/console/src/status/task/process-output/validators/writer/callback.ts similarity index 93% rename from packages/tui/src/status/task/process-output/validators/writer/callback.ts rename to pkgs-ts/console/src/status/task/process-output/validators/writer/callback.ts index 70868109..b0b1aa49 100644 --- a/packages/tui/src/status/task/process-output/validators/writer/callback.ts +++ b/pkgs-ts/console/src/status/task/process-output/validators/writer/callback.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; +import { functionSchema } from '#console/validators/function'; export type ProcessOutputCallback = (error?: Error | null) => void; diff --git a/packages/tui/src/status/task/process-output/validators/writer/chunk.ts b/pkgs-ts/console/src/status/task/process-output/validators/writer/chunk.ts similarity index 83% rename from packages/tui/src/status/task/process-output/validators/writer/chunk.ts rename to pkgs-ts/console/src/status/task/process-output/validators/writer/chunk.ts index 5881ec3f..8aff4670 100644 --- a/packages/tui/src/status/task/process-output/validators/writer/chunk.ts +++ b/pkgs-ts/console/src/status/task/process-output/validators/writer/chunk.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { parseProcessOutputCallback, parseProcessOutputEncoding } from '#tui/status/task/process-output/validators/writer/callback'; -import type { ProcessOutputCallback } from '#tui/status/task/process-output/validators/writer/callback'; +import { parseProcessOutputCallback, parseProcessOutputEncoding } from '#console/status/task/process-output/validators/writer/callback'; +import type { ProcessOutputCallback } from '#console/status/task/process-output/validators/writer/callback'; export type ResolvedProcessOutputWrite = { callback?: ProcessOutputCallback; diff --git a/packages/tui/src/status/task/process-output/validators/writer/stream.ts b/pkgs-ts/console/src/status/task/process-output/validators/writer/stream.ts similarity index 93% rename from packages/tui/src/status/task/process-output/validators/writer/stream.ts rename to pkgs-ts/console/src/status/task/process-output/validators/writer/stream.ts index 9ddef67d..bcaed463 100644 --- a/packages/tui/src/status/task/process-output/validators/writer/stream.ts +++ b/pkgs-ts/console/src/status/task/process-output/validators/writer/stream.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; +import { functionSchema } from '#console/validators/function'; export type WritableProcessStream = { write: NodeJS.WriteStream['write']; diff --git a/packages/tui/src/status/task/process-output/writer.ts b/pkgs-ts/console/src/status/task/process-output/writer.ts similarity index 71% rename from packages/tui/src/status/task/process-output/writer.ts rename to pkgs-ts/console/src/status/task/process-output/writer.ts index af13ecd8..a8af51ac 100644 --- a/packages/tui/src/status/task/process-output/writer.ts +++ b/pkgs-ts/console/src/status/task/process-output/writer.ts @@ -1,5 +1,5 @@ -import { resolveProcessOutputWrite } from '#tui/status/task/process-output/validators/writer'; -import type { ProcessOutputBuffer } from '#tui/status/task/process-output/buffer'; +import { resolveProcessOutputWrite } from '#console/status/task/process-output/validators/writer'; +import type { ProcessOutputBuffer } from '#console/status/task/process-output/buffer'; export const processOutputWriter = (buffer: ProcessOutputBuffer) => { return (chunk: string | Uint8Array, encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean => { diff --git a/packages/tui/src/status/task/render.ts b/pkgs-ts/console/src/status/task/render.ts similarity index 87% rename from packages/tui/src/status/task/render.ts rename to pkgs-ts/console/src/status/task/render.ts index 9cbc33c4..8641d9dd 100644 --- a/packages/tui/src/status/task/render.ts +++ b/pkgs-ts/console/src/status/task/render.ts @@ -1,6 +1,6 @@ -import { renderSpinnerFrame } from '#tui/status/spinner/render'; -import { parseLogLimit } from '#tui/status/validators/limit'; -import type { StableTaskMessage } from '#tui/status/task/messages'; +import { renderSpinnerFrame } from '#console/status/spinner/render'; +import { parseLogLimit } from '#console/status/validators/limit'; +import type { StableTaskMessage } from '#console/status/task/messages'; const TASK_DIVIDER_WIDTH = 60; diff --git a/packages/tui/src/status/task/sanitize.ts b/pkgs-ts/console/src/status/task/sanitize.ts similarity index 100% rename from packages/tui/src/status/task/sanitize.ts rename to pkgs-ts/console/src/status/task/sanitize.ts diff --git a/packages/tui/src/status/task/validators/definition.ts b/pkgs-ts/console/src/status/task/validators/definition.ts similarity index 84% rename from packages/tui/src/status/task/validators/definition.ts rename to pkgs-ts/console/src/status/task/validators/definition.ts index c3ff78e6..812e14bf 100644 --- a/packages/tui/src/status/task/validators/definition.ts +++ b/pkgs-ts/console/src/status/task/validators/definition.ts @@ -1,8 +1,8 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; -import type { TaskDefinition } from '#tui/status/task/definition'; -import type { Logger } from '#tui/status/task/logger'; -import type { MaybePromise } from '#tui/types'; +import { functionSchema } from '#console/validators/function'; +import type { TaskDefinition } from '#console/status/task/definition'; +import type { Logger } from '#console/status/task/logger'; +import type { MaybePromise } from '#console/types'; const taskCallbackSchema = (): z.ZodType<(logger: Logger) => MaybePromise> => functionSchema<(logger: Logger) => MaybePromise>(); diff --git a/packages/tui/src/status/validators/limit.ts b/pkgs-ts/console/src/status/validators/limit.ts similarity index 100% rename from packages/tui/src/status/validators/limit.ts rename to pkgs-ts/console/src/status/validators/limit.ts diff --git a/packages/tui/src/status/validators/progress.ts b/pkgs-ts/console/src/status/validators/progress.ts similarity index 95% rename from packages/tui/src/status/validators/progress.ts rename to pkgs-ts/console/src/status/validators/progress.ts index 875e9c82..1532f427 100644 --- a/packages/tui/src/status/validators/progress.ts +++ b/pkgs-ts/console/src/status/validators/progress.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { iterableSchema } from '#tui/validators/iterable'; +import { iterableSchema } from '#console/validators/iterable'; const progressNumberSchema = z.number().finite(); const progressTotalInputSchema = z.union([z.number(), z.literal(Number.POSITIVE_INFINITY), z.literal(Number.NEGATIVE_INFINITY)]); diff --git a/packages/tui/src/status/validators/signal-target.ts b/pkgs-ts/console/src/status/validators/signal-target.ts similarity index 91% rename from packages/tui/src/status/validators/signal-target.ts rename to pkgs-ts/console/src/status/validators/signal-target.ts index 781229e9..b0992402 100644 --- a/packages/tui/src/status/validators/signal-target.ts +++ b/pkgs-ts/console/src/status/validators/signal-target.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; +import { functionSchema } from '#console/validators/function'; export type StatusSignalTarget = { off(signal: string, listener: () => void): unknown; diff --git a/pkgs-ts/console/src/string-utils/ansi.ts b/pkgs-ts/console/src/string-utils/ansi.ts new file mode 100644 index 00000000..68d6b612 --- /dev/null +++ b/pkgs-ts/console/src/string-utils/ansi.ts @@ -0,0 +1,7 @@ +import stripAnsi from 'strip-ansi'; + +export { ansiCloseSequence, ESC } from '#console/string-utils/ansi/codes'; +export { parseAnsiSegments } from '#console/string-utils/ansi/segments'; +export type { AnsiSegment } from '#console/string-utils/ansi/segments'; + +export const parseAnsiText = (value: string): string => stripAnsi(value); diff --git a/packages/tui/src/string-utils/ansi/codes.ts b/pkgs-ts/console/src/string-utils/ansi/codes.ts similarity index 100% rename from packages/tui/src/string-utils/ansi/codes.ts rename to pkgs-ts/console/src/string-utils/ansi/codes.ts diff --git a/packages/tui/src/string-utils/ansi/segments.ts b/pkgs-ts/console/src/string-utils/ansi/segments.ts similarity index 98% rename from packages/tui/src/string-utils/ansi/segments.ts rename to pkgs-ts/console/src/string-utils/ansi/segments.ts index ab7ef3e6..5ae7faf0 100644 --- a/packages/tui/src/string-utils/ansi/segments.ts +++ b/pkgs-ts/console/src/string-utils/ansi/segments.ts @@ -1,4 +1,4 @@ -import { ansiCode, ansiCodeParts, ESC, isAnsiResetCode, isAnsiStyleSequence } from '#tui/string-utils/ansi/codes'; +import { ansiCode, ansiCodeParts, ESC, isAnsiResetCode, isAnsiStyleSequence } from '#console/string-utils/ansi/codes'; export type AnsiSegment = { codes: string; diff --git a/packages/tui/src/string-utils/truncate.ts b/pkgs-ts/console/src/string-utils/truncate.ts similarity index 85% rename from packages/tui/src/string-utils/truncate.ts rename to pkgs-ts/console/src/string-utils/truncate.ts index 82b4c475..54336027 100644 --- a/packages/tui/src/string-utils/truncate.ts +++ b/pkgs-ts/console/src/string-utils/truncate.ts @@ -1,6 +1,6 @@ -import { ansiCloseSequence, parseAnsiSegments } from '#tui/string-utils/ansi'; -import { parseStringWidth } from '#tui/string-utils/validators/width'; -import { visibleWidth } from '#tui/string-utils/width'; +import { ansiCloseSequence, parseAnsiSegments } from '#console/string-utils/ansi'; +import { parseStringWidth } from '#console/string-utils/validators/width'; +import { visibleWidth } from '#console/string-utils/width'; export const truncate = (value: string, width: number, marker = '...'): string => { const parsedWidth = parseStringWidth(width); diff --git a/packages/tui/src/string-utils/validators/width.ts b/pkgs-ts/console/src/string-utils/validators/width.ts similarity index 100% rename from packages/tui/src/string-utils/validators/width.ts rename to pkgs-ts/console/src/string-utils/validators/width.ts diff --git a/packages/tui/src/string-utils/width.ts b/pkgs-ts/console/src/string-utils/width.ts similarity index 100% rename from packages/tui/src/string-utils/width.ts rename to pkgs-ts/console/src/string-utils/width.ts diff --git a/packages/tui/src/string-utils/wrap.ts b/pkgs-ts/console/src/string-utils/wrap.ts similarity index 57% rename from packages/tui/src/string-utils/wrap.ts rename to pkgs-ts/console/src/string-utils/wrap.ts index ceaef25f..dcc3755d 100644 --- a/packages/tui/src/string-utils/wrap.ts +++ b/pkgs-ts/console/src/string-utils/wrap.ts @@ -1,6 +1,6 @@ import stripAnsi from 'strip-ansi'; -import { restoreAnsiWrappedLines } from '#tui/string-utils/wrap/ansi'; -import { plainWrap } from '#tui/string-utils/wrap/plain'; +import { restoreAnsiWrappedLines } from '#console/string-utils/wrap/ansi'; +import { plainWrap } from '#console/string-utils/wrap/plain'; export const wrap = (value: string, width: number): string[] => { return restoreAnsiWrappedLines(value, plainWrap(stripAnsi(value), width)); diff --git a/packages/tui/src/string-utils/wrap/ansi.ts b/pkgs-ts/console/src/string-utils/wrap/ansi.ts similarity index 89% rename from packages/tui/src/string-utils/wrap/ansi.ts rename to pkgs-ts/console/src/string-utils/wrap/ansi.ts index 1283703a..2437c368 100644 --- a/packages/tui/src/string-utils/wrap/ansi.ts +++ b/pkgs-ts/console/src/string-utils/wrap/ansi.ts @@ -1,5 +1,5 @@ -import { ansiCloseSequence, parseAnsiSegments } from '#tui/string-utils/ansi'; -import type { AnsiSegment } from '#tui/string-utils/ansi'; +import { ansiCloseSequence, parseAnsiSegments } from '#console/string-utils/ansi'; +import type { AnsiSegment } from '#console/string-utils/ansi'; const codedCharacters = (value: string): AnsiSegment[] => parseAnsiSegments(value).flatMap((segment) => [...segment.text].map((text) => ({ text, codes: segment.codes }))); diff --git a/packages/tui/src/string-utils/wrap/plain.ts b/pkgs-ts/console/src/string-utils/wrap/plain.ts similarity index 91% rename from packages/tui/src/string-utils/wrap/plain.ts rename to pkgs-ts/console/src/string-utils/wrap/plain.ts index 6fbea989..08577c12 100644 --- a/packages/tui/src/string-utils/wrap/plain.ts +++ b/pkgs-ts/console/src/string-utils/wrap/plain.ts @@ -1,5 +1,5 @@ -import { parseStringWidth } from '#tui/string-utils/validators/width'; -import { visibleWidth } from '#tui/string-utils/width'; +import { parseStringWidth } from '#console/string-utils/validators/width'; +import { visibleWidth } from '#console/string-utils/width'; const wrappedWideWord = (word: string, width: number): string[] => { const chunks: string[] = []; diff --git a/pkgs-ts/console/src/strings.ts b/pkgs-ts/console/src/strings.ts new file mode 100644 index 00000000..930bd9cf --- /dev/null +++ b/pkgs-ts/console/src/strings.ts @@ -0,0 +1,5 @@ +export { parseAnsiSegments, parseAnsiText } from '#console/string-utils/ansi'; +export type { AnsiSegment } from '#console/string-utils/ansi'; +export { truncate } from '#console/string-utils/truncate'; +export { visibleWidth } from '#console/string-utils/width'; +export { wrap } from '#console/string-utils/wrap'; diff --git a/packages/tui/src/terminal.ts b/pkgs-ts/console/src/terminal.ts similarity index 83% rename from packages/tui/src/terminal.ts rename to pkgs-ts/console/src/terminal.ts index 518bbcd2..d67a9181 100644 --- a/packages/tui/src/terminal.ts +++ b/pkgs-ts/console/src/terminal.ts @@ -1,8 +1,8 @@ -import { promptEnvironment } from '#tui/environment'; -import { defaultBackgroundColor, defaultForegroundColor, parseTerminalColor, terminalSupportsTrueColor } from '#tui/terminal/capabilities'; -import type { TerminalColor } from '#tui/terminal/capabilities'; -import { parseTerminalDimension, parseTerminalLineCount } from '#tui/terminal/validators/size'; -import { parseTerminalTitle } from '#tui/terminal/validators/title'; +import { promptEnvironment } from '#console/environment'; +import { defaultBackgroundColor, defaultForegroundColor, parseTerminalColor, terminalSupportsTrueColor } from '#console/terminal/capabilities'; +import type { TerminalColor } from '#console/terminal/capabilities'; +import { parseTerminalDimension, parseTerminalLineCount } from '#console/terminal/validators/size'; +import { parseTerminalTitle } from '#console/terminal/validators/title'; export type TerminalSize = { columns: number; diff --git a/packages/tui/src/terminal/capabilities.ts b/pkgs-ts/console/src/terminal/capabilities.ts similarity index 86% rename from packages/tui/src/terminal/capabilities.ts rename to pkgs-ts/console/src/terminal/capabilities.ts index 959a2691..82746513 100644 --- a/packages/tui/src/terminal/capabilities.ts +++ b/pkgs-ts/console/src/terminal/capabilities.ts @@ -1,4 +1,4 @@ -import { parseTerminalColor } from '#tui/terminal/validators/color'; +import { parseTerminalColor } from '#console/terminal/validators/color'; export type TerminalColor = readonly [number, number, number]; diff --git a/packages/tui/src/terminal/validators/color.ts b/pkgs-ts/console/src/terminal/validators/color.ts similarity index 84% rename from packages/tui/src/terminal/validators/color.ts rename to pkgs-ts/console/src/terminal/validators/color.ts index 9434d344..df433c12 100644 --- a/packages/tui/src/terminal/validators/color.ts +++ b/pkgs-ts/console/src/terminal/validators/color.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { TerminalColor } from '#tui/terminal/capabilities'; +import type { TerminalColor } from '#console/terminal/capabilities'; const terminalColorSchema = z.tuple([z.number().int().min(0).max(255), z.number().int().min(0).max(255), z.number().int().min(0).max(255)]); diff --git a/packages/tui/src/terminal/validators/size.ts b/pkgs-ts/console/src/terminal/validators/size.ts similarity index 100% rename from packages/tui/src/terminal/validators/size.ts rename to pkgs-ts/console/src/terminal/validators/size.ts diff --git a/packages/tui/src/terminal/validators/title.ts b/pkgs-ts/console/src/terminal/validators/title.ts similarity index 100% rename from packages/tui/src/terminal/validators/title.ts rename to pkgs-ts/console/src/terminal/validators/title.ts diff --git a/pkgs-ts/console/src/theme.ts b/pkgs-ts/console/src/theme.ts new file mode 100644 index 00000000..64d5273a --- /dev/null +++ b/pkgs-ts/console/src/theme.ts @@ -0,0 +1,5 @@ +export { renderChoices } from '#console/theme/choices'; +export { renderError } from '#console/theme/error'; +export { renderQuestion } from '#console/theme/question'; +export { symbols } from '#console/theme/symbols'; +export { renderTable } from '#console/theme/table'; diff --git a/packages/tui/src/theme/box.ts b/pkgs-ts/console/src/theme/box.ts similarity index 89% rename from packages/tui/src/theme/box.ts rename to pkgs-ts/console/src/theme/box.ts index 1f236fde..1c1ed04a 100644 --- a/packages/tui/src/theme/box.ts +++ b/pkgs-ts/console/src/theme/box.ts @@ -1,6 +1,6 @@ -import { truncate, visibleWidth } from '#tui/strings'; -import { terminalSize } from '#tui/terminal'; -import { parseBoxWidth } from '#tui/theme/validators/box'; +import { truncate, visibleWidth } from '#console/strings'; +import { terminalSize } from '#console/terminal'; +import { parseBoxWidth } from '#console/theme/validators/box'; const DEFAULT_BOX_WIDTH = 60; const TERMINAL_PADDING = 6; diff --git a/packages/tui/src/theme/choice-disabled.ts b/pkgs-ts/console/src/theme/choice-disabled.ts similarity index 71% rename from packages/tui/src/theme/choice-disabled.ts rename to pkgs-ts/console/src/theme/choice-disabled.ts index b0a4ecc9..ca335913 100644 --- a/packages/tui/src/theme/choice-disabled.ts +++ b/pkgs-ts/console/src/theme/choice-disabled.ts @@ -1,4 +1,4 @@ -import { parseDisabledReason } from '#tui/theme/validators/disabled'; +import { parseDisabledReason } from '#console/theme/validators/disabled'; export const choiceDisabledSuffix = (disabled: boolean | string | undefined): string => { if (!disabled) { diff --git a/packages/tui/src/theme/choices.ts b/pkgs-ts/console/src/theme/choices.ts similarity index 73% rename from packages/tui/src/theme/choices.ts rename to pkgs-ts/console/src/theme/choices.ts index 4855e95e..60649439 100644 --- a/packages/tui/src/theme/choices.ts +++ b/pkgs-ts/console/src/theme/choices.ts @@ -1,5 +1,5 @@ -import { choiceDisabledSuffix } from '#tui/theme/choice-disabled'; -import type { Choice } from '#tui/types'; +import { choiceDisabledSuffix } from '#console/theme/choice-disabled'; +import type { Choice } from '#console/types'; export const renderChoices = (choices: Array>): string => { return choices diff --git a/packages/tui/src/theme/error.ts b/pkgs-ts/console/src/theme/error.ts similarity index 51% rename from packages/tui/src/theme/error.ts rename to pkgs-ts/console/src/theme/error.ts index 10b1830e..13536400 100644 --- a/packages/tui/src/theme/error.ts +++ b/pkgs-ts/console/src/theme/error.ts @@ -1,4 +1,4 @@ -import { red } from '#tui/theme/styles'; -import { symbols } from '#tui/theme/symbols'; +import { red } from '#console/theme/styles'; +import { symbols } from '#console/theme/symbols'; export const renderError = (message: string): string => `${red(`${symbols.error} ${message}`)}\n`; diff --git a/packages/tui/src/theme/question.ts b/pkgs-ts/console/src/theme/question.ts similarity index 77% rename from packages/tui/src/theme/question.ts rename to pkgs-ts/console/src/theme/question.ts index e3b96482..4b277bce 100644 --- a/packages/tui/src/theme/question.ts +++ b/pkgs-ts/console/src/theme/question.ts @@ -1,4 +1,4 @@ -import { symbols } from '#tui/theme/symbols'; +import { symbols } from '#console/theme/symbols'; export const renderQuestion = (message: string, hint?: string): string => { const suffix = hint ? ` ${hint}` : ''; diff --git a/packages/tui/src/theme/styles.ts b/pkgs-ts/console/src/theme/styles.ts similarity index 100% rename from packages/tui/src/theme/styles.ts rename to pkgs-ts/console/src/theme/styles.ts diff --git a/packages/tui/src/theme/symbols.ts b/pkgs-ts/console/src/theme/symbols.ts similarity index 100% rename from packages/tui/src/theme/symbols.ts rename to pkgs-ts/console/src/theme/symbols.ts diff --git a/packages/tui/src/theme/table.ts b/pkgs-ts/console/src/theme/table.ts similarity index 88% rename from packages/tui/src/theme/table.ts rename to pkgs-ts/console/src/theme/table.ts index 0239ee68..79d0f13f 100644 --- a/packages/tui/src/theme/table.ts +++ b/pkgs-ts/console/src/theme/table.ts @@ -1,5 +1,5 @@ -import { visibleWidth } from '#tui/strings'; -import { isRenderableTableColumnCount } from '#tui/theme/validators/table'; +import { visibleWidth } from '#console/strings'; +import { isRenderableTableColumnCount } from '#console/theme/validators/table'; const padVisible = (value: string, width: number): string => `${value}${' '.repeat(Math.max(0, width - visibleWidth(value)))}`; diff --git a/packages/tui/src/theme/validators/box.ts b/pkgs-ts/console/src/theme/validators/box.ts similarity index 100% rename from packages/tui/src/theme/validators/box.ts rename to pkgs-ts/console/src/theme/validators/box.ts diff --git a/packages/tui/src/theme/validators/disabled.ts b/pkgs-ts/console/src/theme/validators/disabled.ts similarity index 100% rename from packages/tui/src/theme/validators/disabled.ts rename to pkgs-ts/console/src/theme/validators/disabled.ts diff --git a/packages/tui/src/theme/validators/table.ts b/pkgs-ts/console/src/theme/validators/table.ts similarity index 100% rename from packages/tui/src/theme/validators/table.ts rename to pkgs-ts/console/src/theme/validators/table.ts diff --git a/pkgs-ts/console/src/typed-value.ts b/pkgs-ts/console/src/typed-value.ts new file mode 100644 index 00000000..3ba35c7b --- /dev/null +++ b/pkgs-ts/console/src/typed-value.ts @@ -0,0 +1,4 @@ +export { applyTypedKey } from '#console/typed-value/edit'; +export { readTypedValue } from '#console/typed-value/read'; +export type { TypedValueReadResult } from '#console/typed-value/read'; +export type { TypedValueOptions, TypedValueState } from '#console/typed-value/types'; diff --git a/packages/tui/src/typed-value/characters.ts b/pkgs-ts/console/src/typed-value/characters.ts similarity index 100% rename from packages/tui/src/typed-value/characters.ts rename to pkgs-ts/console/src/typed-value/characters.ts diff --git a/packages/tui/src/typed-value/cursor.ts b/pkgs-ts/console/src/typed-value/cursor.ts similarity index 74% rename from packages/tui/src/typed-value/cursor.ts rename to pkgs-ts/console/src/typed-value/cursor.ts index 97534e28..0153e5cf 100644 --- a/packages/tui/src/typed-value/cursor.ts +++ b/pkgs-ts/console/src/typed-value/cursor.ts @@ -1,6 +1,6 @@ -import { characters, fromCharacters } from '#tui/typed-value/characters'; -import { dim, inverse } from '#tui/theme/styles'; -import { parseTypedValueCursor } from '#tui/typed-value/validators/cursor'; +import { characters, fromCharacters } from '#console/typed-value/characters'; +import { dim, inverse } from '#console/theme/styles'; +import { parseTypedValueCursor } from '#console/typed-value/validators/cursor'; export const valueWithCursor = (value: string, cursor: number): string => { const chars = characters(value); diff --git a/packages/tui/src/typed-value/delete.ts b/pkgs-ts/console/src/typed-value/delete.ts similarity index 85% rename from packages/tui/src/typed-value/delete.ts rename to pkgs-ts/console/src/typed-value/delete.ts index 580e5395..1de29d57 100644 --- a/packages/tui/src/typed-value/delete.ts +++ b/pkgs-ts/console/src/typed-value/delete.ts @@ -1,5 +1,5 @@ -import { fromCharacters, stringIndexToCharacterIndex } from '#tui/typed-value/characters'; -import { moveToLineBoundary } from '#tui/typed-value/lines'; +import { fromCharacters, stringIndexToCharacterIndex } from '#console/typed-value/characters'; +import { moveToLineBoundary } from '#console/typed-value/lines'; export const deleteNextCharacter = (value: string[], cursor: number): number => { value.splice(cursor, 1); diff --git a/packages/tui/src/typed-value/edit.ts b/pkgs-ts/console/src/typed-value/edit.ts similarity index 68% rename from packages/tui/src/typed-value/edit.ts rename to pkgs-ts/console/src/typed-value/edit.ts index 568f1814..7d06ef91 100644 --- a/packages/tui/src/typed-value/edit.ts +++ b/pkgs-ts/console/src/typed-value/edit.ts @@ -1,11 +1,11 @@ -import { Key } from '#tui/key'; -import { characterLength, characters } from '#tui/typed-value/characters'; -import { deleteTypedValueKey } from '#tui/typed-value/edit/deletion'; -import { insertPrintableKey } from '#tui/typed-value/edit/insertion'; -import { moveTypedValueCursor } from '#tui/typed-value/edit/navigation'; -import { typedKeyResult } from '#tui/typed-value/edit/result'; -import { parseTypedValueCursor } from '#tui/typed-value/validators/cursor'; -import type { AppliedTypedKey, TypedValueState } from '#tui/typed-value/types'; +import { Key } from '#console/key'; +import { characterLength, characters } from '#console/typed-value/characters'; +import { deleteTypedValueKey } from '#console/typed-value/edit/deletion'; +import { insertPrintableKey } from '#console/typed-value/edit/insertion'; +import { moveTypedValueCursor } from '#console/typed-value/edit/navigation'; +import { typedKeyResult } from '#console/typed-value/edit/result'; +import { parseTypedValueCursor } from '#console/typed-value/validators/cursor'; +import type { AppliedTypedKey, TypedValueState } from '#console/typed-value/types'; export const applyTypedKey = (state: TypedValueState, key: string, allowNewLine = false, wrapWidth?: number): AppliedTypedKey => { const value = characters(state.value); diff --git a/packages/tui/src/typed-value/edit/deletion.ts b/pkgs-ts/console/src/typed-value/edit/deletion.ts similarity index 84% rename from packages/tui/src/typed-value/edit/deletion.ts rename to pkgs-ts/console/src/typed-value/edit/deletion.ts index a61492f1..60a55724 100644 --- a/packages/tui/src/typed-value/edit/deletion.ts +++ b/pkgs-ts/console/src/typed-value/edit/deletion.ts @@ -1,5 +1,5 @@ -import { Key } from '#tui/key'; -import { deleteNextCharacter, deletePreviousCharacter, deletePreviousWord, deleteToLineStart } from '#tui/typed-value/delete'; +import { Key } from '#console/key'; +import { deleteNextCharacter, deletePreviousCharacter, deletePreviousWord, deleteToLineStart } from '#console/typed-value/delete'; export const deleteTypedValueKey = (value: string[], cursor: number, key: string, allowNewLine: boolean): number | undefined => { if (key === Key.delete) { diff --git a/packages/tui/src/typed-value/edit/insertion.ts b/pkgs-ts/console/src/typed-value/edit/insertion.ts similarity index 78% rename from packages/tui/src/typed-value/edit/insertion.ts rename to pkgs-ts/console/src/typed-value/edit/insertion.ts index 77df2631..25a3b513 100644 --- a/packages/tui/src/typed-value/edit/insertion.ts +++ b/pkgs-ts/console/src/typed-value/edit/insertion.ts @@ -1,4 +1,4 @@ -import { characters, isPrintable } from '#tui/typed-value/characters'; +import { characters, isPrintable } from '#console/typed-value/characters'; export const insertPrintableKey = (value: string[], cursor: number, key: string): number | undefined => { if (!isPrintable(key)) { diff --git a/packages/tui/src/typed-value/edit/navigation.ts b/pkgs-ts/console/src/typed-value/edit/navigation.ts similarity index 88% rename from packages/tui/src/typed-value/edit/navigation.ts rename to pkgs-ts/console/src/typed-value/edit/navigation.ts index 732f12ef..ab42df42 100644 --- a/packages/tui/src/typed-value/edit/navigation.ts +++ b/pkgs-ts/console/src/typed-value/edit/navigation.ts @@ -1,5 +1,5 @@ -import { Key, oneOf } from '#tui/key'; -import { moveLine, moveToLineBoundary } from '#tui/typed-value/lines'; +import { Key, oneOf } from '#console/key'; +import { moveLine, moveToLineBoundary } from '#console/typed-value/lines'; export const moveTypedValueCursor = (value: string[], cursor: number, key: string, allowNewLine: boolean, wrapWidth?: number): number | undefined => { if (key === Key.left || key === Key.leftArrow || key === Key.ctrlB) { diff --git a/packages/tui/src/typed-value/edit/result.ts b/pkgs-ts/console/src/typed-value/edit/result.ts similarity index 71% rename from packages/tui/src/typed-value/edit/result.ts rename to pkgs-ts/console/src/typed-value/edit/result.ts index 3e4b06b0..1b96130e 100644 --- a/packages/tui/src/typed-value/edit/result.ts +++ b/pkgs-ts/console/src/typed-value/edit/result.ts @@ -1,5 +1,5 @@ -import { fromCharacters } from '#tui/typed-value/characters'; -import type { AppliedTypedKey } from '#tui/typed-value/types'; +import { fromCharacters } from '#console/typed-value/characters'; +import type { AppliedTypedKey } from '#console/typed-value/types'; type TypedKeyResultOptions = { cancelled?: boolean; diff --git a/packages/tui/src/typed-value/line-ranges.ts b/pkgs-ts/console/src/typed-value/line-ranges.ts similarity index 92% rename from packages/tui/src/typed-value/line-ranges.ts rename to pkgs-ts/console/src/typed-value/line-ranges.ts index ad90ab47..af5786a5 100644 --- a/packages/tui/src/typed-value/line-ranges.ts +++ b/pkgs-ts/console/src/typed-value/line-ranges.ts @@ -1,5 +1,5 @@ -import { visibleWidth } from '#tui/strings'; -import { parseTypedValueWrapWidth } from '#tui/typed-value/validators/width'; +import { visibleWidth } from '#console/strings'; +import { parseTypedValueWrapWidth } from '#console/typed-value/validators/width'; export type LineRange = { end: number; diff --git a/packages/tui/src/typed-value/lines.ts b/pkgs-ts/console/src/typed-value/lines.ts similarity index 72% rename from packages/tui/src/typed-value/lines.ts rename to pkgs-ts/console/src/typed-value/lines.ts index 742c96a6..23e8682d 100644 --- a/packages/tui/src/typed-value/lines.ts +++ b/pkgs-ts/console/src/typed-value/lines.ts @@ -1,9 +1,9 @@ -import { currentLine, lineRanges } from '#tui/typed-value/line-ranges'; -import { visibleLineWindow } from '#tui/typed-value/lines/window'; +import { currentLine, lineRanges } from '#console/typed-value/line-ranges'; +import { visibleLineWindow } from '#console/typed-value/lines/window'; -export { visibleLineWindow } from '#tui/typed-value/lines/window'; -export { visibleTextWindow } from '#tui/typed-value/lines/text-window'; -export type { VisibleLineWindow, VisibleTextWindow } from '#tui/typed-value/lines/types'; +export { visibleLineWindow } from '#console/typed-value/lines/window'; +export { visibleTextWindow } from '#console/typed-value/lines/text-window'; +export type { VisibleLineWindow, VisibleTextWindow } from '#console/typed-value/lines/types'; export const visibleLines = (value: string, cursor: number, rows: number | undefined): string => { return visibleLineWindow(value, cursor, rows).lines.join('\n'); diff --git a/packages/tui/src/typed-value/lines/text-window.ts b/pkgs-ts/console/src/typed-value/lines/text-window.ts similarity index 77% rename from packages/tui/src/typed-value/lines/text-window.ts rename to pkgs-ts/console/src/typed-value/lines/text-window.ts index 94a7be53..80f05552 100644 --- a/packages/tui/src/typed-value/lines/text-window.ts +++ b/pkgs-ts/console/src/typed-value/lines/text-window.ts @@ -1,7 +1,7 @@ -import { lineRanges } from '#tui/typed-value/line-ranges'; -import { visibleLineWindow } from '#tui/typed-value/lines/window'; -import { parseTypedValueCursor } from '#tui/typed-value/validators/cursor'; -import type { VisibleTextWindow } from '#tui/typed-value/lines/types'; +import { lineRanges } from '#console/typed-value/line-ranges'; +import { visibleLineWindow } from '#console/typed-value/lines/window'; +import { parseTypedValueCursor } from '#console/typed-value/validators/cursor'; +import type { VisibleTextWindow } from '#console/typed-value/lines/types'; export const visibleTextWindow = (value: string, cursor: number, rows: number | undefined, width?: number): VisibleTextWindow => { const valueCharacters = [...value]; diff --git a/packages/tui/src/typed-value/lines/types.ts b/pkgs-ts/console/src/typed-value/lines/types.ts similarity index 100% rename from packages/tui/src/typed-value/lines/types.ts rename to pkgs-ts/console/src/typed-value/lines/types.ts diff --git a/packages/tui/src/typed-value/lines/window.ts b/pkgs-ts/console/src/typed-value/lines/window.ts similarity index 69% rename from packages/tui/src/typed-value/lines/window.ts rename to pkgs-ts/console/src/typed-value/lines/window.ts index 2c1726ad..d87737bf 100644 --- a/packages/tui/src/typed-value/lines/window.ts +++ b/pkgs-ts/console/src/typed-value/lines/window.ts @@ -1,8 +1,8 @@ -import { fromCharacters } from '#tui/typed-value/characters'; -import { currentLine, lineRanges } from '#tui/typed-value/line-ranges'; -import { parseTypedValueCursor } from '#tui/typed-value/validators/cursor'; -import { parseTypedValueRows } from '#tui/typed-value/validators/rows'; -import type { VisibleLineWindow } from '#tui/typed-value/lines/types'; +import { fromCharacters } from '#console/typed-value/characters'; +import { currentLine, lineRanges } from '#console/typed-value/line-ranges'; +import { parseTypedValueCursor } from '#console/typed-value/validators/cursor'; +import { parseTypedValueRows } from '#console/typed-value/validators/rows'; +import type { VisibleLineWindow } from '#console/typed-value/lines/types'; export const visibleLineWindow = (value: string, cursor: number, rows: number | undefined, width?: number): VisibleLineWindow => { const valueCharacters = [...value]; diff --git a/packages/tui/src/typed-value/read.ts b/pkgs-ts/console/src/typed-value/read.ts similarity index 66% rename from packages/tui/src/typed-value/read.ts rename to pkgs-ts/console/src/typed-value/read.ts index 363f1c75..4d852939 100644 --- a/packages/tui/src/typed-value/read.ts +++ b/pkgs-ts/console/src/typed-value/read.ts @@ -1,11 +1,11 @@ -import { promptEnvironment } from '#tui/environment'; -import { cancelTypedValueRead } from '#tui/typed-value/read/cancel'; -import { readTypedValueFallback } from '#tui/typed-value/read/fallback'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { applyTypedKey, initialTypedValueState } from '#tui/typed-value/edit'; -import { renderTypedValue } from '#tui/typed-value/render'; -import { TEXTAREA_CONTENT_WIDTH } from '#tui/typed-value/textarea'; -import type { TypedValueOptions, TypedValueState } from '#tui/typed-value/types'; +import { promptEnvironment } from '#console/environment'; +import { cancelTypedValueRead } from '#console/typed-value/read/cancel'; +import { readTypedValueFallback } from '#console/typed-value/read/fallback'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { applyTypedKey, initialTypedValueState } from '#console/typed-value/edit'; +import { renderTypedValue } from '#console/typed-value/render'; +import { TEXTAREA_CONTENT_WIDTH } from '#console/typed-value/textarea'; +import type { TypedValueOptions, TypedValueState } from '#console/typed-value/types'; export type TypedValueReadResult = { cancelled: boolean; diff --git a/packages/tui/src/typed-value/read/cancel.ts b/pkgs-ts/console/src/typed-value/read/cancel.ts similarity index 56% rename from packages/tui/src/typed-value/read/cancel.ts rename to pkgs-ts/console/src/typed-value/read/cancel.ts index 067d9cfe..03b45b2c 100644 --- a/packages/tui/src/typed-value/read/cancel.ts +++ b/pkgs-ts/console/src/typed-value/read/cancel.ts @@ -1,9 +1,9 @@ -import { cancelPrompt } from '#tui/prompt'; -import { eraseRenderedFrame } from '#tui/status/frame'; -import { renderCancelledTypedValue } from '#tui/typed-value/render'; -import { renderCancelledTextareaFrame } from '#tui/typed-value/textarea-frame'; -import type { TypedValueReadResult } from '#tui/typed-value/read'; -import type { TypedValueOptions } from '#tui/typed-value/types'; +import { cancelPrompt } from '#console/prompt'; +import { eraseRenderedFrame } from '#console/status/frame'; +import { renderCancelledTypedValue } from '#console/typed-value/render'; +import { renderCancelledTextareaFrame } from '#console/typed-value/textarea-frame'; +import type { TypedValueReadResult } from '#console/typed-value/read'; +import type { TypedValueOptions } from '#console/typed-value/types'; type CancelTypedValueReadOptions = { frame: string; diff --git a/packages/tui/src/typed-value/read/fallback.ts b/pkgs-ts/console/src/typed-value/read/fallback.ts similarity index 60% rename from packages/tui/src/typed-value/read/fallback.ts rename to pkgs-ts/console/src/typed-value/read/fallback.ts index b07679c6..6971ef31 100644 --- a/packages/tui/src/typed-value/read/fallback.ts +++ b/pkgs-ts/console/src/typed-value/read/fallback.ts @@ -1,8 +1,8 @@ -import { PromptValidationError } from '#tui/prompt'; -import { renderQuestion } from '#tui/theme'; -import type { PromptEnvironment } from '#tui/contracts/environment'; -import type { TypedValueReadResult } from '#tui/typed-value/read'; -import type { TypedValueOptions } from '#tui/typed-value/types'; +import { PromptValidationError } from '#console/prompt'; +import { renderQuestion } from '#console/theme'; +import type { PromptEnvironment } from '#console/contracts/environment'; +import type { TypedValueReadResult } from '#console/typed-value/read'; +import type { TypedValueOptions } from '#console/typed-value/types'; export const readTypedValueFallback = async (environment: PromptEnvironment, message: string, options: TypedValueOptions): Promise => { if (!environment.input.readLine) { diff --git a/packages/tui/src/typed-value/render.ts b/pkgs-ts/console/src/typed-value/render.ts similarity index 75% rename from packages/tui/src/typed-value/render.ts rename to pkgs-ts/console/src/typed-value/render.ts index ee1b9c68..28502bab 100644 --- a/packages/tui/src/typed-value/render.ts +++ b/pkgs-ts/console/src/typed-value/render.ts @@ -1,10 +1,10 @@ -import { promptEnvironment } from '#tui/environment'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red, strikethrough } from '#tui/theme/styles'; -import { valueWithCursor } from '#tui/typed-value/cursor'; -import { visibleTextWindow } from '#tui/typed-value/lines'; -import { renderTextareaFrame } from '#tui/typed-value/textarea-frame'; -import type { TypedValueOptions, TypedValueState } from '#tui/typed-value/types'; +import { promptEnvironment } from '#console/environment'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red, strikethrough } from '#console/theme/styles'; +import { valueWithCursor } from '#console/typed-value/cursor'; +import { visibleTextWindow } from '#console/typed-value/lines'; +import { renderTextareaFrame } from '#console/typed-value/textarea-frame'; +import type { TypedValueOptions, TypedValueState } from '#console/typed-value/types'; export const renderTypedValue = (message: string, state: TypedValueState, options: TypedValueOptions): string => { if (options.allowNewLine) { diff --git a/packages/tui/src/typed-value/textarea-frame.ts b/pkgs-ts/console/src/typed-value/textarea-frame.ts similarity index 77% rename from packages/tui/src/typed-value/textarea-frame.ts rename to pkgs-ts/console/src/typed-value/textarea-frame.ts index 9b4f063e..24cf3688 100644 --- a/packages/tui/src/typed-value/textarea-frame.ts +++ b/pkgs-ts/console/src/typed-value/textarea-frame.ts @@ -1,12 +1,12 @@ -import { renderScrollbarRows } from '#tui/concerns/scrollbar'; -import { promptEnvironment } from '#tui/environment'; -import { renderBox } from '#tui/theme/box'; -import { cyan, dim, red, strikethrough } from '#tui/theme/styles'; -import { valueWithCursor } from '#tui/typed-value/cursor'; -import { visibleTextWindow } from '#tui/typed-value/lines'; -import { TEXTAREA_CONTENT_WIDTH } from '#tui/typed-value/textarea'; -import { parseTypedValueRows } from '#tui/typed-value/validators/rows'; -import type { TypedValueOptions, TypedValueState } from '#tui/typed-value/types'; +import { renderScrollbarRows } from '#console/concerns/scrollbar'; +import { promptEnvironment } from '#console/environment'; +import { renderBox } from '#console/theme/box'; +import { cyan, dim, red, strikethrough } from '#console/theme/styles'; +import { valueWithCursor } from '#console/typed-value/cursor'; +import { visibleTextWindow } from '#console/typed-value/lines'; +import { TEXTAREA_CONTENT_WIDTH } from '#console/typed-value/textarea'; +import { parseTypedValueRows } from '#console/typed-value/validators/rows'; +import type { TypedValueOptions, TypedValueState } from '#console/typed-value/types'; export const renderTextareaFrame = (message: string, state: TypedValueState, options: TypedValueOptions): string => { return renderBox({ body: textareaBody(state, options), borderStyle: cyan, info: 'Ctrl+D to submit', title: cyan(message) }); diff --git a/packages/tui/src/typed-value/textarea.ts b/pkgs-ts/console/src/typed-value/textarea.ts similarity index 100% rename from packages/tui/src/typed-value/textarea.ts rename to pkgs-ts/console/src/typed-value/textarea.ts diff --git a/packages/tui/src/typed-value/types.ts b/pkgs-ts/console/src/typed-value/types.ts similarity index 100% rename from packages/tui/src/typed-value/types.ts rename to pkgs-ts/console/src/typed-value/types.ts diff --git a/packages/tui/src/typed-value/validators/cursor.ts b/pkgs-ts/console/src/typed-value/validators/cursor.ts similarity index 100% rename from packages/tui/src/typed-value/validators/cursor.ts rename to pkgs-ts/console/src/typed-value/validators/cursor.ts diff --git a/packages/tui/src/typed-value/validators/rows.ts b/pkgs-ts/console/src/typed-value/validators/rows.ts similarity index 100% rename from packages/tui/src/typed-value/validators/rows.ts rename to pkgs-ts/console/src/typed-value/validators/rows.ts diff --git a/packages/tui/src/typed-value/validators/width.ts b/pkgs-ts/console/src/typed-value/validators/width.ts similarity index 100% rename from packages/tui/src/typed-value/validators/width.ts rename to pkgs-ts/console/src/typed-value/validators/width.ts diff --git a/packages/tui/src/types.ts b/pkgs-ts/console/src/types.ts similarity index 56% rename from packages/tui/src/types.ts rename to pkgs-ts/console/src/types.ts index ce40ef0b..bbdc3c00 100644 --- a/packages/tui/src/types.ts +++ b/pkgs-ts/console/src/types.ts @@ -1,7 +1,7 @@ -export type { MaybePromise, PromptValue, ValidationResult, Validator } from '#tui/contracts/base'; -export type { PromptEnvironment, PromptInput, PromptOutput } from '#tui/contracts/environment'; -export type { BasePromptOptions } from '#tui/contracts/options'; -export type { Choice, ChoiceInput, ChoiceOptions, PromptInfo } from '#tui/contracts/choices'; +export type { MaybePromise, PromptValue, ValidationResult, Validator } from '#console/contracts/base'; +export type { PromptEnvironment, PromptInput, PromptOutput } from '#console/contracts/environment'; +export type { BasePromptOptions } from '#console/contracts/options'; +export type { Choice, ChoiceInput, ChoiceOptions, PromptInfo } from '#console/contracts/choices'; export type { ConfirmPromptOptions, MultiSearchPromptOptions, @@ -11,6 +11,6 @@ export type { SelectPromptOptions, TextareaPromptOptions, TextPromptOptions, -} from '#tui/contracts/prompts'; -export type { DataTableObjectRow, DataTablePromptOptions, DataTableRow, TableCell, TableOptions } from '#tui/contracts/output'; -export type { StatusOptions } from '#tui/contracts/status'; +} from '#console/contracts/prompts'; +export type { DataTableObjectRow, DataTablePromptOptions, DataTableRow, TableCell, TableOptions } from '#console/contracts/output'; +export type { StatusOptions } from '#console/contracts/status'; diff --git a/packages/tui/src/validators/default.ts b/pkgs-ts/console/src/validators/default.ts similarity index 100% rename from packages/tui/src/validators/default.ts rename to pkgs-ts/console/src/validators/default.ts diff --git a/packages/tui/src/validators/function.ts b/pkgs-ts/console/src/validators/function.ts similarity index 100% rename from packages/tui/src/validators/function.ts rename to pkgs-ts/console/src/validators/function.ts diff --git a/packages/tui/src/validators/iterable.ts b/pkgs-ts/console/src/validators/iterable.ts similarity index 93% rename from packages/tui/src/validators/iterable.ts rename to pkgs-ts/console/src/validators/iterable.ts index 99270705..b72f7969 100644 --- a/packages/tui/src/validators/iterable.ts +++ b/pkgs-ts/console/src/validators/iterable.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import { functionSchema } from '#tui/validators/function'; +import { functionSchema } from '#console/validators/function'; const iteratorMethodSchema = functionSchema<() => Iterator>(); const asyncIteratorMethodSchema = functionSchema<() => AsyncIterator>(); diff --git a/packages/tui/src/validators/required.ts b/pkgs-ts/console/src/validators/required.ts similarity index 100% rename from packages/tui/src/validators/required.ts rename to pkgs-ts/console/src/validators/required.ts diff --git a/packages/tui/src/validators/result.ts b/pkgs-ts/console/src/validators/result.ts similarity index 86% rename from packages/tui/src/validators/result.ts rename to pkgs-ts/console/src/validators/result.ts index 5fdd9ac9..e7cb7421 100644 --- a/packages/tui/src/validators/result.ts +++ b/pkgs-ts/console/src/validators/result.ts @@ -1,5 +1,5 @@ import { z } from 'zod'; -import type { ValidationResult } from '#tui/types'; +import type { ValidationResult } from '#console/types'; const validationResultSchema = z.union([z.string(), z.null(), z.undefined()]); diff --git a/packages/tui/tests/choices.test.ts b/pkgs-ts/console/tests/choices.test.ts similarity index 99% rename from packages/tui/tests/choices.test.ts rename to pkgs-ts/console/tests/choices.test.ts index f20c5b4c..d2d28abe 100644 --- a/packages/tui/tests/choices.test.ts +++ b/pkgs-ts/console/tests/choices.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { confirm, createMemoryOutput, createScriptedInput, Key, multiselect, parseAnsiText, PromptValidationError, select, withPromptEnvironment } from '#tui/index'; -import type { SelectPromptOptions } from '#tui/index'; +import { confirm, createMemoryOutput, createScriptedInput, Key, multiselect, parseAnsiText, PromptValidationError, select, withPromptEnvironment } from '#console/index'; +import type { SelectPromptOptions } from '#console/index'; describe('choice prompts', () => { it('confirms with direct y and n keys', async () => { diff --git a/packages/tui/tests/environment.test.ts b/pkgs-ts/console/tests/environment.test.ts similarity index 96% rename from packages/tui/tests/environment.test.ts rename to pkgs-ts/console/tests/environment.test.ts index 060aac5b..2678c0bd 100644 --- a/packages/tui/tests/environment.test.ts +++ b/pkgs-ts/console/tests/environment.test.ts @@ -1,8 +1,8 @@ import { describe, expect, it } from 'vitest'; import { EventEmitter } from 'node:events'; -import { configurePrompts, createMemoryOutput, createScriptedInput, promptEnvironment, withPromptEnvironment } from '#tui/environment'; -import { readRawKey } from '#tui/environment/raw-key'; -import { Key } from '#tui/key'; +import { configurePrompts, createMemoryOutput, createScriptedInput, promptEnvironment, withPromptEnvironment } from '#console/environment'; +import { readRawKey } from '#console/environment/raw-key'; +import { Key } from '#console/key'; class FakeRawInput extends EventEmitter { isRaw = false; diff --git a/packages/tui/tests/form.test.ts b/pkgs-ts/console/tests/form.test.ts similarity index 99% rename from packages/tui/tests/form.test.ts rename to pkgs-ts/console/tests/form.test.ts index a81db692..3528c93c 100644 --- a/packages/tui/tests/form.test.ts +++ b/pkgs-ts/console/tests/form.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { confirm, createMemoryOutput, createScriptedInput, form, Key, outro, Stream, text, withPromptEnvironment } from '#tui/index'; +import { confirm, createMemoryOutput, createScriptedInput, form, Key, outro, Stream, text, withPromptEnvironment } from '#console/index'; describe('form builder', () => { it('runs chained steps and returns positional responses', async () => { diff --git a/packages/tui/tests/key.test.ts b/pkgs-ts/console/tests/key.test.ts similarity index 96% rename from packages/tui/tests/key.test.ts rename to pkgs-ts/console/tests/key.test.ts index c8fbebd4..1e877d0d 100644 --- a/packages/tui/tests/key.test.ts +++ b/pkgs-ts/console/tests/key.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { Key, keyFromEvent, oneOf } from '#tui/index'; +import { Key, keyFromEvent, oneOf } from '#console/index'; describe('keyboard mapping', () => { it('maps named keys', () => { diff --git a/packages/tui/tests/notify.test.ts b/pkgs-ts/console/tests/notify.test.ts similarity index 97% rename from packages/tui/tests/notify.test.ts rename to pkgs-ts/console/tests/notify.test.ts index 77580184..f0b3fde0 100644 --- a/packages/tui/tests/notify.test.ts +++ b/pkgs-ts/console/tests/notify.test.ts @@ -1,6 +1,6 @@ import { describe, expect, expectTypeOf, it } from 'vitest'; -import { createMemoryOutput, notificationCommand, notificationCommands, notify, notifyForPlatform, withPromptEnvironment } from '#tui/index'; -import type { NotificationCommand } from '#tui/index'; +import { createMemoryOutput, notificationCommand, notificationCommands, notify, notifyForPlatform, withPromptEnvironment } from '#console/index'; +import type { NotificationCommand } from '#console/index'; describe('notify helper', () => { it('builds macOS notification commands', () => { diff --git a/packages/tui/tests/number.test.ts b/pkgs-ts/console/tests/number.test.ts similarity index 98% rename from packages/tui/tests/number.test.ts rename to pkgs-ts/console/tests/number.test.ts index 07006d32..5ff28ea7 100644 --- a/packages/tui/tests/number.test.ts +++ b/pkgs-ts/console/tests/number.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, createScriptedInput, Key, number, parseAnsiText, PromptValidationError, withPromptEnvironment } from '#tui/index'; -import { parseNumberInput } from '#tui/prompts/number/validators/value'; +import { createMemoryOutput, createScriptedInput, Key, number, parseAnsiText, PromptValidationError, withPromptEnvironment } from '#console/index'; +import { parseNumberInput } from '#console/prompts/number/validators/value'; describe('number prompt', () => { it('rejects partial decimal input and accepts a retry', async () => { diff --git a/packages/tui/tests/output.test.ts b/pkgs-ts/console/tests/output.test.ts similarity index 98% rename from packages/tui/tests/output.test.ts rename to pkgs-ts/console/tests/output.test.ts index 32d4c91e..5ddd6495 100644 --- a/packages/tui/tests/output.test.ts +++ b/pkgs-ts/console/tests/output.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { alert, createMemoryOutput, error, grid, info, intro, note, outro, parseAnsiText, table, warning, withPromptEnvironment } from '#tui/index'; -import { renderGrid } from '#tui/output/grid'; +import { alert, createMemoryOutput, error, grid, info, intro, note, outro, parseAnsiText, table, warning, withPromptEnvironment } from '#console/index'; +import { renderGrid } from '#console/output/grid'; describe('output helpers', () => { it('renders note-style helpers without returning a value', async () => { diff --git a/packages/tui/tests/password.test.ts b/pkgs-ts/console/tests/password.test.ts similarity index 98% rename from packages/tui/tests/password.test.ts rename to pkgs-ts/console/tests/password.test.ts index e668349e..710762f6 100644 --- a/packages/tui/tests/password.test.ts +++ b/pkgs-ts/console/tests/password.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, createScriptedInput, Key, password, PromptValidationError, withPromptEnvironment } from '#tui/index'; +import { createMemoryOutput, createScriptedInput, Key, password, PromptValidationError, withPromptEnvironment } from '#console/index'; describe('password prompt', () => { it('returns typed values without rendering the raw password', async () => { diff --git a/packages/tui/tests/pause.test.ts b/pkgs-ts/console/tests/pause.test.ts similarity index 97% rename from packages/tui/tests/pause.test.ts rename to pkgs-ts/console/tests/pause.test.ts index ed25ca1f..adfa33d3 100644 --- a/packages/tui/tests/pause.test.ts +++ b/pkgs-ts/console/tests/pause.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, createScriptedInput, Key, pause, withPromptEnvironment } from '#tui/index'; +import { createMemoryOutput, createScriptedInput, Key, pause, withPromptEnvironment } from '#console/index'; describe('pause prompt', () => { it('waits for enter from key-driven input', async () => { diff --git a/packages/tui/tests/progress.test.ts b/pkgs-ts/console/tests/progress.test.ts similarity index 99% rename from packages/tui/tests/progress.test.ts rename to pkgs-ts/console/tests/progress.test.ts index 1d115824..95169174 100644 --- a/packages/tui/tests/progress.test.ts +++ b/pkgs-ts/console/tests/progress.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; import { EventEmitter } from 'node:events'; -import { createMemoryOutput, Progress, progress, withPromptEnvironment } from '#tui/index'; +import { createMemoryOutput, Progress, progress, withPromptEnvironment } from '#console/index'; describe('progress helper', () => { it('maps iterable steps and returns callback results', async () => { diff --git a/packages/tui/tests/prompt.test.ts b/pkgs-ts/console/tests/prompt.test.ts similarity index 92% rename from packages/tui/tests/prompt.test.ts rename to pkgs-ts/console/tests/prompt.test.ts index f949ba1f..a88a9375 100644 --- a/packages/tui/tests/prompt.test.ts +++ b/pkgs-ts/console/tests/prompt.test.ts @@ -1,9 +1,9 @@ import { afterEach, describe, expect, it } from 'vitest'; -import { createMemoryOutput, withPromptEnvironment } from '#tui/environment'; -import { createScriptedInput } from '#tui/environment/scripted-input'; -import { Key } from '#tui/key'; -import { ask, cancelUsing, ensureRequired, promptUntilValid, PromptValidationError, validationMessage } from '#tui/prompt'; -import { text } from '#tui/prompts/basic'; +import { createMemoryOutput, withPromptEnvironment } from '#console/environment'; +import { createScriptedInput } from '#console/environment/scripted-input'; +import { Key } from '#console/key'; +import { ask, cancelUsing, ensureRequired, promptUntilValid, PromptValidationError, validationMessage } from '#console/prompt'; +import { text } from '#console/prompts/basic'; describe('prompt validation', () => { afterEach(() => { diff --git a/packages/tui/tests/search.test.ts b/pkgs-ts/console/tests/search.test.ts similarity index 99% rename from packages/tui/tests/search.test.ts rename to pkgs-ts/console/tests/search.test.ts index f30e7772..3564cbbe 100644 --- a/packages/tui/tests/search.test.ts +++ b/pkgs-ts/console/tests/search.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, createScriptedInput, Key, multisearch, parseAnsiText, PromptValidationError, search, withPromptEnvironment } from '#tui/index'; -import type { SearchPromptOptions } from '#tui/index'; +import { createMemoryOutput, createScriptedInput, Key, multisearch, parseAnsiText, PromptValidationError, search, withPromptEnvironment } from '#console/index'; +import type { SearchPromptOptions } from '#console/index'; const colors = (value: string): Record => { const options = { diff --git a/packages/tui/tests/spinner.test.ts b/pkgs-ts/console/tests/spinner.test.ts similarity index 96% rename from packages/tui/tests/spinner.test.ts rename to pkgs-ts/console/tests/spinner.test.ts index 42547afe..5cf0c0dd 100644 --- a/packages/tui/tests/spinner.test.ts +++ b/pkgs-ts/console/tests/spinner.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, spin, withPromptEnvironment } from '#tui/index'; -import { renderSpinnerFrame, spinnerFrame } from '#tui/status/spinner/render'; +import { createMemoryOutput, spin, withPromptEnvironment } from '#console/index'; +import { renderSpinnerFrame, spinnerFrame } from '#console/status/spinner/render'; describe('spinner helper', () => { it('runs callback-first spinner callbacks', async () => { diff --git a/packages/tui/tests/stream.test.ts b/pkgs-ts/console/tests/stream.test.ts similarity index 96% rename from packages/tui/tests/stream.test.ts rename to pkgs-ts/console/tests/stream.test.ts index 3c99f3c9..0823ada8 100644 --- a/packages/tui/tests/stream.test.ts +++ b/pkgs-ts/console/tests/stream.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, parseAnsiText, stream, withPromptEnvironment } from '#tui/index'; -import { streamFadeStyles } from '#tui/status/stream/fade'; -import { renderStreamFrame } from '#tui/status/stream/render'; +import { createMemoryOutput, parseAnsiText, stream, withPromptEnvironment } from '#console/index'; +import { streamFadeStyles } from '#console/status/stream/fade'; +import { renderStreamFrame } from '#console/status/stream/render'; describe('stream helper', () => { it('appends streamed content and returns the accumulated value', async () => { diff --git a/packages/tui/tests/strings.test.ts b/pkgs-ts/console/tests/strings.test.ts similarity index 98% rename from packages/tui/tests/strings.test.ts rename to pkgs-ts/console/tests/strings.test.ts index e7e6f3c2..04f54dac 100644 --- a/packages/tui/tests/strings.test.ts +++ b/pkgs-ts/console/tests/strings.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { parseAnsiSegments, parseAnsiText, truncate, visibleWidth, wrap } from '#tui/index'; +import { parseAnsiSegments, parseAnsiText, truncate, visibleWidth, wrap } from '#console/index'; describe('string utilities', () => { it('measures visible width without ANSI control sequences', () => { diff --git a/packages/tui/tests/suggest.test.ts b/pkgs-ts/console/tests/suggest.test.ts similarity index 99% rename from packages/tui/tests/suggest.test.ts rename to pkgs-ts/console/tests/suggest.test.ts index aeead0c1..c26888ea 100644 --- a/packages/tui/tests/suggest.test.ts +++ b/pkgs-ts/console/tests/suggest.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { autocomplete, createMemoryOutput, createScriptedInput, Key, parseAnsiText, suggest, withPromptEnvironment } from '#tui/index'; +import { autocomplete, createMemoryOutput, createScriptedInput, Key, parseAnsiText, suggest, withPromptEnvironment } from '#console/index'; const runSuggest = async (keys: string[], options: string[] | ((query: string) => string[])): Promise<{ output: string; result: string }> => { const output = createMemoryOutput(); diff --git a/packages/tui/tests/table.test.ts b/pkgs-ts/console/tests/table.test.ts similarity index 99% rename from packages/tui/tests/table.test.ts rename to pkgs-ts/console/tests/table.test.ts index ccc29b5e..9b4565df 100644 --- a/packages/tui/tests/table.test.ts +++ b/pkgs-ts/console/tests/table.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, createScriptedInput, datatable, form, Key, parseAnsiText, table, visibleWidth, withPromptEnvironment } from '#tui/index'; +import { createMemoryOutput, createScriptedInput, datatable, form, Key, parseAnsiText, table, visibleWidth, withPromptEnvironment } from '#console/index'; describe('table output', () => { it('renders static table rows', async () => { diff --git a/packages/tui/tests/task.test.ts b/pkgs-ts/console/tests/task.test.ts similarity index 98% rename from packages/tui/tests/task.test.ts rename to pkgs-ts/console/tests/task.test.ts index 0587a674..62c27a1b 100644 --- a/packages/tui/tests/task.test.ts +++ b/pkgs-ts/console/tests/task.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, task, withPromptEnvironment } from '#tui/index'; -import { eraseRenderedFrame, renderedFrameLineCount } from '#tui/status/frame'; -import { renderTaskFrame } from '#tui/status/task/render'; +import { createMemoryOutput, task, withPromptEnvironment } from '#console/index'; +import { eraseRenderedFrame, renderedFrameLineCount } from '#console/status/frame'; +import { renderTaskFrame } from '#console/status/task/render'; describe('task helper', () => { it('passes a bounded logger to the callback and returns the callback value', async () => { diff --git a/packages/tui/tests/terminal.test.ts b/pkgs-ts/console/tests/terminal.test.ts similarity index 98% rename from packages/tui/tests/terminal.test.ts rename to pkgs-ts/console/tests/terminal.test.ts index 072fedfe..0cfbea7b 100644 --- a/packages/tui/tests/terminal.test.ts +++ b/pkgs-ts/console/tests/terminal.test.ts @@ -15,7 +15,7 @@ import { supportsTrueColor, title, withPromptEnvironment, -} from '#tui/index'; +} from '#console/index'; describe('terminal helpers', () => { it('writes clear terminal control sequences', async () => { diff --git a/packages/tui/tests/text.test.ts b/pkgs-ts/console/tests/text.test.ts similarity index 99% rename from packages/tui/tests/text.test.ts rename to pkgs-ts/console/tests/text.test.ts index b64b2867..2a3c5e38 100644 --- a/packages/tui/tests/text.test.ts +++ b/pkgs-ts/console/tests/text.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, createScriptedInput, Key, parseAnsiText, PromptValidationError, text, withPromptEnvironment } from '#tui/index'; +import { createMemoryOutput, createScriptedInput, Key, parseAnsiText, PromptValidationError, text, withPromptEnvironment } from '#console/index'; describe('text prompt', () => { it('renders typed values while reading raw key input', async () => { diff --git a/packages/tui/tests/textarea.test.ts b/pkgs-ts/console/tests/textarea.test.ts similarity index 99% rename from packages/tui/tests/textarea.test.ts rename to pkgs-ts/console/tests/textarea.test.ts index 694ce9f2..36585451 100644 --- a/packages/tui/tests/textarea.test.ts +++ b/pkgs-ts/console/tests/textarea.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { createMemoryOutput, createScriptedInput, Key, parseAnsiText, PromptValidationError, textarea, withPromptEnvironment } from '#tui/index'; +import { createMemoryOutput, createScriptedInput, Key, parseAnsiText, PromptValidationError, textarea, withPromptEnvironment } from '#console/index'; describe('textarea prompt', () => { it('accepts multiline input and submits with ctrl-d', async () => { diff --git a/packages/tui/tests/typed-value.test.ts b/pkgs-ts/console/tests/typed-value.test.ts similarity index 97% rename from packages/tui/tests/typed-value.test.ts rename to pkgs-ts/console/tests/typed-value.test.ts index 98604562..b3b83804 100644 --- a/packages/tui/tests/typed-value.test.ts +++ b/pkgs-ts/console/tests/typed-value.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { applyTypedKey, Key } from '#tui/index'; -import { visibleLineWindow } from '#tui/typed-value/lines'; +import { applyTypedKey, Key } from '#console/index'; +import { visibleLineWindow } from '#console/typed-value/lines'; const apply = (keys: string[]): string => { let state = { cursor: 0, value: '' }; diff --git a/packages/tui/tsconfig.build.json b/pkgs-ts/console/tsconfig.build.json similarity index 80% rename from packages/tui/tsconfig.build.json rename to pkgs-ts/console/tsconfig.build.json index 6b2ea2a1..ba6939bf 100644 --- a/packages/tui/tsconfig.build.json +++ b/pkgs-ts/console/tsconfig.build.json @@ -8,7 +8,7 @@ "outDir": "dist", "rootDir": "src", "sourceMap": true, - "tsBuildInfoFile": "../../infra/.cache/tsbuild/tui-build.tsbuildinfo" + "tsBuildInfoFile": "../../infra/.cache/tsbuild/console-build.tsbuildinfo" }, "exclude": ["dist", "tests", "vitest.config.ts"], "include": ["src/**/*.ts"] diff --git a/pkgs-ts/console/tsconfig.json b/pkgs-ts/console/tsconfig.json new file mode 100644 index 00000000..adb2e61a --- /dev/null +++ b/pkgs-ts/console/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": ["@ollin/console-infra/tsconfig/base.json", "@ollin/console-infra/tsconfig/console.json"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "#console/*": ["./src/*"], + "#console/prompts/*": ["./src/prompts/*"] + } + }, + "include": ["src/**/*.ts", "vitest.config.ts"] +} diff --git a/packages/tui/vitest.config.ts b/pkgs-ts/console/vitest.config.ts similarity index 92% rename from packages/tui/vitest.config.ts rename to pkgs-ts/console/vitest.config.ts index ca1954b0..934154cd 100644 --- a/packages/tui/vitest.config.ts +++ b/pkgs-ts/console/vitest.config.ts @@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url'; const packagePath = dirname(fileURLToPath(import.meta.url)); const workspacePath = dirname(dirname(packagePath)); -const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'tui'); +const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'console'); const sourcePath = join(packagePath, 'src', '$1'); export default defineConfig({ @@ -12,7 +12,7 @@ export default defineConfig({ resolve: { alias: [ { - find: /^#tui\/(.+)$/u, + find: /^#console\/(.+)$/u, replacement: sourcePath, }, ], diff --git a/packages/acceptance/package.json b/pkgs-ts/tests/package.json similarity index 82% rename from packages/acceptance/package.json rename to pkgs-ts/tests/package.json index 03a49b7c..f2c16589 100644 --- a/packages/acceptance/package.json +++ b/pkgs-ts/tests/package.json @@ -1,5 +1,5 @@ { - "name": "@ollin/acceptance", + "name": "@ollin/pkgs-ts-tests", "version": "0.1.0", "private": true, "type": "module", @@ -8,11 +8,11 @@ "typecheck": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@ollin/tui": "workspace:*", + "@ollin/console": "workspace:*", "@opentui/core": "^0.4.0" }, "devDependencies": { - "@ollin/infra": "workspace:*", + "@ollin/console-infra": "workspace:*", "@types/node": "^25.6.2", "typescript": "^6.0.3", "vitest": "^4.1.5" diff --git a/packages/acceptance/tests/package.test.ts b/pkgs-ts/tests/tests/distribution/package.test.ts similarity index 91% rename from packages/acceptance/tests/package.test.ts rename to pkgs-ts/tests/tests/distribution/package.test.ts index c1948458..ff9943d4 100644 --- a/packages/acceptance/tests/package.test.ts +++ b/pkgs-ts/tests/tests/distribution/package.test.ts @@ -5,21 +5,21 @@ import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; const testPath = dirname(fileURLToPath(import.meta.url)); -const acceptancePath = dirname(testPath); +const acceptancePath = dirname(dirname(testPath)); const packagesPath = dirname(acceptancePath); const workspacePath = dirname(packagesPath); -const acceptanceCachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'acceptance'); +const acceptanceCachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'tests'); describe('package consumption', () => { it('imports the built public entrypoint through ESM package resolution', () => { - execFileSync('pnpm', ['--filter', '@ollin/tui', 'build'], { + execFileSync('pnpm', ['--filter', '@ollin/console', 'build'], { cwd: workspacePath, stdio: 'pipe', }); const output = execFileSync( process.execPath, - ['--input-type=module', '-e', "const module = await import('@ollin/tui'); console.log([typeof module.text, typeof module.table, typeof module.stream].join(','));"], + ['--input-type=module', '-e', "const module = await import('@ollin/console'); console.log([typeof module.text, typeof module.table, typeof module.stream].join(','));"], { cwd: acceptancePath, encoding: 'utf8', @@ -30,7 +30,7 @@ describe('package consumption', () => { }, 30_000); it('exports the complete runtime helper surface from the root entrypoint', () => { - execFileSync('pnpm', ['--filter', '@ollin/tui', 'build'], { + execFileSync('pnpm', ['--filter', '@ollin/console', 'build'], { cwd: workspacePath, stdio: 'pipe', }); @@ -116,7 +116,7 @@ describe('package consumption', () => { '--input-type=module', '-e', ` - const module = await import('@ollin/tui'); + const module = await import('@ollin/console'); const expected = ${JSON.stringify(expectedExports)}; const missing = expected.filter((name) => typeof module[name] === 'undefined'); console.log(JSON.stringify({ missing, count: Object.keys(module).length })); @@ -132,7 +132,7 @@ describe('package consumption', () => { }, 30_000); it('exports public helper types from the built root entrypoint', () => { - execFileSync('pnpm', ['--filter', '@ollin/tui', 'build'], { + execFileSync('pnpm', ['--filter', '@ollin/console', 'build'], { cwd: workspacePath, stdio: 'pipe', }); @@ -147,7 +147,7 @@ describe('package consumption', () => { try { mkdirSync(packageScopeDirectory, { recursive: true }); - symlinkSync(join(packagesPath, 'tui'), join(packageScopeDirectory, 'tui'), 'dir'); + symlinkSync(join(packagesPath, 'console'), join(packageScopeDirectory, 'console'), 'dir'); writeFileSync( consumerPath, ` @@ -170,7 +170,7 @@ describe('package consumption', () => { TypedValueOptions, TypedValueReadResult, TypedValueState - } from '@ollin/tui'; + } from '@ollin/console'; const choices: ChoiceOptions = ['one', { label: 'Two', value: 'two' }]; const confirmOptions: ConfirmPromptOptions = { message: 'Continue?', default: true }; diff --git a/pkgs-ts/tests/tests/forms/form-builder.test.ts b/pkgs-ts/tests/tests/forms/form-builder.test.ts new file mode 100644 index 00000000..6f17383c --- /dev/null +++ b/pkgs-ts/tests/tests/forms/form-builder.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from 'vitest'; + +import { form } from '@ollin/console'; + +import { scripted } from '../support/scripted'; + +describe('form builders', () => { + it('runs form builders', async () => { + const response = await scripted(['A', 'd', 'a', '\n', 'y'], () => + form().text('Name', '', '', false, undefined, '', 'name').confirm('Active', true, 'Yes', 'No', false, undefined, '', 'active').submit(), + ); + + expect(response.result.name).toBe('Ada'); + expect(response.result.active).toBe(true); + }); +}); diff --git a/pkgs-ts/tests/tests/output/messages.test.ts b/pkgs-ts/tests/tests/output/messages.test.ts new file mode 100644 index 00000000..7dc3f98c --- /dev/null +++ b/pkgs-ts/tests/tests/output/messages.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest'; + +import { createMemoryOutput, error, info, intro, note, outro, table, title, withPromptEnvironment } from '@ollin/console'; + +describe('output helpers', () => { + it('writes output helpers', async () => { + const output = createMemoryOutput(); + + await withPromptEnvironment({ output, error: output }, async () => { + note('Hello'); + error('Nope'); + info('Facts'); + intro('Start'); + outro('Done'); + table({ headers: ['Name'], rows: [['Ollin']] }); + title('Demo'); + }); + + expect(output.text()).toContain('Hello'); + expect(output.text()).toContain('Nope'); + expect(output.text()).toContain('Facts'); + expect(output.text()).toContain('Start'); + expect(output.text()).toContain('Done'); + expect(output.text()).toContain('| Name'); + expect(output.text()).toContain('\u001B]0;Demo\u0007'); + }); +}); diff --git a/pkgs-ts/tests/tests/output/status.test.ts b/pkgs-ts/tests/tests/output/status.test.ts new file mode 100644 index 00000000..d48f5aa7 --- /dev/null +++ b/pkgs-ts/tests/tests/output/status.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, it } from 'vitest'; + +import { createMemoryOutput, progress, spin, stream, withPromptEnvironment } from '@ollin/console'; + +describe('status helpers', () => { + it('runs status helpers', async () => { + const output = createMemoryOutput(); + + await withPromptEnvironment({ output, error: output }, async () => { + await spin(async () => 'done', { message: 'Working' }); + + const bar = progress(2, 'Files'); + + bar.advance(); + bar.advance(); + bar.finish(); + + await stream(['a', 'b']); + }); + + expect(output.text()).toContain('Working'); + expect(output.text()).toContain('┌ Files '); + expect(output.text()).toContain('2 / 2'); + expect(output.text()).toContain('ab'); + }); +}); diff --git a/pkgs-ts/tests/tests/prompts/prompts.test.ts b/pkgs-ts/tests/tests/prompts/prompts.test.ts new file mode 100644 index 00000000..59ed2627 --- /dev/null +++ b/pkgs-ts/tests/tests/prompts/prompts.test.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; + +import { confirm, multiselect, number, select, text } from '@ollin/console'; + +import { scripted } from '../support/scripted'; + +describe('prompt helpers', () => { + it('reads text and number prompts', async () => { + await expect(scripted(['A', 'd', 'a', '\n'], () => text('Name'))).resolves.toMatchObject({ result: 'Ada' }); + + await expect(scripted(['4', '2', '\n'], () => number({ message: 'Age', integer: true }))).resolves.toMatchObject({ result: 42 }); + }); + + it('reads confirm and choice prompts', async () => { + await expect(scripted(['n'], () => confirm('Continue'))).resolves.toMatchObject({ result: false }); + + await expect( + scripted(['2'], () => + select({ + message: 'Framework', + options: ['Ollin', 'Vue'], + }), + ), + ).resolves.toMatchObject({ result: 'Vue' }); + + await expect( + scripted(['1,2'], () => + multiselect({ + message: 'Tools', + options: ['Prompts', 'OpenTUI'], + }), + ), + ).resolves.toMatchObject({ result: ['Prompts', 'OpenTUI'] }); + }); +}); diff --git a/packages/acceptance/tests/opentui.test.ts b/pkgs-ts/tests/tests/rendering/opentui.test.ts similarity index 95% rename from packages/acceptance/tests/opentui.test.ts rename to pkgs-ts/tests/tests/rendering/opentui.test.ts index 8dd293f1..46538459 100644 --- a/packages/acceptance/tests/opentui.test.ts +++ b/pkgs-ts/tests/tests/rendering/opentui.test.ts @@ -1,7 +1,7 @@ import { Text } from '@opentui/core'; import { createTestRenderer } from '@opentui/core/testing'; import { describe, expect, it } from 'vitest'; -import { renderOpenTuiTextFrame } from '@ollin/tui'; +import { renderOpenTuiTextFrame } from '@ollin/console'; describe('OpenTUI memory renderer', () => { it('captures rendered text without writing to the real terminal', async () => { diff --git a/pkgs-ts/tests/tests/support/scripted.ts b/pkgs-ts/tests/tests/support/scripted.ts new file mode 100644 index 00000000..8afd5c92 --- /dev/null +++ b/pkgs-ts/tests/tests/support/scripted.ts @@ -0,0 +1,17 @@ +import { createMemoryOutput, createScriptedInput, withPromptEnvironment } from '@ollin/console'; + +export const scripted = async (lines: string[], callback: () => Promise): Promise<{ output: string; result: T }> => { + const output = createMemoryOutput(); + + const result = await withPromptEnvironment( + { + input: createScriptedInput(lines), + output, + error: output, + interactive: true, + }, + callback, + ); + + return { output: output.text(), result }; +}; diff --git a/pkgs-ts/tests/tsconfig.json b/pkgs-ts/tests/tsconfig.json new file mode 100644 index 00000000..60e1106d --- /dev/null +++ b/pkgs-ts/tests/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": ["@ollin/console-infra/tsconfig/base.json", "@ollin/console-infra/tsconfig/acceptance.json"], + "compilerOptions": { + "baseUrl": "..", + "paths": { + "@ollin/console": ["console/src/index.ts"], + "#console/*": ["console/src/*"], + "#console/prompts/*": ["console/src/prompts/*"] + } + }, + "include": ["tests/**/*.ts", "vitest.config.ts", "../console/src/**/*.ts"] +} diff --git a/packages/acceptance/vitest.config.ts b/pkgs-ts/tests/vitest.config.ts similarity index 73% rename from packages/acceptance/vitest.config.ts rename to pkgs-ts/tests/vitest.config.ts index 68b5f430..a98d767a 100644 --- a/packages/acceptance/vitest.config.ts +++ b/pkgs-ts/tests/vitest.config.ts @@ -5,20 +5,20 @@ import { fileURLToPath } from 'node:url'; const packagePath = dirname(fileURLToPath(import.meta.url)); const packagesPath = dirname(packagePath); const workspacePath = dirname(packagesPath); -const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'acceptance'); -const sourcePath = join(packagesPath, 'tui', 'src', 'index.ts'); -const internalSourcePath = join(packagesPath, 'tui', 'src', '$1'); +const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'tests'); +const sourcePath = join(packagesPath, 'console', 'src', 'index.ts'); +const internalSourcePath = join(packagesPath, 'console', 'src', '$1'); export default defineConfig({ cacheDir: cachePath, resolve: { alias: [ { - find: '@ollin/tui', + find: '@ollin/console', replacement: sourcePath, }, { - find: /^#tui\/(.+)$/u, + find: /^#console\/(.+)$/u, replacement: internalSourcePath, }, ], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da4e5552..ba1f4f7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,7 +8,7 @@ importers: .: devDependencies: - '@ollin/infra': + '@ollin/console-infra': specifier: workspace:* version: link:infra '@types/node': @@ -24,38 +24,7 @@ importers: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) - infra: - devDependencies: - '@types/node': - specifier: ^25.6.2 - version: 25.9.2 - typescript: - specifier: ^6.0.3 - version: 6.0.3 - - packages/acceptance: - dependencies: - '@ollin/tui': - specifier: workspace:* - version: link:../tui - '@opentui/core': - specifier: ^0.4.0 - version: 0.4.0(typescript@6.0.3)(web-tree-sitter@0.25.10) - devDependencies: - '@ollin/infra': - specifier: workspace:* - version: link:../../infra - '@types/node': - specifier: ^25.6.2 - version: 25.9.2 - typescript: - specifier: ^6.0.3 - version: 6.0.3 - vitest: - specifier: ^4.1.5 - version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) - - packages/docs: + apps/docs: dependencies: '@fontsource/geist-mono': specifier: ^5.2.8 @@ -63,9 +32,9 @@ importers: '@fontsource/geist-sans': specifier: ^5.2.5 version: 5.2.5 - '@ollin/tui': + '@ollin/console': specifier: workspace:* - version: link:../tui + version: link:../../pkgs-ts/console '@vueuse/core': specifier: ^14.3.0 version: 14.3.0(vue@3.5.38(typescript@6.0.3)) @@ -76,7 +45,7 @@ importers: specifier: ^2.9.10 version: 2.9.10(vue@3.5.38(typescript@6.0.3)) devDependencies: - '@ollin/infra': + '@ollin/console-infra': specifier: workspace:* version: link:../../infra '@tailwindcss/vite': @@ -119,7 +88,18 @@ importers: specifier: ^3.5.38 version: 3.5.38(typescript@6.0.3) - packages/tui: + infra: + devDependencies: + '@types/node': + specifier: ^25.6.2 + version: 25.9.2 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + + pkgs-go: {} + + pkgs-ts/console: dependencies: '@opentui/core': specifier: ^0.4.0 @@ -134,7 +114,29 @@ importers: specifier: ^4.4.3 version: 4.4.3 devDependencies: - '@ollin/infra': + '@ollin/console-infra': + specifier: workspace:* + version: link:../../infra + '@types/node': + specifier: ^25.6.2 + version: 25.9.2 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vitest: + specifier: ^4.1.5 + version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) + + pkgs-ts/tests: + dependencies: + '@ollin/console': + specifier: workspace:* + version: link:../console + '@opentui/core': + specifier: ^0.4.0 + version: 0.4.0(typescript@6.0.3)(web-tree-sitter@0.25.10) + devDependencies: + '@ollin/console-infra': specifier: workspace:* version: link:../../infra '@types/node': @@ -1002,27 +1004,15 @@ packages: '@vitest/utils@4.1.8': resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} - '@vue/compiler-core@3.5.37': - resolution: {integrity: sha512-TfQz4bsBQTPoTeBWTUPJPq+4FCTTXg2pbp8TjjAyrGaLAu9nfrZTxKLf6mdAlclnwtyUToFaMQu7QRS63Qek1g==} - '@vue/compiler-core@3.5.38': resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} - '@vue/compiler-dom@3.5.37': - resolution: {integrity: sha512-oqfl/QaCVEWxphALFEZ7m+q9z+Sghz9ZCcoJ/oplTGxsOgx2czVzSZxkMkzQrWIahywOeyGHdg9ml/WUz3DMzw==} - '@vue/compiler-dom@3.5.38': resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} - '@vue/compiler-sfc@3.5.37': - resolution: {integrity: sha512-hYu+efs678xaPHYxhFRK3ZhkQ/FueMVnROooZqemOYlyQBQg06qkIrpyAUrUWWqMLfifgOdWwU6CL6FuTRvP4A==} - '@vue/compiler-sfc@3.5.38': resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} - '@vue/compiler-ssr@3.5.37': - resolution: {integrity: sha512-ihbdCLJLXFKV3efEQlFfzy6TLHRuOQ/+dze2vZfg0DIncVxkcUxwCqPewCiSVdWXFeoiuMMON87wpt+G+yT22A==} - '@vue/compiler-ssr@3.5.38': resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} @@ -1035,37 +1025,20 @@ packages: '@vue/devtools-shared@7.7.9': resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==} - '@vue/reactivity@3.5.37': - resolution: {integrity: sha512-M7j7YF68IUd2uFNIqhwybpzUG/Sk9HUtk+ULmC+g6JeZ80LyCyGnjv6SYBR86t3fyyuYlZUSb18yu4UYLgw5jg==} - '@vue/reactivity@3.5.38': resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} - '@vue/runtime-core@3.5.37': - resolution: {integrity: sha512-N0IWRirNPzJp/DuUCR9M+obVUHZArMkmldRApKsJRIWA+XDO6iwF4Zh94HP6uCzYVgWVwr8YuKeWF4H52VxTbw==} - '@vue/runtime-core@3.5.38': resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} - '@vue/runtime-dom@3.5.37': - resolution: {integrity: sha512-9VkutCFwfVOiMRH7mgi7QapsqC8Hxcow3DLvBKf+mRH88P94Ib/D/u6l/ln62ST+fIvmsOO7+Db99LzWv9slJg==} - '@vue/runtime-dom@3.5.38': resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} - '@vue/server-renderer@3.5.37': - resolution: {integrity: sha512-CP7nbxJb1Zc0/oeBqu6CtMf9TN64fz6qE75BZ8mWh04zAEya8EAZmqH2gRQWkoUUjFqv9i7h/mV+E4/LL4JXXw==} - peerDependencies: - vue: 3.5.37 - '@vue/server-renderer@3.5.38': resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} peerDependencies: vue: 3.5.38 - '@vue/shared@3.5.37': - resolution: {integrity: sha512-JzFx4aYGz+EtBl8zzw8XECNWSmNXTrU5jpub3T1lQ+2X5Ys9QzHWafxhE+E5qS2Ry/mVl8o2QqrwRGYYOFYguw==} - '@vue/shared@3.5.38': resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} @@ -1762,14 +1735,6 @@ packages: '@vue/composition-api': optional: true - vue@3.5.37: - resolution: {integrity: sha512-So4bMq165gsD4+hDVC1/bcbsOpTlUFGGkpuH2sx9vCflChIWahy4C0K4ZcX/COe0ad1IToIRT3VQz0dl4XPihg==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - vue@3.5.38: resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} peerDependencies: @@ -2484,10 +2449,10 @@ snapshots: '@ungap/structured-clone@1.3.1': {} - '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@25.9.2)(lightningcss@1.32.0))(vue@3.5.37(typescript@6.0.3))': + '@vitejs/plugin-vue@5.2.4(vite@5.4.21(@types/node@25.9.2)(lightningcss@1.32.0))(vue@3.5.38(typescript@6.0.3))': dependencies: vite: 5.4.21(@types/node@25.9.2)(lightningcss@1.32.0) - vue: 3.5.37(typescript@6.0.3) + vue: 3.5.38(typescript@6.0.3) '@vitest/expect@4.1.8': dependencies: @@ -2530,14 +2495,6 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@vue/compiler-core@3.5.37': - dependencies: - '@babel/parser': 7.29.7 - '@vue/shared': 3.5.37 - entities: 7.0.1 - estree-walker: 2.0.2 - source-map-js: 1.2.1 - '@vue/compiler-core@3.5.38': dependencies: '@babel/parser': 7.29.7 @@ -2546,28 +2503,11 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.37': - dependencies: - '@vue/compiler-core': 3.5.37 - '@vue/shared': 3.5.37 - '@vue/compiler-dom@3.5.38': dependencies: '@vue/compiler-core': 3.5.38 '@vue/shared': 3.5.38 - '@vue/compiler-sfc@3.5.37': - dependencies: - '@babel/parser': 7.29.7 - '@vue/compiler-core': 3.5.37 - '@vue/compiler-dom': 3.5.37 - '@vue/compiler-ssr': 3.5.37 - '@vue/shared': 3.5.37 - estree-walker: 2.0.2 - magic-string: 0.30.21 - postcss: 8.5.15 - source-map-js: 1.2.1 - '@vue/compiler-sfc@3.5.38': dependencies: '@babel/parser': 7.29.7 @@ -2580,11 +2520,6 @@ snapshots: postcss: 8.5.15 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.37': - dependencies: - '@vue/compiler-dom': 3.5.37 - '@vue/shared': 3.5.37 - '@vue/compiler-ssr@3.5.38': dependencies: '@vue/compiler-dom': 3.5.38 @@ -2608,31 +2543,15 @@ snapshots: dependencies: rfdc: 1.4.1 - '@vue/reactivity@3.5.37': - dependencies: - '@vue/shared': 3.5.37 - '@vue/reactivity@3.5.38': dependencies: '@vue/shared': 3.5.38 - '@vue/runtime-core@3.5.37': - dependencies: - '@vue/reactivity': 3.5.37 - '@vue/shared': 3.5.37 - '@vue/runtime-core@3.5.38': dependencies: '@vue/reactivity': 3.5.38 '@vue/shared': 3.5.38 - '@vue/runtime-dom@3.5.37': - dependencies: - '@vue/reactivity': 3.5.37 - '@vue/runtime-core': 3.5.37 - '@vue/shared': 3.5.37 - csstype: 3.2.3 - '@vue/runtime-dom@3.5.38': dependencies: '@vue/reactivity': 3.5.38 @@ -2640,20 +2559,12 @@ snapshots: '@vue/shared': 3.5.38 csstype: 3.2.3 - '@vue/server-renderer@3.5.37(vue@3.5.37(typescript@6.0.3))': - dependencies: - '@vue/compiler-ssr': 3.5.37 - '@vue/shared': 3.5.37 - vue: 3.5.37(typescript@6.0.3) - '@vue/server-renderer@3.5.38(vue@3.5.38(typescript@6.0.3))': dependencies: '@vue/compiler-ssr': 3.5.38 '@vue/shared': 3.5.38 vue: 3.5.38(typescript@6.0.3) - '@vue/shared@3.5.37': {} - '@vue/shared@3.5.38': {} '@vueuse/core@12.8.2(typescript@6.0.3)': @@ -2661,7 +2572,7 @@ snapshots: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 12.8.2 '@vueuse/shared': 12.8.2(typescript@6.0.3) - vue: 3.5.37(typescript@6.0.3) + vue: 3.5.38(typescript@6.0.3) transitivePeerDependencies: - typescript @@ -2676,7 +2587,7 @@ snapshots: dependencies: '@vueuse/core': 12.8.2(typescript@6.0.3) '@vueuse/shared': 12.8.2(typescript@6.0.3) - vue: 3.5.37(typescript@6.0.3) + vue: 3.5.38(typescript@6.0.3) optionalDependencies: focus-trap: 7.8.0 transitivePeerDependencies: @@ -2688,7 +2599,7 @@ snapshots: '@vueuse/shared@12.8.2(typescript@6.0.3)': dependencies: - vue: 3.5.37(typescript@6.0.3) + vue: 3.5.38(typescript@6.0.3) transitivePeerDependencies: - typescript @@ -3250,9 +3161,9 @@ snapshots: '@shikijs/transformers': 2.5.0 '@shikijs/types': 2.5.0 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@25.9.2)(lightningcss@1.32.0))(vue@3.5.37(typescript@6.0.3)) + '@vitejs/plugin-vue': 5.2.4(vite@5.4.21(@types/node@25.9.2)(lightningcss@1.32.0))(vue@3.5.38(typescript@6.0.3)) '@vue/devtools-api': 7.7.9 - '@vue/shared': 3.5.37 + '@vue/shared': 3.5.38 '@vueuse/core': 12.8.2(typescript@6.0.3) '@vueuse/integrations': 12.8.2(focus-trap@7.8.0)(typescript@6.0.3) focus-trap: 7.8.0 @@ -3260,7 +3171,7 @@ snapshots: minisearch: 7.2.0 shiki: 2.5.0 vite: 5.4.21(@types/node@25.9.2)(lightningcss@1.32.0) - vue: 3.5.37(typescript@6.0.3) + vue: 3.5.38(typescript@6.0.3) optionalDependencies: postcss: 8.5.15 transitivePeerDependencies: @@ -3321,16 +3232,6 @@ snapshots: dependencies: vue: 3.5.38(typescript@6.0.3) - vue@3.5.37(typescript@6.0.3): - dependencies: - '@vue/compiler-dom': 3.5.37 - '@vue/compiler-sfc': 3.5.37 - '@vue/runtime-dom': 3.5.37 - '@vue/server-renderer': 3.5.37(vue@3.5.37(typescript@6.0.3)) - '@vue/shared': 3.5.37 - optionalDependencies: - typescript: 6.0.3 - vue@3.5.38(typescript@6.0.3): dependencies: '@vue/compiler-dom': 3.5.38 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cf12e65e..f4e426ac 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,7 @@ packages: - - "packages/*" + - "pkgs-ts/*" + - "apps/*" + - "pkgs-go" - "infra" allowBuilds: From 0b0244905b707f61aa1be6b7793954d1e42c3137 Mon Sep 17 00:00:00 2001 From: Gustavo Ocanto Date: Wed, 17 Jun 2026 15:47:38 +0800 Subject: [PATCH 3/4] format --- apps/docs/package.json | 20 ++--- apps/docs/tests/docs.test.ts | 2 +- apps/docs/tsconfig.json | 8 +- apps/docs/vitest.config.ts | 27 +----- infra/README.md | 2 +- infra/make/fresh.mk | 1 + infra/tsconfig/acceptance.json | 5 -- infra/tsconfig/tests.json | 5 ++ pkgs-ts/tests/tsconfig.json | 2 +- pnpm-lock.yaml | 85 ++++++++++++------- pnpm-workspace.yaml | 1 + {apps/docs => vitepress}/components.json | 2 +- {apps/docs/vitepress => vitepress}/config.ts | 4 +- vitepress/package.json | 31 +++++++ .../theme/components/TerminalOutput.vue | 0 .../theme/components/ui/badge/Badge.vue | 0 .../theme/components/ui/badge/index.ts | 0 .../theme/components/ui/badge/variants.ts | 0 .../theme/components/ui/card/Card.vue | 0 .../theme/components/ui/card/CardAction.vue | 0 .../theme/components/ui/card/CardContent.vue | 0 .../components/ui/card/CardDescription.vue | 0 .../theme/components/ui/card/CardFooter.vue | 0 .../theme/components/ui/card/CardHeader.vue | 0 .../theme/components/ui/card/CardTitle.vue | 0 .../theme/components/ui/card/index.ts | 0 .../components/ui/separator/Separator.vue | 0 .../theme/components/ui/separator/index.ts | 0 .../vitepress => vitepress}/theme/index.ts | 0 .../theme/lib/utils.ts | 0 .../vitepress => vitepress}/theme/styles.css | 0 vitepress/tsconfig.json | 14 +++ {apps/docs/vitepress => vitepress}/vue.d.ts | 0 33 files changed, 119 insertions(+), 90 deletions(-) delete mode 100644 infra/tsconfig/acceptance.json create mode 100644 infra/tsconfig/tests.json rename {apps/docs => vitepress}/components.json (90%) rename {apps/docs/vitepress => vitepress}/config.ts (92%) create mode 100644 vitepress/package.json rename {apps/docs/vitepress => vitepress}/theme/components/TerminalOutput.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/badge/Badge.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/badge/index.ts (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/badge/variants.ts (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/Card.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/CardAction.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/CardContent.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/CardDescription.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/CardFooter.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/CardHeader.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/CardTitle.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/card/index.ts (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/separator/Separator.vue (100%) rename {apps/docs/vitepress => vitepress}/theme/components/ui/separator/index.ts (100%) rename {apps/docs/vitepress => vitepress}/theme/index.ts (100%) rename {apps/docs/vitepress => vitepress}/theme/lib/utils.ts (100%) rename {apps/docs/vitepress => vitepress}/theme/styles.css (100%) create mode 100644 vitepress/tsconfig.json rename {apps/docs/vitepress => vitepress}/vue.d.ts (100%) diff --git a/apps/docs/package.json b/apps/docs/package.json index d7d8ed50..fdde6bd7 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -5,34 +5,24 @@ "type": "module", "scripts": { "api": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright typedoc --options typedoc.json && cp src/api/README.md src/api/index.md", - "build": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress build src --config vitepress/config.ts", - "dev": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress dev src --config vitepress/config.ts --host 127.0.0.1", - "preview": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress preview src --config vitepress/config.ts --host 127.0.0.1", + "build": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress build src --config ../../vitepress/config.ts", + "dev": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress dev src --config ../../vitepress/config.ts --host 127.0.0.1", + "preview": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress preview src --config ../../vitepress/config.ts --host 127.0.0.1", "test": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitest run --config vitest.config.ts", "typecheck": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@fontsource/geist-mono": "^5.2.8", - "@fontsource/geist-sans": "^5.2.5", "@ollin/console": "workspace:*", - "@vueuse/core": "^14.3.0", - "@xterm/xterm": "^6.0.0", - "reka-ui": "^2.9.10" + "@ollin/vitepress": "workspace:*" }, "devDependencies": { "@ollin/console-infra": "workspace:*", - "@tailwindcss/vite": "^4.3.0", "@types/node": "^25.6.2", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "tailwind-merge": "^3.6.0", - "tailwindcss": "^4.3.0", "typedoc": "^0.28.19", "typedoc-plugin-markdown": "^4.12.0", "typescript": "^6.0.3", "vite": "^8.0.16", "vitepress": "^1.6.4", - "vitest": "^4.1.5", - "vue": "^3.5.38" + "vitest": "^4.1.5" } } diff --git a/apps/docs/tests/docs.test.ts b/apps/docs/tests/docs.test.ts index caa2b7e7..12293096 100644 --- a/apps/docs/tests/docs.test.ts +++ b/apps/docs/tests/docs.test.ts @@ -2,7 +2,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; import { dirname, extname, join, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; import { describe, expect, it } from 'vitest'; -import { guideSections } from '@docs-config'; +import { guideSections } from '@ollin/vitepress'; const testsPath = dirname(fileURLToPath(import.meta.url)); const packagePath = dirname(testsPath); diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index 0327742e..976b3a39 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -4,17 +4,13 @@ "baseUrl": ".", "paths": { "@docs/*": ["src/*"], - "@docs-components/*": ["vitepress/theme/components/*"], - "@docs-config": ["vitepress/config.ts"], - "@docs-lib/*": ["vitepress/theme/lib/*"], "@docs-tests/*": ["tests/*"], - "@docs-theme/*": ["vitepress/theme/*"], - "@docs-ui/*": ["vitepress/theme/components/ui/*"], + "@ollin/vitepress": ["../../vitepress/config.ts"], "@ollin/console": ["../../pkgs-ts/console/src/index.ts"], "#console/*": ["../../pkgs-ts/console/src/*"], "#console/prompts/*": ["../../pkgs-ts/console/src/prompts/*"] }, "tsBuildInfoFile": "../../infra/.cache/tsbuild/docs.tsbuildinfo" }, - "include": ["examples/**/*.ts", "tests/**/*.ts", "vitepress/**/*.ts", "vitest.config.ts", "../../pkgs-ts/console/src/**/*.ts"] + "include": ["examples/**/*.ts", "tests/**/*.ts", "vitest.config.ts", "../../vitepress/config.ts", "../../pkgs-ts/console/src/**/*.ts"] } diff --git a/apps/docs/vitest.config.ts b/apps/docs/vitest.config.ts index ae1e3912..661a997c 100644 --- a/apps/docs/vitest.config.ts +++ b/apps/docs/vitest.config.ts @@ -6,16 +6,11 @@ const packagePath = dirname(fileURLToPath(import.meta.url)); const packagesPath = dirname(packagePath); const workspacePath = dirname(packagesPath); const docsSourcePath = join(packagePath, 'src'); -const docsVitepressPath = join(packagePath, 'vitepress'); -const docsThemePath = join(docsVitepressPath, 'theme'); -const docsComponentsPath = join(docsThemePath, 'components'); const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'docs'); const consoleSourcePath = join(workspacePath, 'pkgs-ts', 'console', 'src', 'index.ts'); const internalSourcePath = join(workspacePath, 'pkgs-ts', 'console', 'src', '$1'); -const docsConfigPath = join(docsVitepressPath, 'config.ts'); -const docsLibPath = join(docsThemePath, 'lib'); +const vitepressConfigPath = join(workspacePath, 'vitepress', 'config.ts'); const docsTestsPath = join(packagePath, 'tests'); -const docsUiPath = join(docsComponentsPath, 'ui'); export default defineConfig({ cacheDir: cachePath, @@ -25,29 +20,13 @@ export default defineConfig({ find: '@docs', replacement: docsSourcePath, }, - { - find: '@docs-components', - replacement: docsComponentsPath, - }, - { - find: '@docs-config', - replacement: docsConfigPath, - }, - { - find: '@docs-lib', - replacement: docsLibPath, - }, { find: '@docs-tests', replacement: docsTestsPath, }, { - find: '@docs-theme', - replacement: docsThemePath, - }, - { - find: '@docs-ui', - replacement: docsUiPath, + find: '@ollin/vitepress', + replacement: vitepressConfigPath, }, { find: '@ollin/console', diff --git a/infra/README.md b/infra/README.md index 71af227c..d7b39bce 100644 --- a/infra/README.md +++ b/infra/README.md @@ -6,7 +6,7 @@ the public package runtime: - `src` exposes shared TypeScript path helpers (`infraRoot`, `cacheDir`, `workspacePath`, …) for the tool cache. - `tsconfig` holds the centralized TypeScript configs every package extends - (`base.json`, `console.json`, `acceptance.json`), published via the + (`base.json`, `console.json`, `tests.json`), published via the `@ollin/console-infra/tsconfig/*.json` exports. - `make` holds the modular Makefile. The repo-root `Makefile` is a transparent forwarder into `infra/make/Makefile`. diff --git a/infra/make/fresh.mk b/infra/make/fresh.mk index 48ea53d9..8d9c5059 100644 --- a/infra/make/fresh.mk +++ b/infra/make/fresh.mk @@ -9,6 +9,7 @@ fresh: ## Clean generated state, reinstall dependencies, then build "$(ROOT_PATH)"/pkgs-ts/*/node_modules \ "$(ROOT_PATH)"/apps/*/node_modules \ "$(ROOT_PATH)/pkgs-go/node_modules" \ + "$(ROOT_PATH)/vitepress/node_modules" \ "$(ROOT_PATH)/infra/node_modules" \ "$(ROOT_PATH)/infra/.cache" \ "$(ROOT_PATH)/apps/docs/src/.vitepress/cache" \ diff --git a/infra/tsconfig/acceptance.json b/infra/tsconfig/acceptance.json deleted file mode 100644 index fe189ce5..00000000 --- a/infra/tsconfig/acceptance.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "../.cache/tsbuild/acceptance.tsbuildinfo" - } -} diff --git a/infra/tsconfig/tests.json b/infra/tsconfig/tests.json new file mode 100644 index 00000000..3db97d85 --- /dev/null +++ b/infra/tsconfig/tests.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "../.cache/tsbuild/tests.tsbuildinfo" + } +} diff --git a/pkgs-ts/tests/tsconfig.json b/pkgs-ts/tests/tsconfig.json index 60e1106d..5a1314c1 100644 --- a/pkgs-ts/tests/tsconfig.json +++ b/pkgs-ts/tests/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": ["@ollin/console-infra/tsconfig/base.json", "@ollin/console-infra/tsconfig/acceptance.json"], + "extends": ["@ollin/console-infra/tsconfig/base.json", "@ollin/console-infra/tsconfig/tests.json"], "compilerOptions": { "baseUrl": "..", "paths": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba1f4f7b..1184d58c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,46 +26,19 @@ importers: apps/docs: dependencies: - '@fontsource/geist-mono': - specifier: ^5.2.8 - version: 5.2.8 - '@fontsource/geist-sans': - specifier: ^5.2.5 - version: 5.2.5 '@ollin/console': specifier: workspace:* version: link:../../pkgs-ts/console - '@vueuse/core': - specifier: ^14.3.0 - version: 14.3.0(vue@3.5.38(typescript@6.0.3)) - '@xterm/xterm': - specifier: ^6.0.0 - version: 6.0.0 - reka-ui: - specifier: ^2.9.10 - version: 2.9.10(vue@3.5.38(typescript@6.0.3)) + '@ollin/vitepress': + specifier: workspace:* + version: link:../../vitepress devDependencies: '@ollin/console-infra': specifier: workspace:* version: link:../../infra - '@tailwindcss/vite': - specifier: ^4.3.0 - version: 4.3.0(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) '@types/node': specifier: ^25.6.2 version: 25.9.2 - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - tailwind-merge: - specifier: ^3.6.0 - version: 3.6.0 - tailwindcss: - specifier: ^4.3.0 - version: 4.3.0 typedoc: specifier: ^0.28.19 version: 0.28.19(typescript@6.0.3) @@ -84,9 +57,6 @@ importers: vitest: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) - vue: - specifier: ^3.5.38 - version: 3.5.38(typescript@6.0.3) infra: devDependencies: @@ -149,6 +119,55 @@ importers: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) + vitepress: + dependencies: + '@fontsource/geist-mono': + specifier: ^5.2.8 + version: 5.2.8 + '@fontsource/geist-sans': + specifier: ^5.2.5 + version: 5.2.5 + '@vueuse/core': + specifier: ^14.3.0 + version: 14.3.0(vue@3.5.38(typescript@6.0.3)) + '@xterm/xterm': + specifier: ^6.0.0 + version: 6.0.0 + reka-ui: + specifier: ^2.9.10 + version: 2.9.10(vue@3.5.38(typescript@6.0.3)) + devDependencies: + '@ollin/console-infra': + specifier: workspace:* + version: link:../infra + '@tailwindcss/vite': + specifier: ^4.3.0 + version: 4.3.0(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) + '@types/node': + specifier: ^25.6.2 + version: 25.9.2 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + tailwind-merge: + specifier: ^3.6.0 + version: 3.6.0 + tailwindcss: + specifier: ^4.3.0 + version: 4.3.0 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vitepress: + specifier: ^1.6.4 + version: 1.6.4(@algolia/client-search@5.53.0)(@types/node@25.9.2)(lightningcss@1.32.0)(postcss@8.5.15)(search-insights@2.17.3)(typescript@6.0.3) + vue: + specifier: ^3.5.38 + version: 3.5.38(typescript@6.0.3) + packages: '@algolia/abtesting@1.19.0': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f4e426ac..639f1ff1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,6 +2,7 @@ packages: - "pkgs-ts/*" - "apps/*" - "pkgs-go" + - "vitepress" - "infra" allowBuilds: diff --git a/apps/docs/components.json b/vitepress/components.json similarity index 90% rename from apps/docs/components.json rename to vitepress/components.json index acd2bf12..1073bf41 100644 --- a/apps/docs/components.json +++ b/vitepress/components.json @@ -4,7 +4,7 @@ "typescript": true, "tailwind": { "config": "", - "css": "vitepress/theme/styles.css", + "css": "theme/styles.css", "baseColor": "neutral", "cssVariables": true, "prefix": "" diff --git a/apps/docs/vitepress/config.ts b/vitepress/config.ts similarity index 92% rename from apps/docs/vitepress/config.ts rename to vitepress/config.ts index 62967256..4b452b1d 100644 --- a/apps/docs/vitepress/config.ts +++ b/vitepress/config.ts @@ -2,12 +2,11 @@ import { fileURLToPath } from 'node:url'; import tailwindcss from '@tailwindcss/vite'; import { defineConfig } from 'vitepress'; -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('../../../infra/.cache/vitepress/docs', import.meta.url)); +const viteCachePath = fileURLToPath(new URL('../infra/.cache/vitepress/docs', import.meta.url)); const tailwindPlugin = tailwindcss() as never; export const guideSections = [ @@ -51,7 +50,6 @@ export default defineConfig({ plugins: [tailwindPlugin], resolve: { alias: [ - { find: '@docs', replacement: sourcePath }, { find: '@docs-components', replacement: themeComponentsPath }, { find: '@docs-lib', replacement: themeLibPath }, { find: '@docs-theme', replacement: themePath }, diff --git a/vitepress/package.json b/vitepress/package.json new file mode 100644 index 00000000..8f1fb54a --- /dev/null +++ b/vitepress/package.json @@ -0,0 +1,31 @@ +{ + "name": "@ollin/vitepress", + "version": "0.1.0", + "private": true, + "type": "module", + "exports": { + ".": "./config.ts" + }, + "scripts": { + "typecheck": "XDG_CACHE_HOME=../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../infra/.cache/playwright tsc -p tsconfig.json --noEmit" + }, + "dependencies": { + "@fontsource/geist-mono": "^5.2.8", + "@fontsource/geist-sans": "^5.2.5", + "@vueuse/core": "^14.3.0", + "@xterm/xterm": "^6.0.0", + "reka-ui": "^2.9.10" + }, + "devDependencies": { + "@ollin/console-infra": "workspace:*", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^25.6.2", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "tailwind-merge": "^3.6.0", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vitepress": "^1.6.4", + "vue": "^3.5.38" + } +} diff --git a/apps/docs/vitepress/theme/components/TerminalOutput.vue b/vitepress/theme/components/TerminalOutput.vue similarity index 100% rename from apps/docs/vitepress/theme/components/TerminalOutput.vue rename to vitepress/theme/components/TerminalOutput.vue diff --git a/apps/docs/vitepress/theme/components/ui/badge/Badge.vue b/vitepress/theme/components/ui/badge/Badge.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/badge/Badge.vue rename to vitepress/theme/components/ui/badge/Badge.vue diff --git a/apps/docs/vitepress/theme/components/ui/badge/index.ts b/vitepress/theme/components/ui/badge/index.ts similarity index 100% rename from apps/docs/vitepress/theme/components/ui/badge/index.ts rename to vitepress/theme/components/ui/badge/index.ts diff --git a/apps/docs/vitepress/theme/components/ui/badge/variants.ts b/vitepress/theme/components/ui/badge/variants.ts similarity index 100% rename from apps/docs/vitepress/theme/components/ui/badge/variants.ts rename to vitepress/theme/components/ui/badge/variants.ts diff --git a/apps/docs/vitepress/theme/components/ui/card/Card.vue b/vitepress/theme/components/ui/card/Card.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/Card.vue rename to vitepress/theme/components/ui/card/Card.vue diff --git a/apps/docs/vitepress/theme/components/ui/card/CardAction.vue b/vitepress/theme/components/ui/card/CardAction.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/CardAction.vue rename to vitepress/theme/components/ui/card/CardAction.vue diff --git a/apps/docs/vitepress/theme/components/ui/card/CardContent.vue b/vitepress/theme/components/ui/card/CardContent.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/CardContent.vue rename to vitepress/theme/components/ui/card/CardContent.vue diff --git a/apps/docs/vitepress/theme/components/ui/card/CardDescription.vue b/vitepress/theme/components/ui/card/CardDescription.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/CardDescription.vue rename to vitepress/theme/components/ui/card/CardDescription.vue diff --git a/apps/docs/vitepress/theme/components/ui/card/CardFooter.vue b/vitepress/theme/components/ui/card/CardFooter.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/CardFooter.vue rename to vitepress/theme/components/ui/card/CardFooter.vue diff --git a/apps/docs/vitepress/theme/components/ui/card/CardHeader.vue b/vitepress/theme/components/ui/card/CardHeader.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/CardHeader.vue rename to vitepress/theme/components/ui/card/CardHeader.vue diff --git a/apps/docs/vitepress/theme/components/ui/card/CardTitle.vue b/vitepress/theme/components/ui/card/CardTitle.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/CardTitle.vue rename to vitepress/theme/components/ui/card/CardTitle.vue diff --git a/apps/docs/vitepress/theme/components/ui/card/index.ts b/vitepress/theme/components/ui/card/index.ts similarity index 100% rename from apps/docs/vitepress/theme/components/ui/card/index.ts rename to vitepress/theme/components/ui/card/index.ts diff --git a/apps/docs/vitepress/theme/components/ui/separator/Separator.vue b/vitepress/theme/components/ui/separator/Separator.vue similarity index 100% rename from apps/docs/vitepress/theme/components/ui/separator/Separator.vue rename to vitepress/theme/components/ui/separator/Separator.vue diff --git a/apps/docs/vitepress/theme/components/ui/separator/index.ts b/vitepress/theme/components/ui/separator/index.ts similarity index 100% rename from apps/docs/vitepress/theme/components/ui/separator/index.ts rename to vitepress/theme/components/ui/separator/index.ts diff --git a/apps/docs/vitepress/theme/index.ts b/vitepress/theme/index.ts similarity index 100% rename from apps/docs/vitepress/theme/index.ts rename to vitepress/theme/index.ts diff --git a/apps/docs/vitepress/theme/lib/utils.ts b/vitepress/theme/lib/utils.ts similarity index 100% rename from apps/docs/vitepress/theme/lib/utils.ts rename to vitepress/theme/lib/utils.ts diff --git a/apps/docs/vitepress/theme/styles.css b/vitepress/theme/styles.css similarity index 100% rename from apps/docs/vitepress/theme/styles.css rename to vitepress/theme/styles.css diff --git a/vitepress/tsconfig.json b/vitepress/tsconfig.json new file mode 100644 index 00000000..d9285a84 --- /dev/null +++ b/vitepress/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@ollin/console-infra/tsconfig/base.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@docs-components/*": ["theme/components/*"], + "@docs-lib/*": ["theme/lib/*"], + "@docs-theme/*": ["theme/*"], + "@docs-ui/*": ["theme/components/ui/*"] + }, + "tsBuildInfoFile": "../infra/.cache/tsbuild/vitepress.tsbuildinfo" + }, + "include": ["config.ts", "theme/**/*.ts", "vue.d.ts"] +} diff --git a/apps/docs/vitepress/vue.d.ts b/vitepress/vue.d.ts similarity index 100% rename from apps/docs/vitepress/vue.d.ts rename to vitepress/vue.d.ts From 532b1e5edfb29edbaeba8bcc62a094fdf1fdab55 Mon Sep 17 00:00:00 2001 From: Gustavo Ocanto Date: Wed, 17 Jun 2026 16:08:01 +0800 Subject: [PATCH 4/4] format --- .gitignore | 15 ++- apps/docs/package.json | 6 +- apps/docs/tsconfig.json | 4 +- apps/docs/vitest.config.ts | 2 +- {vitepress => apps/vitepress}/components.json | 0 {vitepress => apps/vitepress}/config.ts | 2 +- {vitepress => apps/vitepress}/package.json | 2 +- .../theme/components/TerminalOutput.vue | 0 .../theme/components/ui/badge/Badge.vue | 0 .../theme/components/ui/badge/index.ts | 0 .../theme/components/ui/badge/variants.ts | 0 .../theme/components/ui/card/Card.vue | 0 .../theme/components/ui/card/CardAction.vue | 0 .../theme/components/ui/card/CardContent.vue | 0 .../components/ui/card/CardDescription.vue | 0 .../theme/components/ui/card/CardFooter.vue | 0 .../theme/components/ui/card/CardHeader.vue | 0 .../theme/components/ui/card/CardTitle.vue | 0 .../theme/components/ui/card/index.ts | 0 .../components/ui/separator/Separator.vue | 0 .../theme/components/ui/separator/index.ts | 0 {vitepress => apps/vitepress}/theme/index.ts | 0 .../vitepress}/theme/lib/utils.ts | 0 .../vitepress}/theme/styles.css | 0 {vitepress => apps/vitepress}/tsconfig.json | 2 +- {vitepress => apps/vitepress}/vue.d.ts | 0 infra/README.md | 4 + infra/make/fresh.mk | 3 +- infra/scripts/run-turbo.mjs | 91 ++++++++++++++++ package.json | 6 +- .../distribution/package.test.ts | 22 ++-- .../forms/form-builder.test.ts | 0 .../output/messages.test.ts | 0 .../{tests => console}/output/status.test.ts | 0 .../prompts/prompts.test.ts | 0 .../rendering/opentui.test.ts | 0 .../{tests => console}/support/scripted.ts | 0 pkgs-ts/tests/tsconfig.json | 2 +- pnpm-lock.yaml | 100 +++++++++--------- pnpm-workspace.yaml | 1 - 40 files changed, 184 insertions(+), 78 deletions(-) rename {vitepress => apps/vitepress}/components.json (100%) rename {vitepress => apps/vitepress}/config.ts (96%) rename {vitepress => apps/vitepress}/package.json (82%) rename {vitepress => apps/vitepress}/theme/components/TerminalOutput.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/badge/Badge.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/badge/index.ts (100%) rename {vitepress => apps/vitepress}/theme/components/ui/badge/variants.ts (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/Card.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/CardAction.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/CardContent.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/CardDescription.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/CardFooter.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/CardHeader.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/CardTitle.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/card/index.ts (100%) rename {vitepress => apps/vitepress}/theme/components/ui/separator/Separator.vue (100%) rename {vitepress => apps/vitepress}/theme/components/ui/separator/index.ts (100%) rename {vitepress => apps/vitepress}/theme/index.ts (100%) rename {vitepress => apps/vitepress}/theme/lib/utils.ts (100%) rename {vitepress => apps/vitepress}/theme/styles.css (100%) rename {vitepress => apps/vitepress}/tsconfig.json (82%) rename {vitepress => apps/vitepress}/vue.d.ts (100%) create mode 100644 infra/scripts/run-turbo.mjs rename pkgs-ts/tests/{tests => console}/distribution/package.test.ts (88%) rename pkgs-ts/tests/{tests => console}/forms/form-builder.test.ts (100%) rename pkgs-ts/tests/{tests => console}/output/messages.test.ts (100%) rename pkgs-ts/tests/{tests => console}/output/status.test.ts (100%) rename pkgs-ts/tests/{tests => console}/prompts/prompts.test.ts (100%) rename pkgs-ts/tests/{tests => console}/rendering/opentui.test.ts (100%) rename pkgs-ts/tests/{tests => console}/support/scripted.ts (100%) diff --git a/.gitignore b/.gitignore index 1ea40b92..53224dfb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,26 @@ +# infra/.cache is the only mutable tool-cache root (see infra/README.md). +# Every cache/build artifact below is generated and deliberately ignored; +# nothing cache-related should ever live outside infra/.cache. node_modules/ + +# Tool caches & build output (all redirected into infra/.cache) .turbo/ **/.turbo/ .cache/ **/.cache/ infra/.cache/ -.DS_Store -.idea/ coverage/ *.tsbuildinfo -pkgs-ts/console/dist/ +**/dist/ +**/.vitepress/cache/ +**/.vitepress/dist/ apps/docs/src/.vitepress/ apps/docs/src/api/ +# OS / editor +.DS_Store +.idea/ + # Go pkgs-go/bin/ *.test diff --git a/apps/docs/package.json b/apps/docs/package.json index fdde6bd7..a1bf8f0d 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -5,9 +5,9 @@ "type": "module", "scripts": { "api": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright typedoc --options typedoc.json && cp src/api/README.md src/api/index.md", - "build": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress build src --config ../../vitepress/config.ts", - "dev": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress dev src --config ../../vitepress/config.ts --host 127.0.0.1", - "preview": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress preview src --config ../../vitepress/config.ts --host 127.0.0.1", + "build": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress build src --config ../vitepress/config.ts", + "dev": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright pnpm api && XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress dev src --config ../vitepress/config.ts --host 127.0.0.1", + "preview": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitepress preview src --config ../vitepress/config.ts --host 127.0.0.1", "test": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright vitest run --config vitest.config.ts", "typecheck": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.json --noEmit" }, diff --git a/apps/docs/tsconfig.json b/apps/docs/tsconfig.json index 976b3a39..76bc3e36 100644 --- a/apps/docs/tsconfig.json +++ b/apps/docs/tsconfig.json @@ -5,12 +5,12 @@ "paths": { "@docs/*": ["src/*"], "@docs-tests/*": ["tests/*"], - "@ollin/vitepress": ["../../vitepress/config.ts"], + "@ollin/vitepress": ["../vitepress/config.ts"], "@ollin/console": ["../../pkgs-ts/console/src/index.ts"], "#console/*": ["../../pkgs-ts/console/src/*"], "#console/prompts/*": ["../../pkgs-ts/console/src/prompts/*"] }, "tsBuildInfoFile": "../../infra/.cache/tsbuild/docs.tsbuildinfo" }, - "include": ["examples/**/*.ts", "tests/**/*.ts", "vitest.config.ts", "../../vitepress/config.ts", "../../pkgs-ts/console/src/**/*.ts"] + "include": ["examples/**/*.ts", "tests/**/*.ts", "vitest.config.ts", "../vitepress/config.ts", "../../pkgs-ts/console/src/**/*.ts"] } diff --git a/apps/docs/vitest.config.ts b/apps/docs/vitest.config.ts index 661a997c..15ae5838 100644 --- a/apps/docs/vitest.config.ts +++ b/apps/docs/vitest.config.ts @@ -9,7 +9,7 @@ const docsSourcePath = join(packagePath, 'src'); const cachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'docs'); const consoleSourcePath = join(workspacePath, 'pkgs-ts', 'console', 'src', 'index.ts'); const internalSourcePath = join(workspacePath, 'pkgs-ts', 'console', 'src', '$1'); -const vitepressConfigPath = join(workspacePath, 'vitepress', 'config.ts'); +const vitepressConfigPath = join(packagesPath, 'vitepress', 'config.ts'); const docsTestsPath = join(packagePath, 'tests'); export default defineConfig({ diff --git a/vitepress/components.json b/apps/vitepress/components.json similarity index 100% rename from vitepress/components.json rename to apps/vitepress/components.json diff --git a/vitepress/config.ts b/apps/vitepress/config.ts similarity index 96% rename from vitepress/config.ts rename to apps/vitepress/config.ts index 4b452b1d..bd689855 100644 --- a/vitepress/config.ts +++ b/apps/vitepress/config.ts @@ -6,7 +6,7 @@ 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('../infra/.cache/vitepress/docs', import.meta.url)); +const viteCachePath = fileURLToPath(new URL('../../infra/.cache/vitepress/docs', import.meta.url)); const tailwindPlugin = tailwindcss() as never; export const guideSections = [ diff --git a/vitepress/package.json b/apps/vitepress/package.json similarity index 82% rename from vitepress/package.json rename to apps/vitepress/package.json index 8f1fb54a..d01b5096 100644 --- a/vitepress/package.json +++ b/apps/vitepress/package.json @@ -7,7 +7,7 @@ ".": "./config.ts" }, "scripts": { - "typecheck": "XDG_CACHE_HOME=../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../infra/.cache/playwright tsc -p tsconfig.json --noEmit" + "typecheck": "XDG_CACHE_HOME=../../infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=../../infra/.cache/playwright tsc -p tsconfig.json --noEmit" }, "dependencies": { "@fontsource/geist-mono": "^5.2.8", diff --git a/vitepress/theme/components/TerminalOutput.vue b/apps/vitepress/theme/components/TerminalOutput.vue similarity index 100% rename from vitepress/theme/components/TerminalOutput.vue rename to apps/vitepress/theme/components/TerminalOutput.vue diff --git a/vitepress/theme/components/ui/badge/Badge.vue b/apps/vitepress/theme/components/ui/badge/Badge.vue similarity index 100% rename from vitepress/theme/components/ui/badge/Badge.vue rename to apps/vitepress/theme/components/ui/badge/Badge.vue diff --git a/vitepress/theme/components/ui/badge/index.ts b/apps/vitepress/theme/components/ui/badge/index.ts similarity index 100% rename from vitepress/theme/components/ui/badge/index.ts rename to apps/vitepress/theme/components/ui/badge/index.ts diff --git a/vitepress/theme/components/ui/badge/variants.ts b/apps/vitepress/theme/components/ui/badge/variants.ts similarity index 100% rename from vitepress/theme/components/ui/badge/variants.ts rename to apps/vitepress/theme/components/ui/badge/variants.ts diff --git a/vitepress/theme/components/ui/card/Card.vue b/apps/vitepress/theme/components/ui/card/Card.vue similarity index 100% rename from vitepress/theme/components/ui/card/Card.vue rename to apps/vitepress/theme/components/ui/card/Card.vue diff --git a/vitepress/theme/components/ui/card/CardAction.vue b/apps/vitepress/theme/components/ui/card/CardAction.vue similarity index 100% rename from vitepress/theme/components/ui/card/CardAction.vue rename to apps/vitepress/theme/components/ui/card/CardAction.vue diff --git a/vitepress/theme/components/ui/card/CardContent.vue b/apps/vitepress/theme/components/ui/card/CardContent.vue similarity index 100% rename from vitepress/theme/components/ui/card/CardContent.vue rename to apps/vitepress/theme/components/ui/card/CardContent.vue diff --git a/vitepress/theme/components/ui/card/CardDescription.vue b/apps/vitepress/theme/components/ui/card/CardDescription.vue similarity index 100% rename from vitepress/theme/components/ui/card/CardDescription.vue rename to apps/vitepress/theme/components/ui/card/CardDescription.vue diff --git a/vitepress/theme/components/ui/card/CardFooter.vue b/apps/vitepress/theme/components/ui/card/CardFooter.vue similarity index 100% rename from vitepress/theme/components/ui/card/CardFooter.vue rename to apps/vitepress/theme/components/ui/card/CardFooter.vue diff --git a/vitepress/theme/components/ui/card/CardHeader.vue b/apps/vitepress/theme/components/ui/card/CardHeader.vue similarity index 100% rename from vitepress/theme/components/ui/card/CardHeader.vue rename to apps/vitepress/theme/components/ui/card/CardHeader.vue diff --git a/vitepress/theme/components/ui/card/CardTitle.vue b/apps/vitepress/theme/components/ui/card/CardTitle.vue similarity index 100% rename from vitepress/theme/components/ui/card/CardTitle.vue rename to apps/vitepress/theme/components/ui/card/CardTitle.vue diff --git a/vitepress/theme/components/ui/card/index.ts b/apps/vitepress/theme/components/ui/card/index.ts similarity index 100% rename from vitepress/theme/components/ui/card/index.ts rename to apps/vitepress/theme/components/ui/card/index.ts diff --git a/vitepress/theme/components/ui/separator/Separator.vue b/apps/vitepress/theme/components/ui/separator/Separator.vue similarity index 100% rename from vitepress/theme/components/ui/separator/Separator.vue rename to apps/vitepress/theme/components/ui/separator/Separator.vue diff --git a/vitepress/theme/components/ui/separator/index.ts b/apps/vitepress/theme/components/ui/separator/index.ts similarity index 100% rename from vitepress/theme/components/ui/separator/index.ts rename to apps/vitepress/theme/components/ui/separator/index.ts diff --git a/vitepress/theme/index.ts b/apps/vitepress/theme/index.ts similarity index 100% rename from vitepress/theme/index.ts rename to apps/vitepress/theme/index.ts diff --git a/vitepress/theme/lib/utils.ts b/apps/vitepress/theme/lib/utils.ts similarity index 100% rename from vitepress/theme/lib/utils.ts rename to apps/vitepress/theme/lib/utils.ts diff --git a/vitepress/theme/styles.css b/apps/vitepress/theme/styles.css similarity index 100% rename from vitepress/theme/styles.css rename to apps/vitepress/theme/styles.css diff --git a/vitepress/tsconfig.json b/apps/vitepress/tsconfig.json similarity index 82% rename from vitepress/tsconfig.json rename to apps/vitepress/tsconfig.json index d9285a84..e753fe3c 100644 --- a/vitepress/tsconfig.json +++ b/apps/vitepress/tsconfig.json @@ -8,7 +8,7 @@ "@docs-theme/*": ["theme/*"], "@docs-ui/*": ["theme/components/ui/*"] }, - "tsBuildInfoFile": "../infra/.cache/tsbuild/vitepress.tsbuildinfo" + "tsBuildInfoFile": "../../infra/.cache/tsbuild/vitepress.tsbuildinfo" }, "include": ["config.ts", "theme/**/*.ts", "vue.d.ts"] } diff --git a/vitepress/vue.d.ts b/apps/vitepress/vue.d.ts similarity index 100% rename from vitepress/vue.d.ts rename to apps/vitepress/vue.d.ts diff --git a/infra/README.md b/infra/README.md index d7b39bce..3dc18dd5 100644 --- a/infra/README.md +++ b/infra/README.md @@ -10,6 +10,10 @@ the public package runtime: `@ollin/console-infra/tsconfig/*.json` exports. - `make` holds the modular Makefile. The repo-root `Makefile` is a transparent forwarder into `infra/make/Makefile`. +- `scripts/run-turbo.mjs` is the single entry point for workspace turbo tasks + (`build`, `test`, `typecheck`). It points turbo's cache, logs, and XDG/Playwright + env at `infra/.cache`, then deletes the per-package `.turbo/turbo-.log` + dirs turbo writes into each workspace (turbo offers no flag to relocate those). - `.cache` is the only mutable tool-cache root for workspace commands. Cache buckets are named by tool: diff --git a/infra/make/fresh.mk b/infra/make/fresh.mk index 8d9c5059..cb42b43b 100644 --- a/infra/make/fresh.mk +++ b/infra/make/fresh.mk @@ -15,7 +15,8 @@ fresh: ## Clean generated state, reinstall dependencies, then build "$(ROOT_PATH)/apps/docs/src/.vitepress/cache" \ "$(ROOT_PATH)/apps/docs/src/.vitepress/dist" \ "$(ROOT_PATH)/apps/docs/src/api" \ - "$(ROOT_PATH)/pkgs-ts/console/dist" + "$(ROOT_PATH)/pkgs-ts/console/dist" \ + "$(ROOT_PATH)/pkgs-ts/infra" $(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)/infra/.cache" -prune -o -type d -name '.cache' -prune -exec rm -rf {} + diff --git a/infra/scripts/run-turbo.mjs b/infra/scripts/run-turbo.mjs new file mode 100644 index 00000000..81b59fcc --- /dev/null +++ b/infra/scripts/run-turbo.mjs @@ -0,0 +1,91 @@ +// Single entry point for workspace turbo tasks. +// +// Turbo writes its content cache wherever `--cache-dir` points (we send it to +// infra/.cache/turbo), but it ALSO drops a per-package `.turbo/turbo-.log` +// into every workspace dir and offers no flag to relocate those. This runner +// centralizes the cache env/flags in one place and deletes the stray `.turbo` +// dirs after the run so `infra/.cache` stays the only cache root on disk. +// +// Usage: node infra/scripts/run-turbo.mjs [outputLogs] +// turbo task to run (build | test | typecheck) +// [outputLogs] value for --output-logs (default: none) + +import { spawnSync } from 'node:child_process'; +import { existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const infraRoot = resolve(scriptDir, '..'); +const repoRoot = resolve(infraRoot, '..'); +const cacheRoot = resolve(infraRoot, '.cache'); + +const turboCache = join(cacheRoot, 'turbo'); +const task = process.argv[2]; +const outputLogs = process.argv[3] ?? 'none'; + +if (!task) { + console.error('run-turbo: missing task name (build | test | typecheck)'); + process.exit(2); +} + +// Skip node_modules/.git when hunting for stray .turbo dirs; never matches the +// real cache bucket, which is named `turbo` (no dot) under infra/.cache. +const PRUNE = new Set(['node_modules', '.git']); + +function removeStrayTurboDirs(dir) { + let entries; + try { + entries = readdirSync(dir, { withFileTypes: true }); + } catch { + return; + } + for (const entry of entries) { + if (!entry.isDirectory()) { + continue; + } + if (entry.name === '.turbo') { + rmSync(join(dir, entry.name), { recursive: true, force: true }); + continue; + } + if (PRUNE.has(entry.name)) { + continue; + } + removeStrayTurboDirs(join(dir, entry.name)); + } +} + +mkdirSync(join(turboCache, 'logs'), { recursive: true }); + +const turboBin = join(repoRoot, 'node_modules', '.bin', 'turbo'); +const command = existsSync(turboBin) ? turboBin : 'turbo'; + +let exitCode = 1; +try { + const result = spawnSync( + command, + [ + 'run', + task, + '--cache-dir', + turboCache, + '--log-file', + join(turboCache, 'logs', `${task}.json`), + `--output-logs=${outputLogs}`, + ], + { + cwd: repoRoot, + stdio: 'inherit', + env: { + ...process.env, + XDG_CACHE_HOME: join(cacheRoot, 'xdg'), + PLAYWRIGHT_BROWSERS_PATH: join(cacheRoot, 'playwright'), + }, + }, + ); + exitCode = result.status ?? 1; +} finally { + removeStrayTurboDirs(repoRoot); +} + +process.exit(exitCode); diff --git a/package.json b/package.json index f0c55e02..04c1bd55 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,12 @@ "private": true, "type": "module", "scripts": { - "build": "XDG_CACHE_HOME=infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=infra/.cache/playwright turbo run build --cache-dir infra/.cache/turbo --log-file infra/.cache/turbo/logs/build.json --output-logs=none", + "build": "node infra/scripts/run-turbo.mjs build none", "dev": "make dev", "format": "make format", "format-all": "make format-all", - "test": "XDG_CACHE_HOME=infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=infra/.cache/playwright turbo run test --cache-dir infra/.cache/turbo --log-file infra/.cache/turbo/logs/test.json --output-logs=full", - "typecheck": "XDG_CACHE_HOME=infra/.cache/xdg PLAYWRIGHT_BROWSERS_PATH=infra/.cache/playwright turbo run typecheck --cache-dir infra/.cache/turbo --log-file infra/.cache/turbo/logs/typecheck.json --output-logs=none" + "test": "node infra/scripts/run-turbo.mjs test full", + "typecheck": "node infra/scripts/run-turbo.mjs typecheck none" }, "devDependencies": { "@ollin/console-infra": "workspace:*", diff --git a/pkgs-ts/tests/tests/distribution/package.test.ts b/pkgs-ts/tests/console/distribution/package.test.ts similarity index 88% rename from pkgs-ts/tests/tests/distribution/package.test.ts rename to pkgs-ts/tests/console/distribution/package.test.ts index ff9943d4..5ebb2ff9 100644 --- a/pkgs-ts/tests/tests/distribution/package.test.ts +++ b/pkgs-ts/tests/console/distribution/package.test.ts @@ -4,11 +4,13 @@ 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 = dirname(dirname(testPath)); -const packagesPath = dirname(acceptancePath); -const workspacePath = dirname(packagesPath); -const acceptanceCachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'tests'); +const testDirectoryPath = dirname(fileURLToPath(import.meta.url)); // .../tests/console/distribution +const suitePath = dirname(testDirectoryPath); // .../tests/console +const testsPackagePath = dirname(suitePath); // .../tests (consumer package) +const pkgsTsPath = dirname(testsPackagePath); // .../pkgs-ts +const consolePackagePath = join(pkgsTsPath, 'console'); // .../pkgs-ts/console (@ollin/console) +const workspacePath = dirname(pkgsTsPath); // .../tui (pnpm workspace root) +const consumerCachePath = join(workspacePath, 'infra', '.cache', 'vitest', 'tests'); describe('package consumption', () => { it('imports the built public entrypoint through ESM package resolution', () => { @@ -21,7 +23,7 @@ describe('package consumption', () => { process.execPath, ['--input-type=module', '-e', "const module = await import('@ollin/console'); console.log([typeof module.text, typeof module.table, typeof module.stream].join(','));"], { - cwd: acceptancePath, + cwd: testsPackagePath, encoding: 'utf8', }, ); @@ -123,7 +125,7 @@ describe('package consumption', () => { `, ], { - cwd: acceptancePath, + cwd: testsPackagePath, encoding: 'utf8', }, ); @@ -137,7 +139,7 @@ describe('package consumption', () => { stdio: 'pipe', }); - const typecheckCachePath = join(acceptanceCachePath, 'types'); + const typecheckCachePath = join(consumerCachePath, 'types'); mkdirSync(typecheckCachePath, { recursive: true }); @@ -147,7 +149,7 @@ describe('package consumption', () => { try { mkdirSync(packageScopeDirectory, { recursive: true }); - symlinkSync(join(packagesPath, 'console'), join(packageScopeDirectory, 'console'), 'dir'); + symlinkSync(consolePackagePath, join(packageScopeDirectory, 'console'), 'dir'); writeFileSync( consumerPath, ` @@ -214,7 +216,7 @@ describe('package consumption', () => { try { execFileSync('pnpm', ['exec', 'tsc', '--ignoreConfig', '--module', 'NodeNext', '--moduleResolution', 'NodeNext', '--target', 'ES2022', '--strict', '--noEmit', consumerPath], { - cwd: acceptancePath, + cwd: testsPackagePath, stdio: 'pipe', }); } catch (error) { diff --git a/pkgs-ts/tests/tests/forms/form-builder.test.ts b/pkgs-ts/tests/console/forms/form-builder.test.ts similarity index 100% rename from pkgs-ts/tests/tests/forms/form-builder.test.ts rename to pkgs-ts/tests/console/forms/form-builder.test.ts diff --git a/pkgs-ts/tests/tests/output/messages.test.ts b/pkgs-ts/tests/console/output/messages.test.ts similarity index 100% rename from pkgs-ts/tests/tests/output/messages.test.ts rename to pkgs-ts/tests/console/output/messages.test.ts diff --git a/pkgs-ts/tests/tests/output/status.test.ts b/pkgs-ts/tests/console/output/status.test.ts similarity index 100% rename from pkgs-ts/tests/tests/output/status.test.ts rename to pkgs-ts/tests/console/output/status.test.ts diff --git a/pkgs-ts/tests/tests/prompts/prompts.test.ts b/pkgs-ts/tests/console/prompts/prompts.test.ts similarity index 100% rename from pkgs-ts/tests/tests/prompts/prompts.test.ts rename to pkgs-ts/tests/console/prompts/prompts.test.ts diff --git a/pkgs-ts/tests/tests/rendering/opentui.test.ts b/pkgs-ts/tests/console/rendering/opentui.test.ts similarity index 100% rename from pkgs-ts/tests/tests/rendering/opentui.test.ts rename to pkgs-ts/tests/console/rendering/opentui.test.ts diff --git a/pkgs-ts/tests/tests/support/scripted.ts b/pkgs-ts/tests/console/support/scripted.ts similarity index 100% rename from pkgs-ts/tests/tests/support/scripted.ts rename to pkgs-ts/tests/console/support/scripted.ts diff --git a/pkgs-ts/tests/tsconfig.json b/pkgs-ts/tests/tsconfig.json index 5a1314c1..5e439ab0 100644 --- a/pkgs-ts/tests/tsconfig.json +++ b/pkgs-ts/tests/tsconfig.json @@ -8,5 +8,5 @@ "#console/prompts/*": ["console/src/prompts/*"] } }, - "include": ["tests/**/*.ts", "vitest.config.ts", "../console/src/**/*.ts"] + "include": ["**/*.ts", "../console/src/**/*.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1184d58c..bc304c89 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,7 +31,7 @@ importers: version: link:../../pkgs-ts/console '@ollin/vitepress': specifier: workspace:* - version: link:../../vitepress + version: link:../vitepress devDependencies: '@ollin/console-infra': specifier: workspace:* @@ -58,6 +58,55 @@ importers: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) + apps/vitepress: + dependencies: + '@fontsource/geist-mono': + specifier: ^5.2.8 + version: 5.2.8 + '@fontsource/geist-sans': + specifier: ^5.2.5 + version: 5.2.5 + '@vueuse/core': + specifier: ^14.3.0 + version: 14.3.0(vue@3.5.38(typescript@6.0.3)) + '@xterm/xterm': + specifier: ^6.0.0 + version: 6.0.0 + reka-ui: + specifier: ^2.9.10 + version: 2.9.10(vue@3.5.38(typescript@6.0.3)) + devDependencies: + '@ollin/console-infra': + specifier: workspace:* + version: link:../../infra + '@tailwindcss/vite': + specifier: ^4.3.0 + version: 4.3.0(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) + '@types/node': + specifier: ^25.6.2 + version: 25.9.2 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + tailwind-merge: + specifier: ^3.6.0 + version: 3.6.0 + tailwindcss: + specifier: ^4.3.0 + version: 4.3.0 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vitepress: + specifier: ^1.6.4 + version: 1.6.4(@algolia/client-search@5.53.0)(@types/node@25.9.2)(lightningcss@1.32.0)(postcss@8.5.15)(search-insights@2.17.3)(typescript@6.0.3) + vue: + specifier: ^3.5.38 + version: 3.5.38(typescript@6.0.3) + infra: devDependencies: '@types/node': @@ -119,55 +168,6 @@ importers: specifier: ^4.1.5 version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) - vitepress: - dependencies: - '@fontsource/geist-mono': - specifier: ^5.2.8 - version: 5.2.8 - '@fontsource/geist-sans': - specifier: ^5.2.5 - version: 5.2.5 - '@vueuse/core': - specifier: ^14.3.0 - version: 14.3.0(vue@3.5.38(typescript@6.0.3)) - '@xterm/xterm': - specifier: ^6.0.0 - version: 6.0.0 - reka-ui: - specifier: ^2.9.10 - version: 2.9.10(vue@3.5.38(typescript@6.0.3)) - devDependencies: - '@ollin/console-infra': - specifier: workspace:* - version: link:../infra - '@tailwindcss/vite': - specifier: ^4.3.0 - version: 4.3.0(vite@8.0.16(@types/node@25.9.2)(jiti@2.7.0)(yaml@2.9.0)) - '@types/node': - specifier: ^25.6.2 - version: 25.9.2 - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - tailwind-merge: - specifier: ^3.6.0 - version: 3.6.0 - tailwindcss: - specifier: ^4.3.0 - version: 4.3.0 - typescript: - specifier: ^6.0.3 - version: 6.0.3 - vitepress: - specifier: ^1.6.4 - version: 1.6.4(@algolia/client-search@5.53.0)(@types/node@25.9.2)(lightningcss@1.32.0)(postcss@8.5.15)(search-insights@2.17.3)(typescript@6.0.3) - vue: - specifier: ^3.5.38 - version: 3.5.38(typescript@6.0.3) - packages: '@algolia/abtesting@1.19.0': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 639f1ff1..f4e426ac 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,7 +2,6 @@ packages: - "pkgs-ts/*" - "apps/*" - "pkgs-go" - - "vitepress" - "infra" allowBuilds: