[
  {
    "path": ".changeset/README.md",
    "content": "# Changesets\n\nHello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works\nwith multi-package repos, or single-package repos to help you version and publish your code. You can\nfind the full documentation for it [in our repository](https://github.com/changesets/changesets)\n\nWe have a quick list of common questions to get you started engaging with this project in\n[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)\n\nYou will be responsible for writing a **changeset** for your Astro PR. This is a Markdown file that states:\n\n- which repository has changed\n- the kind of change according to [Astro's semantic versioning](https://docs.astro.build/en/upgrade-astro/#semantic-versioning)\n- a message describing the change that will be publicly displayed on the repo's CHANGELOG\n\n```md title=\".changeset/my-super-cool-changeset.md\" wrap\n---\n\"astro\": patch\n---\n\nFixes unexpected `undefined` value when calling an action from the client without a return value\n```\n\nYou can generate a changeset using the `pnpm changeset` command, which will prompt you for the necessary information and create a randomly-named file in the `.changeset` folder. You can then edit the generated file to add more detail, or write your changeset from scratch.\n\n## Format\n\nBegin your changeset message with **a present tense verb** that completes a sentence in the style of: \"This PR . . .\" or \"This contribution ...\"\n\n- Adds\n- Removes\n- Fixes\n- Updates\n- Refactors\n- Improves\n- Deprecates\n\nFinish the introductory sentence with a message focusing on what has changed **about the codebase** (not what your feature itself does) that is meaningful to a **user** of Astro. It is usually more helpful to describe the change **as someone building an Astro site will experience it**, instead of describing **how you fixed it** or **what the code in the PR does**:\n\n```markdown title=\"changeset.md\" del={2} ins={5}\n// What the code now does\nLogs helpful errors if content is invalid\n\n// The nature of the change to the Astro code base\nAdds logging for content collections configuration errors.\n```\n\nYou may then include additional paragraphs if necessary to describe the change in more detail. This may not be needed for a small bug fix, but is often helpful if the reader must make a change to their own code, or needs to understand how the change might affect them.\n\nThe level of detail of a changeset depends on the type of change (e.g. `patch` vs `minor`, breaking or not, only affects integration authors etc.) You may also use [`<h4>` - `<h6>` Markdown headings](#using-markdown-section-headings) to break your longer content into sections.\n\n:::tip[Don't hide the good stuff in the changeset!]\nCHANGELOGS are often read only once, when someone is updating to the latest version of a package. Documentation is a constant reference that will be revisited and consulted frequently.\n\nMake sure that the helpful explanations and examples for your fellow developers in both your changeset and your PR description are captured in the actual feature documentation, too!\n:::\n\n### Patch updates\n\nThese updates are often fixes, refactors or other small improvements. They are typically not user-facing, and do not require someone to update their own project code.\n\nVerbs like \"fixes\" and \"refactors\" are helpful to let readers know this is an internal or implementation change that they do not need to worry about. At the same time, these messages are helpful to someone who is interested in keeping up with small changes to the codebase.\n\nOften one line is enough to describe your change meaningfully to an Astro user:\n\n```md title=\"my-patch-changeset.md\" wrap\n---\n\"astro\": patch\n---\n\nFixes a bug where the toolbar audit would incorrectly flag images as above the fold\n```\n\n```md title=\"my-patch-changeset.md\" wrap\n---\n\"astro\": patch\n---\n\nRefactors internal handling of styles and scripts for content collections to improve build performance\n```\n\n```md title=\"my-patch-changeset.md\" wrap\n---\n\"astro\": patch\n---\n\nUpdates the `HTMLAttributes` type exported from `astro` to allow data attributes\n```\n\nThese do not need to be full sentences and do not need end punctuation unless you write multiple sentences.\n\n:::tip[Help your reader figure out if this is change important to them]\nEven though these are small changes described by very short sentences, they still need to communicate a lot!\n\nCheck that you have clearly stated not just **what has changed** but also **who needs to know**. If your reader can identify that a change is important to them, they can always seek out further information if they need to know more.\n:::\n\n#### Tips and Examples\n\nFor a great changeset message:\n\nInclude the specific API changed (using inline code highlighting as appropriate) when your change might not be easy to identify so that your reader can easily tell whether it's something they are using and need to care about:\n\n> Improves automatic fallbacks generation\n>\n> vs\n>\n> ✅ Improves automatic `fallbacks` generation **for the experimental Fonts API**\n\nWhen the specific API change is not user-facing (e.g. a type not publicly exposed) and/or your reader will not recognize it by name, describe the use case or end result that will be meaningful to the reader instead:\n\n> Adds `| (string & {})` for better autocomplete of `App.SessionData`\n>\n> vs\n>\n> ✅ Improves autocompletion for session keys\n\n### New features\n\nBegin your changeset with \"Adds\" to alert readers that there is something new and mention the names of any new items (options, functions) that have been added directly in the first sentence:\n\n```md title=\"my-minor-changeset.md\" wrap\n---\n\"astro\": minor\n---\n\nAdds a new `flamethrow` view transitions animation\n\n<!-- -->\n```\n\nAdditionally, describe what people are now able to do because of these additions that they could not before.\n\nThe changeset is an opportunity to call people's attention to new things they might wish to try in their Astro project, and may include a code example showing basic usage of the new feature:\n\n````md wrap title=\"my-minor-changeset.md\"\n---\n\"astro\": minor\n---\n\nAdds a new, optional property `timeout` for the `client:idle` directive\n\nThis value allows you to specify a maximum time to wait, in milliseconds, before hydrating a UI framework component, even if the page is not yet done with its initial load.\n\nThis means you can delay hydration for lower-priority UI elements with more control to ensure your element is interactive within a specified time frame.\n\n```\n<Button client:idle={{ timeout: 500 }} />\n```\n````\n\nYou can also use [`<h4>` - `<h6>` Markdown headings](#using-markdown-section-headings) to break your longer content into sections.\n\n### Breaking changes\n\nChangesets focus on what has changed, and **must include any breaking changes**, including changes to default behavior. Most users will have several default settings configured (often by not setting any value themselves), so changes to defaults can have a significant impact on someone's project!\n\nVerbs like \"removes\", \"changes\", and \"deprecates\" call attention to something that might require attention. Unlike a new feature someone can choose not to use, changing default or expected behavior cannot be ignored.\n\nYou can also use [`<h4>` - `<h6>` Markdown headings](#using-markdown-section-headings) to break your content into sections, for example, to add headings like, \"What should I do?\" or \"Migrating from the previous version.\"\n\n```md title=\"my-major-changeset.md\" wrap\n---\n\"astro\": major\n---\n\nRemoves support for returning simple objects from endpoints. You must now return a `Response` instead.\n```\n\nChangeset messages for breaking changes must also provide clear guidance for updating. Diff code samples are encouraged when appropriate:\n\n````md title=\"my-major-changeset.md\" wrap\n---\n\"astro\": major\n---\n\nRemoves support for Shiki custom language's `path` property. The language JSON file must now be imported and passed to the option instead.\n\n```diff\n// astro.config.js\n+ import customLang from './custom.tmLanguage.json'\n\nexport default defineConfig({\n  markdown: {\n    shikiConfig: {\n      langs: [\n-       { path: './custom.tmLanguage.json' },\n+       customLang,\n      ],\n    },\n  },\n})\n```\n````\n\nIf your contribution changes a default value, then it is helpful to describe how to revert back to the previous behavior. Readers may also appreciate being informed that they can remove configuration that is no longer needed.\n\n````md title=\"my-major-changeset.md\" wrap\n---\n\"astro\": major\n---\n\nChanges the default value of `security.checkOrigin` to true, which now enables Cross-Site Request Forgery (CSRF) protection by default for pages rendered on demand.\n\nIf you had previously configured `security.checkOrigin: true`, you no longer need this set in your Astro config. This is now the default and it is safe to remove.\n\nTo revert to the previous default behavior and opt out of automatically checking that the “origin” header matches the URL sent by each request, you must now explicitly set `security.checkOrigin: false`:\n\n```diff\nexport default defineConfig({\n+  security: {\n+    checkOrigin: false\n+  }\n})\n```\n````\n\n## Using Markdown section headings\n\nFor longer descriptions that you want to split into sections, always start at the `<h4>` level, using `####` where you would normally use `##` in a regular Markdown post. This ensures readability when your message is incorporated into the final CHANGELOG:\n\n```md wrap title=\"my-long-changeset-with-sections.md\"\n---\n\"astro\": minor\n---\n\nAdds a new Sessions API to store user state between requests for on-demand rendered pages.\n\n#### Configuring session storage\n\n<!-- ... -->\n\n#### Using sessions\n\n<!-- ... -->\n\n##### In `.astro` pages\n\n<!-- ... -->\n\n##### In API endpoints\n\n<!-- ... -->\n\n#### Upgrading from the experimental API\n\n<!-- ... -->\n```\n"
  },
  {
    "path": ".changeset/afraid-donkeys-sin.md",
    "content": "---\n\"@clack/prompts\": minor\n\"@clack/core\": minor\n---\n\nExternalize `fast-string-width` and `fast-wrap-ansi` to avoid double dependencies\n"
  },
  {
    "path": ".changeset/big-pants-invite.md",
    "content": "---\n\"@clack/prompts\": patch\n---\n\nFix the `path` prompt so `directory: true` correctly enforces directory-only selection while still allowing directory navigation, and add regression tests for both directory and default file selection behavior.\n"
  },
  {
    "path": ".changeset/config.json",
    "content": "{\n  \"$schema\": \"https://unpkg.com/@changesets/config@2.3.0/schema.json\",\n  \"changelog\": \"@changesets/cli/changelog\",\n  \"commit\": false,\n  \"fixed\": [],\n  \"linked\": [],\n  \"access\": \"public\",\n  \"baseBranch\": \"main\",\n  \"updateInternalDependencies\": \"patch\",\n  \"ignore\": [\"@example/*\"]\n}\n"
  },
  {
    "path": ".changeset/dirty-actors-find.md",
    "content": "---\n\"@clack/prompts\": patch\n\"@clack/core\": patch\n---\n\nAdds `placeholder` option to `autocomplete`. When the placeholder is set and the input is empty, pressing `tab` will set the value to `placeholder`.\n\n"
  },
  {
    "path": ".changeset/tangy-mirrors-hug.md",
    "content": "---\n\"@clack/prompts\": minor\n\"@clack/core\": minor\n---\n\nAdds `date` prompt with `format` support (YMD, MDY, DMY)\n"
  },
  {
    "path": ".changeset/tricky-states-tease.md",
    "content": "---\n\"@clack/prompts\": patch\n---\n\nFix `path` directory mode so pressing Enter with an existing directory `initialValue` submits that current directory instead of the first child option, and add regression coverage for immediate submit and child-directory navigation.\n"
  },
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.{yml,json,yaml}]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: '[Bug] '\nlabels: bug\nassignees: ''\n---\n\n**Environment**\n\n- OS: [e.g. macOS, Windows]\n- Node Version: [e.g. v18.14.0]\n- Package: [e.g. `@clack/prompts`, `@clack/core`]\n- Package Version: [e.g. v0.2.0]\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nInclude a link to a minimal reproduction using [`node.new`](https://node.new/)\n\nSteps to reproduce the behavior:\n\n- Include reproduction steps\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Additional Information**\nIf applicable, add screenshots to help explain your problem.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: '[Request]'\nlabels: enhancement\nassignees: ''\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n\n# Automatically cancel in-progress actions on the same branch\nconcurrency:\n  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}\n  cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}\n\njobs:\n  scripts:\n    if: github.repository_owner == 'bombshell-dev'\n    uses: bombshell-dev/automation/.github/workflows/run.yml@main\n    secrets: inherit\n    with:\n      commands: >\n        [\n          \"build\",\n          \"types\",\n          \"test\",\n          \"deps\"\n        ]\n"
  },
  {
    "path": ".github/workflows/detect-agent.yml",
    "content": "name: Detect Agent\n\non:\n  pull_request_target:\n    types: [opened]\n  workflow_dispatch: {}\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  detect:\n    if: github.event_name != 'workflow_dispatch'\n    uses: bombshell-dev/automation/.github/workflows/detect-agent.yml@main\n\n  backfill:\n    if: github.event_name == 'workflow_dispatch'\n    uses: bombshell-dev/automation/.github/workflows/detect-agent-backfill.yml@main\n"
  },
  {
    "path": ".github/workflows/format.yml",
    "content": "name: Format\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - main\n\njobs:\n  format:\n    if: github.repository_owner == 'bombshell-dev'\n    uses: bombshell-dev/automation/.github/workflows/format.yml@main\n    permissions:\n      contents: write\n      pull-requests: write\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/issue.yml",
    "content": "name: issue\n\non:\n  issues:\n    types: [opened, edited, labeled, reopened]\n\njobs:\n  backlog:\n    if: github.event.action == 'edited' || github.event.action == 'labeled'\n    uses: bombshell-dev/automation/.github/workflows/move-issue-to-backlog.yml@main\n    secrets: inherit\n\n  project:\n    if: github.event.action == 'opened' || github.event.action == 'reopened'\n    uses: bombshell-dev/automation/.github/workflows/add-issue-to-project.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/preview.yml",
    "content": "name: Preview\n\non:\n  push:\n    branches:\n      - main\n  pull_request:\n  workflow_dispatch:\n\n\njobs:\n  preview:\n    if: github.repository_owner == 'bombshell-dev'\n    uses: bombshell-dev/automation/.github/workflows/preview.yml@main\n    permissions: \n      contents: write\n      pull-requests: write\n      id-token: write\n    with:\n      publish: \"./packages/*\"\n      template: \"./examples/*\"\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Publish\n\non:\n  push:\n    branches: [main, v0]\n  workflow_dispatch:\n\npermissions:\n  id-token: write\n  contents: write\n  pull-requests: write\n  packages: write\n\njobs:\n  publish:\n    if: github.repository_owner == 'bombshell-dev'\n    uses: bombshell-dev/automation/.github/workflows/publish.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/require-allow-edits.yml",
    "content": "name: Require “Allow Edits”\n\non: [pull_request_target]\n\npermissions:\n  contents: read\n\njobs:\n  _:\n    permissions:\n      pull-requests: read\n\n    name: \"Require “Allow Edits”\"\n\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: ljharb/require-allow-edits@v2\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# JetBrains IDEA\n.idea\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n"
  },
  {
    "path": ".npmrc",
    "content": "# Important! Never install from registry even when new version is available\nprefer-workspace-packages=true\nlink-workspace-packages=true\nsave-workspace-protocol=false\nauto-install-peers=false\n"
  },
  {
    "path": ".nvmrc",
    "content": "20.18.1\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"typescript.tsdk\": \"node_modules/typescript/lib\"\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to Clack\n\nThank you for your interest in contributing to Clack! This document provides detailed instructions for setting up your development environment, navigating the codebase, making changes, and submitting contributions.\n\n> [!Tip]\n> **For new contributors:** Take a look at [https://github.com/firstcontributions/first-contributions](https://github.com/firstcontributions/first-contributions) for helpful information on contributing to open source projects.\n\n## Getting Started\n\n### Prerequisites\n\n- [Node.js](https://nodejs.org/) (version specified in `.nvmrc`, currently v20.18.1)\n- [pnpm](https://pnpm.io/) (version 9.14.2 or higher)\n\nIf you use [volta](https://volta.sh/) or [nvm](https://github.com/nvm-sh/nvm), the correct Node.js version will be automatically selected based on the project's `.nvmrc` file.\n\n### Local Development Setup\n\n1. **Fork the repository**:\n   - Visit [https://github.com/bombshell-dev/clack](https://github.com/bombshell-dev/clack)\n   - Click the \"Fork\" button in the top right\n   - Clone your fork to your local machine\n\n   ```bash\n   git clone https://github.com/YOUR_USERNAME/clack.git\n   cd clack\n   ```\n\n2. **Set up the upstream remote**:\n   ```bash\n   git remote add upstream https://github.com/bombshell-dev/clack.git\n   ```\n\n3. **Install dependencies**:\n   ```bash\n   pnpm install\n   ```\n\n4. **Build the packages**:\n   ```bash\n   pnpm build\n   ```\n\n5. **Run the development server**:\n   ```bash\n   pnpm dev\n   ```\n\n### Using Clack Packages in Your Own Projects During Development\n\nIf you want to test changes to Clack packages in your own project, you can use pnpm's linking capabilities:\n\n1. **Build the Clack packages locally first**:\n   ```bash\n   # In the clack repository\n   cd /path/to/clack\n   pnpm build\n   ```\n\n2. **Link the packages to your project using one of these methods**:\n\n   **Method 1: Using pnpm link**\n   ```bash\n   # In your project\n   cd /path/to/your-project\n   \n   # Link @clack/core\n   pnpm link --global /path/to/clack/packages/core\n   \n   # Link @clack/prompts\n   pnpm link --global /path/to/clack/packages/prompts\n   ```\n\n   **Method 2: Using local path in package.json**\n   \n   In your project's package.json, reference the local paths:\n   ```json\n   {\n     \"dependencies\": {\n       \"@clack/core\": \"file:/path/to/clack/packages/core\",\n       \"@clack/prompts\": \"file:/path/to/clack/packages/prompts\"\n     }\n   }\n   ```\n   Then run `pnpm install` in your project.\n\n3. **Watch for changes** (optional):\n   ```bash\n   # In the clack repository\n   cd /path/to/clack\n   pnpm build --watch\n   ```\n\n4. **Refresh after changes**:\n   If you're making changes to Clack while testing in your project, you'll need to rebuild Clack and potentially reinstall in your project:\n   ```bash\n   # In the clack repository\n   cd /path/to/clack\n   pnpm build\n   \n   # In your project (if using Method 2)\n   cd /path/to/your-project\n   pnpm install\n   ```\n\nWith this setup, you can develop and test your changes to Clack within the context of your own project. This is especially useful for implementing new features like filtering.\n\n## Repository Structure\n\nClack is organized as a monorepo using pnpm workspaces. Understanding the structure will help you navigate and contribute effectively:\n\n```\nclack/\n├── .changeset/         # Changeset files for versioning\n├── .github/            # GitHub workflows and templates\n├── examples/           # Example implementations of Clack\n├── packages/           # Core packages\n│   ├── core/           # Unstyled primitives (@clack/core)\n│   └── prompts/        # Ready-to-use components (@clack/prompts)\n├── biome.json          # Biome configuration\n├── package.json        # Root package.json\n├── pnpm-workspace.yaml # Workspace configuration\n└── tsconfig.json       # TypeScript configuration\n```\n\n### Key Packages\n\n1. **@clack/core** (`packages/core/`): \n   - Contains the unstyled, extensible primitives for building CLI applications\n   - The foundation layer that provides the core functionality\n\n2. **@clack/prompts** (`packages/prompts/`): \n   - Built on top of @clack/core\n   - Provides beautiful, ready-to-use CLI prompt components\n   - What most users will interact with directly\n\n### Examples\n\nThe `examples/` directory contains sample projects that demonstrate how to use Clack. Examining these examples is a great way to understand how the library works in practice.\n\n## Development Workflow\n\n### Common Commands\n\n- **Build all packages**: \n  ```bash\n  pnpm build\n  ```\n\n- **Start development environment**:\n  ```bash\n  pnpm dev\n  ```\n\n- **Run tests**:\n  ```bash\n  pnpm test\n  ```\n\n- **Lint code**:\n  ```bash\n  pnpm lint\n  ```\n\n- **Format code**:\n  ```bash\n  pnpm format\n  ```\n\n- **Type check**:\n  ```bash\n  pnpm run types\n  ```\n\n- **Build stubbed packages** (for faster development):\n  ```bash\n  pnpm stub\n  ```\n\n### Making Changes\n\n1. **Create a new branch**:\n   ```bash\n   git checkout -b my-feature-branch\n   ```\n\n2. **Implement your changes**:\n   - For bug fixes, start by reproducing the issue\n   - For new features, consider how it fits into the existing architecture\n   - Maintain type safety with TypeScript\n   - Add or update tests as necessary\n\n3. **Run local verification**:\n   ```bash\n   # Ensure everything builds\n   pnpm build\n   \n   # Check formatting and lint issues\n   pnpm format\n   pnpm lint\n   \n   # Verify type correctness\n   pnpm types\n   \n   # Run tests\n   pnpm test\n   ```\n\n4. **Create a changeset** (for changes that need versioning):\n   ```bash\n   pnpm changeset\n   ```\n   - Follow the prompts to select which packages have changed\n   - Choose the appropriate semver increment (patch, minor, major)\n   - Write a concise but descriptive message explaining the changes\n\n### Testing Your Changes\n\nFor testing changes to the core functionality:\n\n1. **Use the examples**:\n   ```bash\n   # Run an example to test your changes\n   pnpm --filter @example/changesets run start\n   ```\n\n2. **Create a test-specific example** (if needed):\n   - Add a new directory in the `examples/` folder\n   - Implement a minimal reproduction that uses your new feature/fix\n   - Run it with `pnpm --filter @example/your-example run start`\n\n### Debugging Tips\n\nWhen encountering issues during development:\n\n1. **Check for errors in the console** - Clack will often output helpful error messages\n2. **Review the API documentation** - Ensure you're using components and functions as intended\n3. **Look at existing examples** - See how similar features are implemented\n4. **Inspect the packages individually** - Sometimes issues are isolated to either `core` or `prompts`\n\n## Pull Request Process\n\n1. **Commit your changes**:\n   ```bash\n   git add .\n   git commit -m \"feat: add new awesome feature\"\n   ```\n\n2. **Push to your fork**:\n   ```bash\n   git push origin my-feature-branch\n   ```\n\n3. **Create a pull request**:\n   - Go to your fork on GitHub\n   - Click \"New pull request\"\n   - Select your branch and add a descriptive title\n   - Fill in the PR template with details about your changes\n   - Reference any related issues\n\n4. **Wait for the automated checks**:\n   - GitHub Actions will run tests, type checking, and lint validation\n   - Fix any issues that arise\n\n5. **Address review feedback**:\n   - Make requested changes\n   - Push additional commits to your branch\n   - The PR will update automatically\n\n### PR Previews\n\nClack uses [pkg.pr.new](https://pkg.pr.new) (provided by [bolt.new](https://bolt.new)) to create continuous preview releases of all PRs. This simplifies testing and makes verifying bug fixes easier for our dependents. \n\nThe workflow that builds a preview version and adds instructions for installation as a comment on your PR should run automatically if you have contributed to Clack before. First-time contributors may need to wait until a maintainer manually approves GitHub Actions running on your PR.\n\n## Release Process\n\nClack uses [Changesets](https://github.com/changesets/changesets) to manage versions and releases.\n\n1. **For contributors**:\n   - Create a changeset file with your PR as described above\n   - Maintainers will handle the actual release process\n\n2. **For maintainers**:\n   - Merging PRs with changesets will queue them for the next release\n   - When ready to release, merge the `[ci] release` PR\n\n### Backporting to v0 Branch\n\nClack maintains a stable `v0` branch alongside the main development branch. For maintainers who need to backport changes:\n\n1. Label PRs that should be backported with the `backport` label\n2. After the PR is merged to `main`, manually cherry-pick the squashed commit into the `v0` branch:\n   ```bash\n   # Ensure you have the latest v0 branch\n   git checkout v0\n   git pull upstream v0\n   \n   # Cherry-pick the squashed commit from main\n   git cherry-pick <commit-hash>\n   \n   # Push the changes\n   git push upstream v0\n   ```\n3. CI is configured to run changesets from the `v0` branch, so release PRs will be opened automatically\n\nThe GitHub Actions are configured to cut releases from both the `main` and `v0` branches.\n\n## Filing Issues\n\nWhen reporting bugs or requesting features:\n\n1. **Check existing issues** to avoid duplicates\n2. **Use the issue templates** to provide all necessary information\n3. **Be specific and clear** about what's happening and what you expect\n4. **Provide reproduction steps** - ideally a minimal example that demonstrates the issue\n5. **Include environment details** like OS, Node.js version, etc.\n\n### Issue Types\n\nWhen opening an issue, consider which category it falls into:\n\n- **Bug Report**: Something isn't working as documented or expected\n- **Feature Request**: A suggestion for new functionality\n- **Documentation Issue**: Improvements or corrections to documentation\n- **Performance Issue**: Problems with speed or resource usage\n\n## Style Guide\n\nWe use [Biome](https://biomejs.dev/) for linting and formatting. Your code should follow these standards:\n\n```bash\n# To check formatting\npnpm format\n\n# To lint and fix issues automatically where possible\npnpm lint\n```\n\nThe project follows standard TypeScript practices. If you're new to TypeScript:\n- Use precise types whenever possible\n- Avoid `any` unless absolutely necessary\n- Look at existing code for patterns to follow\n\n### Commit Message Format\n\nWe follow conventional commits for commit messages:\n\n- `feat:` - A new feature\n- `fix:` - A bug fix\n- `docs:` - Documentation changes\n- `style:` - Changes that don't affect code functionality (formatting, etc)\n- `refactor:` - Code changes that neither fix bugs nor add features\n- `perf:` - Performance improvements\n- `test:` - Adding or correcting tests\n- `chore:` - Changes to the build process, tools, etc\n\n## License\n\nBy contributing, you agree that your contributions will be licensed under the project's MIT License.\n\nThank you for taking the time to contribute to Clack! Feel free to join our community Discord at [bomb.sh/chat](https://bomb.sh/chat). It's a great place to connect with other project contributors—we're chill!\n\n## Acknowledgments\n\nThis contributing guide was inspired by and adapted from the [Astro Contributing Manual](https://github.com/withastro/astro/blob/main/CONTRIBUTING.md). We appreciate their excellent documentation and open source practices.\n"
  },
  {
    "path": "README.md",
    "content": "<br />\n<br />\n\n<div align=\"center\">\n    <img alt=\"Clack logo\" src=\"/.github/assets/clack.png?sanitize=true\" width=\"320\">\n</div>\n<h2 align=\"center\">stylish interactive prompts for JavaScript CLIs</h3>\n\n<h4 align=\"center\"><a href=\"packages/prompts#readme\"><code>@clack/prompts</code></a>: opinionated, ready-to-use prompt components</h4>\n\n<h4 align=\"center\"><a href=\"packages/core#readme\"><code>@clack/core</code></a>: headless, unstyled prompt primitives</h4>\n\n<br />\n<br />\n\n<h3 align=\"center\"><a href=\"https://bomb.sh/docs/clack/basics/getting-started/\">Read the docs</a></h3>\n"
  },
  {
    "path": "biome.json",
    "content": "{\n  \"$schema\": \"https://biomejs.dev/schemas/2.1.2/schema.json\",\n  \"vcs\": { \"enabled\": false, \"clientKind\": \"git\", \"useIgnoreFile\": false },\n  \"files\": { \"ignoreUnknown\": false, \"includes\": [\"**\", \"!**/dist/**\"] },\n  \"formatter\": {\n    \"enabled\": true,\n    \"useEditorconfig\": true,\n    \"formatWithErrors\": false,\n    \"indentStyle\": \"tab\",\n    \"indentWidth\": 2,\n    \"lineEnding\": \"lf\",\n    \"lineWidth\": 100,\n    \"attributePosition\": \"auto\",\n    \"bracketSpacing\": true,\n    \"includes\": [\n      \"**\",\n      \"!**/.github/workflows/**/*.yml\",\n      \"!**/.changeset/**/*.md\",\n      \"!**/pnpm-lock.yaml\",\n      \"!**/package.json\"\n    ]\n  },\n  \"assist\": { \"actions\": { \"source\": { \"organizeImports\": \"on\" } } },\n  \"linter\": {\n    \"enabled\": true,\n    \"rules\": { \"recommended\": true, \"suspicious\": { \"noExplicitAny\": \"off\" } }\n  },\n  \"javascript\": {\n    \"formatter\": {\n      \"jsxQuoteStyle\": \"double\",\n      \"quoteProperties\": \"asNeeded\",\n      \"trailingCommas\": \"es5\",\n      \"semicolons\": \"always\",\n      \"arrowParentheses\": \"always\",\n      \"bracketSameLine\": false,\n      \"quoteStyle\": \"single\",\n      \"attributePosition\": \"auto\",\n      \"bracketSpacing\": true\n    }\n  },\n  \"overrides\": [\n    {\n      \"includes\": [\"**/*.json\", \"**/*.toml\", \"**/*.yml\"],\n      \"formatter\": { \"indentStyle\": \"space\" }\n    }\n  ]\n}\n"
  },
  {
    "path": "build.preset.ts",
    "content": "import { definePreset } from 'unbuild';\n\n// @see https://github.com/unjs/unbuild\nexport default definePreset({\n\tclean: true,\n\tdeclaration: 'node16',\n\tsourcemap: true,\n\trollup: {\n\t\temitCJS: false,\n\t\tinlineDependencies: true,\n\t\tesbuild: {\n\t\t\tminify: true,\n\t\t},\n\t},\n});\n"
  },
  {
    "path": "examples/basic/autocomplete-multiselect.ts",
    "content": "import * as p from '@clack/prompts';\nimport color from 'picocolors';\n\n/**\n * Example demonstrating the integrated autocomplete multiselect component\n * Which combines filtering and selection in a single interface\n */\n\nasync function main() {\n\tconsole.clear();\n\n\tp.intro(`${color.bgCyan(color.black(' Integrated Autocomplete Multiselect Example '))}`);\n\n\tp.note(\n\t\t`\n${color.cyan('Filter and select multiple items in a single interface:')}\n- ${color.yellow('Type')} to filter the list in real-time\n- Use ${color.yellow('up/down arrows')} to navigate with improved stability\n- Press ${color.yellow('Space')} to select/deselect the highlighted item ${color.green('(multiple selections allowed)')}\n- Use ${color.yellow('Backspace')} to modify your filter text when searching for different options\n- Press ${color.yellow('Enter')} when done selecting all items\n- Press ${color.yellow('Ctrl+C')} to cancel\n  `,\n\t\t'Instructions'\n\t);\n\n\t// Frameworks in alphabetical order\n\tconst frameworks = [\n\t\t{ value: 'angular', label: 'Angular', hint: 'Frontend/UI' },\n\t\t{ value: 'django', label: 'Django', hint: 'Python Backend' },\n\t\t{ value: 'dotnet', label: '.NET Core', hint: 'C# Backend' },\n\t\t{ value: 'electron', label: 'Electron', hint: 'Desktop' },\n\t\t{ value: 'express', label: 'Express', hint: 'Node.js Backend' },\n\t\t{ value: 'flask', label: 'Flask', hint: 'Python Backend' },\n\t\t{ value: 'flutter', label: 'Flutter', hint: 'Mobile' },\n\t\t{ value: 'laravel', label: 'Laravel', hint: 'PHP Backend' },\n\t\t{ value: 'nestjs', label: 'NestJS', hint: 'Node.js Backend' },\n\t\t{ value: 'nextjs', label: 'Next.js', hint: 'React Framework' },\n\t\t{ value: 'nuxt', label: 'Nuxt.js', hint: 'Vue Framework' },\n\t\t{ value: 'rails', label: 'Ruby on Rails', hint: 'Ruby Backend' },\n\t\t{ value: 'react', label: 'React', hint: 'Frontend/UI' },\n\t\t{ value: 'reactnative', label: 'React Native', hint: 'Mobile' },\n\t\t{ value: 'spring', label: 'Spring Boot', hint: 'Java Backend' },\n\t\t{ value: 'svelte', label: 'Svelte', hint: 'Frontend/UI' },\n\t\t{ value: 'tauri', label: 'Tauri', hint: 'Desktop' },\n\t\t{ value: 'vue', label: 'Vue.js', hint: 'Frontend/UI' },\n\t];\n\n\t// Use the new integrated autocompleteMultiselect component\n\tconst result = await p.autocompleteMultiselect<string>({\n\t\tmessage: 'Select frameworks (type to filter)',\n\t\toptions: frameworks,\n\t\tplaceholder: 'Type to filter...',\n\t\tmaxItems: 8,\n\t});\n\n\tif (p.isCancel(result)) {\n\t\tp.cancel('Operation cancelled.');\n\t\tprocess.exit(0);\n\t}\n\n\t// Type guard: if not a cancel symbol, result must be a string array\n\tfunction isStringArray(value: unknown): value is string[] {\n\t\treturn Array.isArray(value) && value.every((item) => typeof item === 'string');\n\t}\n\n\t// We can now use the type guard to ensure type safety\n\tif (!isStringArray(result)) {\n\t\tthrow new Error('Unexpected result type');\n\t}\n\n\tconst selectedFrameworks = result;\n\n\t// If no items selected, show a message\n\tif (selectedFrameworks.length === 0) {\n\t\tp.note('No frameworks were selected', 'Empty Selection');\n\t\tprocess.exit(0);\n\t}\n\n\t// Display selected frameworks with detailed information\n\tp.note(\n\t\t`You selected ${color.green(selectedFrameworks.length)} frameworks:`,\n\t\t'Selection Complete'\n\t);\n\n\t// Show each selected framework with its details\n\tconst selectedDetails = selectedFrameworks\n\t\t.map((value) => {\n\t\t\tconst framework = frameworks.find((f) => f.value === value);\n\t\t\treturn framework\n\t\t\t\t? `${color.cyan(framework.label)} ${color.dim(`- ${framework.hint}`)}`\n\t\t\t\t: value;\n\t\t})\n\t\t.join('\\n');\n\n\tp.log.message(selectedDetails);\n\tp.outro(`Successfully selected ${color.green(selectedFrameworks.length)} frameworks.`);\n}\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/basic/autocomplete.ts",
    "content": "import * as p from '@clack/prompts';\nimport color from 'picocolors';\n\nasync function main() {\n\tconsole.clear();\n\n\tp.intro(`${color.bgCyan(color.black(' Autocomplete Example '))}`);\n\n\tp.note(\n\t\t`\n${color.cyan('This example demonstrates the type-ahead autocomplete feature:')}\n- ${color.yellow('Type')} to filter the list in real-time\n- Use ${color.yellow('up/down arrows')} to navigate the filtered results\n- Press ${color.yellow('Enter')} to select the highlighted option\n- Press ${color.yellow('Ctrl+C')} to cancel\n  `,\n\t\t'Instructions'\n\t);\n\n\tconst countries = [\n\t\t{ value: 'us', label: 'United States', hint: 'NA' },\n\t\t{ value: 'ca', label: 'Canada', hint: 'NA' },\n\t\t{ value: 'mx', label: 'Mexico', hint: 'NA' },\n\t\t{ value: 'br', label: 'Brazil', hint: 'SA' },\n\t\t{ value: 'ar', label: 'Argentina', hint: 'SA' },\n\t\t{ value: 'uk', label: 'United Kingdom', hint: 'EU' },\n\t\t{ value: 'fr', label: 'France', hint: 'EU' },\n\t\t{ value: 'de', label: 'Germany', hint: 'EU' },\n\t\t{ value: 'it', label: 'Italy', hint: 'EU' },\n\t\t{ value: 'es', label: 'Spain', hint: 'EU' },\n\t\t{ value: 'pt', label: 'Portugal', hint: 'EU' },\n\t\t{ value: 'ru', label: 'Russia', hint: 'EU/AS' },\n\t\t{ value: 'cn', label: 'China', hint: 'AS' },\n\t\t{ value: 'jp', label: 'Japan', hint: 'AS' },\n\t\t{ value: 'in', label: 'India', hint: 'AS' },\n\t\t{ value: 'kr', label: 'South Korea', hint: 'AS' },\n\t\t{ value: 'au', label: 'Australia', hint: 'OC' },\n\t\t{ value: 'nz', label: 'New Zealand', hint: 'OC' },\n\t\t{ value: 'za', label: 'South Africa', hint: 'AF' },\n\t\t{ value: 'eg', label: 'Egypt', hint: 'AF' },\n\t];\n\n\tconst result = await p.autocomplete({\n\t\tmessage: 'Select a country',\n\t\toptions: countries,\n\t\tplaceholder: 'Type to search countries...',\n\t\tmaxItems: 8,\n\t});\n\n\tif (p.isCancel(result)) {\n\t\tp.cancel('Operation cancelled.');\n\t\tprocess.exit(0);\n\t}\n\n\tconst selected = countries.find((c) => c.value === result);\n\tp.outro(`You selected: ${color.cyan(selected?.label)} (${color.yellow(selected?.hint)})`);\n}\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/basic/date.ts",
    "content": "import * as p from '@clack/prompts';\nimport color from 'picocolors';\n\nasync function main() {\n\tconst result = (await p.date({\n\t\tmessage: color.magenta('Pick a date'),\n\t\tformat: 'YMD',\n\t\tminDate: new Date('2026-01-01'),\n\t\tmaxDate: new Date('2026-12-31'),\n\t})) as Date;\n\n\tif (p.isCancel(result)) {\n\t\tp.cancel('Operation cancelled.');\n\t\tprocess.exit(0);\n\t}\n\n\tconst fmt = (d: Date) => d.toISOString().slice(0, 10);\n\tp.outro(`Selected date: ${color.cyan(fmt(result))}`);\n}\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/basic/default-value.ts",
    "content": "import * as p from '@clack/prompts';\nimport color from 'picocolors';\n\nasync function main() {\n\tconst defaultPath = 'my-project';\n\n\tconst result = await p.text({\n\t\tmessage: 'Enter the directory to bootstrap the project',\n\t\tplaceholder: `  (hit Enter to use '${defaultPath}')`,\n\t\tdefaultValue: defaultPath,\n\t\tvalidate: (value) => {\n\t\t\tif (!value) {\n\t\t\t\treturn 'Directory is required';\n\t\t\t}\n\t\t\tif (value.includes(' ')) {\n\t\t\t\treturn 'Directory cannot contain spaces';\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t});\n\n\tif (p.isCancel(result)) {\n\t\tp.cancel('Operation cancelled.');\n\t\tprocess.exit(0);\n\t}\n\n\tp.outro(`Let's bootstrap the project in ${color.cyan(result)}`);\n}\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/basic/index.ts",
    "content": "import { setTimeout } from 'node:timers/promises';\nimport * as p from '@clack/prompts';\nimport color from 'picocolors';\n\nasync function main() {\n\tconsole.clear();\n\n\tawait setTimeout(1000);\n\n\tp.updateSettings({\n\t\taliases: {\n\t\t\tw: 'up',\n\t\t\ts: 'down',\n\t\t\ta: 'left',\n\t\t\td: 'right',\n\t\t},\n\t});\n\n\tp.intro(`${color.bgCyan(color.black(' create-app '))}`);\n\n\tconst project = await p.group(\n\t\t{\n\t\t\tpath: () =>\n\t\t\t\tp.text({\n\t\t\t\t\tmessage: 'Where should we create your project?',\n\t\t\t\t\tplaceholder: './sparkling-solid',\n\t\t\t\t\tvalidate: (value) => {\n\t\t\t\t\t\tif (!value) return 'Please enter a path.';\n\t\t\t\t\t\tif (value[0] !== '.') return 'Please enter a relative path.';\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\tpassword: () =>\n\t\t\t\tp.password({\n\t\t\t\t\tmessage: 'Provide a password',\n\t\t\t\t\tvalidate: (value) => {\n\t\t\t\t\t\tif (!value) return 'Please enter a password.';\n\t\t\t\t\t\tif (value.length < 5) return 'Password should have at least 5 characters.';\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\ttype: ({ results }) =>\n\t\t\t\tp.select({\n\t\t\t\t\tmessage: `Pick a project type within \"${results.path}\"`,\n\t\t\t\t\tinitialValue: 'ts',\n\t\t\t\t\tmaxItems: 5,\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{ value: 'ts', label: 'TypeScript' },\n\t\t\t\t\t\t{ value: 'js', label: 'JavaScript' },\n\t\t\t\t\t\t{ value: 'rust', label: 'Rust' },\n\t\t\t\t\t\t{ value: 'go', label: 'Go' },\n\t\t\t\t\t\t{ value: 'python', label: 'Python' },\n\t\t\t\t\t\t{ value: 'coffee', label: 'CoffeeScript', hint: 'oh no' },\n\t\t\t\t\t],\n\t\t\t\t}),\n\t\t\ttools: () =>\n\t\t\t\tp.multiselect({\n\t\t\t\t\tmessage: 'Select additional tools.',\n\t\t\t\t\tinitialValues: ['prettier', 'eslint'],\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{ value: 'prettier', label: 'Prettier', hint: 'recommended' },\n\t\t\t\t\t\t{ value: 'eslint', label: 'ESLint', hint: 'recommended' },\n\t\t\t\t\t\t{ value: 'stylelint', label: 'Stylelint' },\n\t\t\t\t\t\t{ value: 'gh-action', label: 'GitHub Action' },\n\t\t\t\t\t],\n\t\t\t\t}),\n\t\t\tinstall: () =>\n\t\t\t\tp.confirm({\n\t\t\t\t\tmessage: 'Install dependencies?',\n\t\t\t\t\tinitialValue: false,\n\t\t\t\t}),\n\t\t},\n\t\t{\n\t\t\tonCancel: () => {\n\t\t\t\tp.cancel('Operation cancelled.');\n\t\t\t\tprocess.exit(0);\n\t\t\t},\n\t\t}\n\t);\n\n\tif (project.install) {\n\t\tconst s = p.spinner();\n\t\ts.start('Installing via pnpm');\n\t\tawait setTimeout(2500);\n\t\ts.stop('Installed via pnpm');\n\t}\n\n\tconst nextSteps = `cd ${project.path}        \\n${project.install ? '' : 'pnpm install\\n'}pnpm dev`;\n\n\tp.note(nextSteps, 'Next steps.');\n\n\tp.outro(`Problems? ${color.underline(color.cyan('https://example.com/issues'))}`);\n}\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/basic/package.json",
    "content": "{\n  \"name\": \"@example/basic\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@clack/prompts\": \"workspace:*\",\n    \"picocolors\": \"^1.0.0\",\n    \"jiti\": \"^1.17.0\"\n  },\n  \"scripts\": {\n    \"start\": \"jiti ./index.ts\",\n    \"stream\": \"jiti ./stream.ts\",\n    \"progress\": \"jiti ./progress.ts\",\n    \"spinner\": \"jiti ./spinner.ts\",\n    \"path\": \"jiti ./path.ts\",\n\t\t\"date\": \"jiti ./date.ts\",\n\t\t\"spinner-ci\": \"npx cross-env CI=\\\"true\\\" jiti ./spinner-ci.ts\",\n    \"spinner-timer\": \"jiti ./spinner-timer.ts\",\n    \"task-log\": \"jiti ./task-log.ts\"\n  },\n  \"devDependencies\": {\n    \"cross-env\": \"^7.0.3\"\n  }\n}\n"
  },
  {
    "path": "examples/basic/path.ts",
    "content": "import * as p from '@clack/prompts';\n\nasync function demo() {\n\tp.intro('path start...');\n\n\tconst _path = await p.path({\n\t\tmessage: 'Read file',\n\t});\n\n\tp.outro('path stop...');\n}\n\nvoid demo();\n"
  },
  {
    "path": "examples/basic/progress.ts",
    "content": "import { setTimeout } from 'node:timers/promises';\nimport type { ProgressResult } from '@clack/prompts';\nimport * as p from '@clack/prompts';\n\nasync function fakeProgress(progressbar: ProgressResult): Promise<void> {\n\tawait setTimeout(1000);\n\tfor (const _i in Array(10).fill(1)) {\n\t\tprogressbar.advance();\n\t\tawait setTimeout(100 + Math.random() * 500);\n\t}\n}\n\nasync function demo() {\n\tp.intro('progress start...');\n\n\tconst download = p.progress({ style: 'block', max: 10, size: 30 });\n\tdownload.start('Downloading package');\n\tawait fakeProgress(download);\n\tdownload.stop('Download completed');\n\n\tconst unarchive = p.progress({ style: 'heavy', max: 10, size: 30, indicator: undefined });\n\tunarchive.start('Un-archiving');\n\tawait fakeProgress(unarchive);\n\tunarchive.stop('Un-archiving completed');\n\n\tconst linking = p.progress({ style: 'light', max: 10, size: 30, indicator: 'timer' });\n\tlinking.start('Linking');\n\tawait fakeProgress(linking);\n\tlinking.stop('Package linked');\n\n\tp.outro('progress stop...');\n}\n\nvoid demo();\n"
  },
  {
    "path": "examples/basic/spinner-cancel-advanced.ts",
    "content": "import { setTimeout as sleep } from 'node:timers/promises';\nimport * as p from '@clack/prompts';\n\nasync function main() {\n\tp.intro('Advanced Spinner Cancellation Demo');\n\n\t// First demonstrate a visible spinner with no user input needed\n\tp.note('First, we will show a basic spinner (press CTRL+C to cancel)', 'Demo Part 1');\n\n\tconst demoSpinner = p.spinner({\n\t\tindicator: 'dots',\n\t\tonCancel: () => {\n\t\t\tp.note('Initial spinner was cancelled with CTRL+C', 'Demo Cancelled');\n\t\t},\n\t});\n\n\tdemoSpinner.start('Loading demo resources');\n\n\t// Update spinner message a few times to show activity\n\tfor (let i = 0; i < 5; i++) {\n\t\tif (demoSpinner.isCancelled) break;\n\t\tawait sleep(1000);\n\t\tdemoSpinner.message(`Loading demo resources (${i + 1}/5)`);\n\t}\n\n\tif (!demoSpinner.isCancelled) {\n\t\tdemoSpinner.stop('Demo resources loaded successfully');\n\t}\n\n\t// Only continue with the rest of the demo if the initial spinner wasn't cancelled\n\tif (!demoSpinner.isCancelled) {\n\t\t// Stage 1: Get user input with multiselect\n\t\tp.note(\"Now let's select some languages to process\", 'Demo Part 2');\n\n\t\tconst languages = await p.multiselect({\n\t\t\tmessage: 'Select programming languages to process:',\n\t\t\toptions: [\n\t\t\t\t{ value: 'typescript', label: 'TypeScript' },\n\t\t\t\t{ value: 'javascript', label: 'JavaScript' },\n\t\t\t\t{ value: 'python', label: 'Python' },\n\t\t\t\t{ value: 'rust', label: 'Rust' },\n\t\t\t\t{ value: 'go', label: 'Go' },\n\t\t\t],\n\t\t\trequired: true,\n\t\t});\n\n\t\t// Handle cancellation of the multiselect\n\t\tif (p.isCancel(languages)) {\n\t\t\tp.cancel('Operation cancelled during language selection.');\n\t\t\tprocess.exit(0);\n\t\t}\n\n\t\t// Stage 2: Show a spinner that can be cancelled\n\t\tconst processSpinner = p.spinner({\n\t\t\tindicator: 'dots',\n\t\t\tonCancel: () => {\n\t\t\t\tp.note(\n\t\t\t\t\t'You cancelled during processing. Any completed work will be saved.',\n\t\t\t\t\t'Processing Cancelled'\n\t\t\t\t);\n\t\t\t},\n\t\t});\n\n\t\tprocessSpinner.start('Starting to process selected languages...');\n\n\t\t// Process each language with individual progress updates\n\t\tlet completedCount = 0;\n\t\tconst totalLanguages = languages.length;\n\n\t\tfor (const language of languages) {\n\t\t\t// Skip the rest if cancelled\n\t\t\tif (processSpinner.isCancelled) break;\n\n\t\t\t// Update spinner message with current language\n\t\t\tprocessSpinner.message(`Processing ${language} (${completedCount + 1}/${totalLanguages})`);\n\n\t\t\ttry {\n\t\t\t\t// Simulate work - longer pause to give time to test CTRL+C\n\t\t\t\tawait sleep(2000);\n\t\t\t\tcompletedCount++;\n\t\t\t} catch (error) {\n\t\t\t\t// Handle errors but continue if not cancelled\n\t\t\t\tif (!processSpinner.isCancelled) {\n\t\t\t\t\tp.note(`Error processing ${language}: ${error.message}`, 'Error');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Stage 3: Handle completion based on cancellation status\n\t\tif (!processSpinner.isCancelled) {\n\t\t\tprocessSpinner.stop(`Processed ${completedCount}/${totalLanguages} languages successfully`);\n\n\t\t\t// Stage 4: Additional user input based on processing results\n\t\t\tif (completedCount > 0) {\n\t\t\t\tconst action = await p.select({\n\t\t\t\t\tmessage: 'What would you like to do with the processed data?',\n\t\t\t\t\toptions: [\n\t\t\t\t\t\t{ value: 'save', label: 'Save results', hint: 'Write to disk' },\n\t\t\t\t\t\t{ value: 'share', label: 'Share results', hint: 'Upload to server' },\n\t\t\t\t\t\t{ value: 'analyze', label: 'Further analysis', hint: 'Generate reports' },\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tif (p.isCancel(action)) {\n\t\t\t\t\tp.cancel('Operation cancelled at final stage.');\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}\n\n\t\t\t\t// Stage 5: Final action with a timer spinner\n\t\t\t\tp.note('Now demonstrating a timer-style spinner', 'Final Stage');\n\n\t\t\t\tconst finalSpinner = p.spinner({\n\t\t\t\t\tindicator: 'timer', // Use timer indicator for variety\n\t\t\t\t\tonCancel: () => {\n\t\t\t\t\t\tp.note(\n\t\t\t\t\t\t\t'Final operation was cancelled, but processing results are still valid.',\n\t\t\t\t\t\t\t'Final Stage Cancelled'\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tfinalSpinner.start(`Performing ${action} operation...`);\n\n\t\t\t\ttry {\n\t\t\t\t\t// Simulate final action with incremental updates\n\t\t\t\t\tfor (let i = 0; i < 3; i++) {\n\t\t\t\t\t\tif (finalSpinner.isCancelled) break;\n\t\t\t\t\t\tawait sleep(1500);\n\t\t\t\t\t\tfinalSpinner.message(`Performing ${action} operation... Step ${i + 1}/3`);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!finalSpinner.isCancelled) {\n\t\t\t\t\t\tfinalSpinner.stop(`${action} operation completed successfully`);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!finalSpinner.isCancelled) {\n\t\t\t\t\t\tfinalSpinner.stop(`Error during ${action}: ${error.message}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tp.outro('Advanced demo completed. Thanks for trying out the spinner cancellation features!');\n}\n\nmain().catch((error) => {\n\tconsole.error('Unexpected error:', error);\n\tprocess.exit(1);\n});\n"
  },
  {
    "path": "examples/basic/spinner-cancel.ts",
    "content": "import * as p from '@clack/prompts';\n\np.intro('Spinner with cancellation detection');\n\n// Example 1: Using onCancel callback\nconst spin1 = p.spinner({\n\tindicator: 'dots',\n\tonCancel: () => {\n\t\tp.note('You cancelled the spinner with CTRL-C!', 'Callback detected');\n\t},\n});\n\nspin1.start('Press CTRL-C to cancel this spinner (using callback)');\n\n// Sleep for 10 seconds, allowing time for user to press CTRL-C\nawait sleep(10000).then(() => {\n\t// Only show success message if not cancelled\n\tif (!spin1.isCancelled) {\n\t\tspin1.stop('Spinner completed without cancellation');\n\t}\n});\n\n// Example 2: Checking the isCancelled property\np.note('Starting second example...', 'Example 2');\n\nconst spin2 = p.spinner({ indicator: 'timer' });\nspin2.start('Press CTRL-C to cancel this spinner (polling isCancelled)');\n\nawait sleep(10000).then(() => {\n\tif (spin2.isCancelled) {\n\t\tp.note('Spinner was cancelled by the user!', 'Property check');\n\t} else {\n\t\tspin2.stop('Spinner completed without cancellation');\n\t}\n});\n\np.outro('Example completed');\n\n// Helper function\nfunction sleep(ms: number) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n"
  },
  {
    "path": "examples/basic/spinner-ci.ts",
    "content": "/**\n * This example addresses a issue reported in GitHub Actions where `spinner` was excessively writing messages,\n * leading to confusion and cluttered output.\n * To enhance the CI workflow and provide a smoother experience,\n * the following changes have been made only for CI environment:\n * - Messages will now only be written when a `spinner` method is called and the message updated, preventing unnecessary message repetition.\n * - There will be no loading dots animation, instead it will be always `...`\n * - Instead of erase the previous message, action that is blocked during CI, it will just write a new one.\n *\n * Issue: https://github.com/bombshell-dev/clack/issues/168\n */\nimport * as p from '@clack/prompts';\n\nconst s = p.spinner();\nlet progress = 0;\nlet counter = 0;\nlet loop: NodeJS.Timer;\n\np.intro('Running spinner in CI environment');\ns.start('spinner.start');\nnew Promise((resolve) => {\n\tloop = setInterval(() => {\n\t\tif (progress % 1000 === 0) {\n\t\t\tcounter++;\n\t\t}\n\t\tprogress += 100;\n\t\ts.message(`spinner.message [${counter}]`);\n\t\tif (counter > 6) {\n\t\t\tclearInterval(loop);\n\t\t\tresolve(true);\n\t\t}\n\t}, 100);\n}).then(() => {\n\ts.stop('spinner.stop');\n\tp.outro('Done');\n});\n"
  },
  {
    "path": "examples/basic/spinner-timer.ts",
    "content": "import * as p from '@clack/prompts';\n\np.intro('spinner start...');\n\nasync function main() {\n\tconst spin = p.spinner({ indicator: 'timer' });\n\n\tspin.start('First spinner');\n\n\tawait sleep(3_000);\n\n\tspin.stop('Done first spinner');\n\n\tspin.start('Second spinner');\n\tawait sleep(5_000);\n\n\tspin.stop('Done second spinner');\n\n\tp.outro('spinner stop.');\n}\n\nfunction sleep(ms: number) {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nmain();\n"
  },
  {
    "path": "examples/basic/spinner.ts",
    "content": "import * as p from '@clack/prompts';\n\np.intro('spinner start...');\n\nconst spin = p.spinner();\nconst total = 6000;\nlet progress = 0;\nspin.start();\n\nnew Promise((resolve) => {\n\tconst timer = setInterval(() => {\n\t\tprogress = Math.min(total, progress + 100);\n\t\tif (progress >= total) {\n\t\t\tclearInterval(timer);\n\t\t\tresolve(true);\n\t\t}\n\t\tspin.message(`Loading packages [${progress}/${total}]`); // <===\n\t}, 100);\n}).then(() => {\n\tspin.stop('Done');\n\tp.outro('spinner stop...');\n});\n"
  },
  {
    "path": "examples/basic/stream.ts",
    "content": "import { setTimeout } from 'node:timers/promises';\nimport * as p from '@clack/prompts';\nimport color from 'picocolors';\n\nasync function main() {\n\tconsole.clear();\n\n\tawait setTimeout(1000);\n\n\tp.intro(`${color.bgCyan(color.black(' create-app '))}`);\n\n\tawait p.stream.step(\n\t\t(async function* () {\n\t\t\tfor (const line of lorem) {\n\t\t\t\tfor (const word of line.split(' ')) {\n\t\t\t\t\tyield word;\n\t\t\t\t\tyield ' ';\n\t\t\t\t\tawait setTimeout(200);\n\t\t\t\t}\n\t\t\t\tyield '\\n';\n\t\t\t\tif (line !== lorem.at(-1)) {\n\t\t\t\t\tawait setTimeout(1000);\n\t\t\t\t}\n\t\t\t}\n\t\t})()\n\t);\n\n\tp.outro(`Problems? ${color.underline(color.cyan('https://example.com/issues'))}`);\n}\n\nconst lorem = [\n\t'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',\n\t'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.',\n];\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/basic/task-log.ts",
    "content": "import { setTimeout } from 'node:timers/promises';\nimport * as p from '@clack/prompts';\n\nasync function main() {\n\tp.intro('task log start...');\n\n\tconst log = p.taskLog({\n\t\ttitle: 'Running npm install',\n\t\tlimit: 5,\n\t});\n\n\tfor await (const line of fakeCommand()) {\n\t\tlog.message(line);\n\t}\n\n\tlog.success('Done!');\n\n\tp.outro('task log stop...');\n}\n\nasync function* fakeCommand() {\n\tfor (let i = 0; i < 100; i++) {\n\t\tyield `line \\x1b[32m${i}\\x1b[39m...`;\n\t\tawait setTimeout(80);\n\t}\n}\n\nmain();\n"
  },
  {
    "path": "examples/basic/text-validation.ts",
    "content": "import { setTimeout } from 'node:timers/promises';\nimport { isCancel, note, text } from '@clack/prompts';\n\nasync function main() {\n\tconsole.clear();\n\n\t// Example demonstrating the issue with initial value validation\n\tconst name = await text({\n\t\tmessage: 'Enter your name (letters and spaces only)',\n\t\tinitialValue: 'John123', // Invalid initial value with numbers\n\t\tvalidate: (value) => {\n\t\t\tif (!value || !/^[a-zA-Z\\s]+$/.test(value)) return 'Name can only contain letters and spaces';\n\t\t\treturn undefined;\n\t\t},\n\t});\n\n\tif (!isCancel(name)) {\n\t\tnote(`Valid name: ${name}`, 'Success');\n\t}\n\n\tawait setTimeout(1000);\n\n\t// Example with a valid initial value for comparison\n\tconst validName = await text({\n\t\tmessage: 'Enter another name (letters and spaces only)',\n\t\tinitialValue: 'John Doe', // Valid initial value\n\t\tvalidate: (value) => {\n\t\t\tif (!value || !/^[a-zA-Z\\s]+$/.test(value)) return 'Name can only contain letters and spaces';\n\t\t\treturn undefined;\n\t\t},\n\t});\n\n\tif (!isCancel(validName)) {\n\t\tnote(`Valid name: ${validName}`, 'Success');\n\t}\n\n\tawait setTimeout(1000);\n}\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/basic/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "examples/changesets/index.ts",
    "content": "import { setTimeout } from 'node:timers/promises';\nimport * as p from '@clack/prompts';\nimport color from 'picocolors';\n\nfunction onCancel() {\n\tp.cancel('Operation cancelled.');\n\tprocess.exit(0);\n}\n\nasync function main() {\n\tconsole.clear();\n\n\tawait setTimeout(1000);\n\n\tp.intro(`${color.bgCyan(color.black(' changesets '))}`);\n\n\tconst _changeset = await p.group(\n\t\t{\n\t\t\tpackages: () =>\n\t\t\t\tp.groupMultiselect({\n\t\t\t\t\tmessage: 'Which packages would you like to include?',\n\t\t\t\t\toptions: {\n\t\t\t\t\t\t'changed packages': [\n\t\t\t\t\t\t\t{ value: '@scope/a' },\n\t\t\t\t\t\t\t{ value: '@scope/b' },\n\t\t\t\t\t\t\t{ value: '@scope/c' },\n\t\t\t\t\t\t],\n\t\t\t\t\t\t'unchanged packages': [\n\t\t\t\t\t\t\t{ value: '@scope/x' },\n\t\t\t\t\t\t\t{ value: '@scope/y' },\n\t\t\t\t\t\t\t{ value: '@scope/z' },\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\tmajor: ({ results }) => {\n\t\t\t\tconst packages = results.packages ?? [];\n\t\t\t\treturn p.multiselect({\n\t\t\t\t\tmessage: `Which packages should have a ${color.red('major')} bump?`,\n\t\t\t\t\toptions: packages.map((value) => ({ value })),\n\t\t\t\t\trequired: false,\n\t\t\t\t});\n\t\t\t},\n\t\t\tminor: ({ results }) => {\n\t\t\t\tconst packages = results.packages ?? [];\n\t\t\t\tconst major = Array.isArray(results.major) ? results.major : [];\n\t\t\t\tconst possiblePackages = packages.filter((pkg) => !major.includes(pkg));\n\t\t\t\tif (possiblePackages.length === 0) return;\n\t\t\t\treturn p.multiselect({\n\t\t\t\t\tmessage: `Which packages should have a ${color.yellow('minor')} bump?`,\n\t\t\t\t\toptions: possiblePackages.map((value) => ({ value })),\n\t\t\t\t\trequired: false,\n\t\t\t\t});\n\t\t\t},\n\t\t\tpatch: async ({ results }) => {\n\t\t\t\tconst packages = results.packages ?? [];\n\t\t\t\tconst major = Array.isArray(results.major) ? results.major : [];\n\t\t\t\tconst minor = Array.isArray(results.minor) ? results.minor : [];\n\t\t\t\tconst possiblePackages = packages.filter(\n\t\t\t\t\t(pkg) => !major.includes(pkg) && !minor.includes(pkg)\n\t\t\t\t);\n\t\t\t\tif (possiblePackages.length === 0) return;\n\t\t\t\tconst note = possiblePackages.join(color.dim(', '));\n\n\t\t\t\tp.log.step(`These packages will have a ${color.green('patch')} bump.\\n${color.dim(note)}`);\n\t\t\t\treturn possiblePackages;\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tonCancel,\n\t\t}\n\t);\n\n\tconst message = await p.text({\n\t\tplaceholder: 'Summary',\n\t\tmessage: 'Please enter a summary for this change',\n\t});\n\n\tif (p.isCancel(message)) {\n\t\treturn onCancel();\n\t}\n\n\tp.outro(`Changeset added! ${color.underline(color.cyan('.changeset/orange-crabs-sing.md'))}`);\n}\n\nmain().catch(console.error);\n"
  },
  {
    "path": "examples/changesets/package.json",
    "content": "{\n  \"name\": \"@example/changesets\",\n  \"private\": true,\n  \"version\": \"0.0.0\",\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"jiti\": \"^1.17.0\",\n    \"@clack/prompts\": \"workspace:*\",\n    \"picocolors\": \"^1.0.0\"\n  },\n  \"scripts\": {\n    \"start\": \"jiti ./index.ts\"\n  },\n  \"devDependencies\": {}\n}\n"
  },
  {
    "path": "examples/changesets/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\"\n}\n"
  },
  {
    "path": "knip.json",
    "content": "{\n  \"workspaces\": {\n    \".\": {\n      \"ignore\": [\"build.preset.ts\"]\n    },\n    \"examples/*\": {\n      \"entry\": \"*.ts!\",\n      \"project\": \"*.ts\"\n    },\n    \"packages/*\": {\n      \"entry\": \"src/index.ts!\",\n      \"project\": [\"src/**/*.ts!\", \"test/**/*.ts\"]\n    }\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@clack/root\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"scripts\": {\n    \"stub\": \"pnpm -r run build --stub\",\n    \"build\": \"pnpm --filter \\\"@clack/*\\\" run build\",\n    \"start\": \"pnpm run dev\",\n    \"dev\": \"pnpm --filter @example/changesets run start\",\n    \"format\": \"biome check --write\",\n    \"lint\": \"biome lint --write --unsafe\",\n    \"types\": \"tsc --noEmit\",\n    \"deps\": \"pnpm exec knip --production\",\n    \"test\": \"pnpm --color -r run test\",\n    \"pretest\": \"pnpm run build\"\n  },\n  \"devDependencies\": {\n    \"@biomejs/biome\": \"^2.1.2\",\n    \"@changesets/cli\": \"^2.29.5\",\n    \"@types/node\": \"^24.1.0\",\n    \"jsr\": \"^0.13.4\",\n    \"knip\": \"^5.62.0\",\n    \"typescript\": \"^5.8.3\",\n    \"unbuild\": \"^3.6.0\"\n  },\n  \"packageManager\": \"pnpm@9.14.2\",\n  \"volta\": {\n    \"node\": \"20.18.1\"\n  }\n}\n"
  },
  {
    "path": "packages/core/CHANGELOG.md",
    "content": "# @clack/core\n\n## 1.1.0\n\n### Minor Changes\n\n- e3333fb: Replaces `picocolors` with Node.js built-in `styleText`.\n\n## 1.0.1\n\n### Patch Changes\n\n- 6404dc1: Disallows selection of `disabled` options in autocomplete.\n- 2533180: Updates the documentation to mention `userInputWithCursor` when using the `TextPrompt` primitive.\n\n## 1.0.0\n\n### Major Changes\n\n- c713fd5: The package is now distributed as ESM-only. In `v0` releases, the package was dual-published as CJS and ESM.\n\n  For existing CJS projects using Node v20+, please see Node's guide on [Loading ECMAScript modules using `require()`](https://nodejs.org/docs/latest-v20.x/api/modules.html#loading-ecmascript-modules-using-require).\n\n### Minor Changes\n\n- 7bc3301: Prompts now have a `userInput` stored separately from their `value`.\n- 2837845: Adds suggestion and path prompts\n- 729bbb6: Add support for customizable spinner cancel and error messages. Users can now customize these messages either per spinner instance or globally via the `updateSettings` function to support multilingual CLIs.\n\n  This update also improves the architecture by exposing the core settings to the prompts package, enabling more consistent default message handling across the codebase.\n\n  ```ts\n  // Per-instance customization\n  const spinner = prompts.spinner({\n    cancelMessage: \"Operación cancelada\", // \"Operation cancelled\" in Spanish\n    errorMessage: \"Se produjo un error\", // \"An error occurred\" in Spanish\n  });\n\n  // Global customization via updateSettings\n  prompts.updateSettings({\n    messages: {\n      cancel: \"Operación cancelada\", // \"Operation cancelled\" in Spanish\n      error: \"Se produjo un error\", // \"An error occurred\" in Spanish\n    },\n  });\n\n  // Settings can now be accessed directly\n  console.log(prompts.settings.messages.cancel); // \"Operación cancelada\"\n\n  // Direct options take priority over global settings\n  const spinner = prompts.spinner({\n    cancelMessage: \"Cancelled\", // This will be used instead of the global setting\n  });\n  ```\n\n- 55645c2: Support wrapping autocomplete and select prompts.\n- f2c2b89: Adds `AutocompletePrompt` to core with comprehensive tests and implement both `autocomplete` and `autocomplete-multiselect` components in prompts package.\n- df4eea1: Remove `suggestion` prompt and change `path` prompt to be an autocomplete prompt.\n- 1604f97: Add `clearOnError` option to password prompt to automatically clear input when validation fails\n\n### Patch Changes\n\n- 0718b07: fix: export `*Options` types for prompts.\n- bfe0dd3: Prevents placeholder from being used as input value in text prompts\n- 6868c1c: Adds a new `selectableGroups` boolean to the group multi-select prompt. Using `selectableGroups: false` will disable the ability to select a top-level group, but still allow every child to be selected individually.\n- 7df841d: Removed all trailing space in prompt output and fixed various padding rendering bugs.\n- a4f5034: Fixes an edge case for placeholder values. Previously, when pressing `enter` on an empty prompt, placeholder values would be ignored. Now, placeholder values are treated as the prompt value.\n- b103ad3: Allow disabled options in multi-select and select prompts.\n- 71b5029: Add missing nullish checks around values.\n- a36292b: Fix \"TTY initialization failed: uv_tty_init returned EBADF (bad file descriptor)\" error happening on Windows for non-tty terminals.\n- 1a45f93: Switched from wrap-ansi to fast-wrap-ansi\n- 4ba2d78: Support short terminal windows when re-rendering by accounting for off-screen lines\n- 34f52fe: Validates initial values immediately when using text prompts with initialValue and validate props.\n- 94fee2a: Changes `placeholder` to be a visual hint rather than a tabbable value.\n- 4f6b3c2: Set initial values of auto complete prompt to first option when multiple is false.\n- 8ead5d3: Avoid passing initial values to core when using auto complete prompt\n- acc4c3a: Add a new `withGuide` option to all prompts to disable the default clack border\n- 68dbf9b: select-key: Fixed wrapping and added new `caseSensitive` option\n- 2310b43: Allow custom writables as output stream.\n- d98e033: add invert selection for multiselect prompt\n\n## 0.4.1\n\n### Patch Changes\n\n- 8093f3c: Adds `Error` support to the `validate` function\n- e5ba09a: Fixes a cursor display bug in terminals that do not support the \"hidden\" escape sequence. See [Issue #127](https://github.com/bombshell-dev/clack/issues/127).\n- 8cba8e3: Fixes a rendering bug with cursor positions for `TextPrompt`\n\n## 0.4.0\n\n### Minor Changes\n\n- a83d2f8: Adds a new `updateSettings()` function to support new global keybindings.\n\n  `updateSettings()` accepts an `aliases` object that maps custom keys to an action (`up | down | left | right | space | enter | cancel`).\n\n  ```ts\n  import { updateSettings } from \"@clack/core\";\n\n  // Support custom keybindings\n  updateSettings({\n    aliases: {\n      w: \"up\",\n      a: \"left\",\n      s: \"down\",\n      d: \"right\",\n    },\n  });\n  ```\n\n> [!WARNING]\n> In order to enforce consistent, user-friendly defaults across the ecosystem, `updateSettings` does not support disabling Clack's default keybindings.\n\n- 801246b: Adds a new `signal` option to support programmatic prompt cancellation with an [abort controller](https://kettanaito.com/blog/dont-sleep-on-abort-controller).\n\n- a83d2f8: Updates default keybindings to support Vim motion shortcuts and map the `escape` key to cancel (`ctrl+c`).\n\n  | alias | action |\n  | ----- | ------ |\n  | `k`   | up     |\n  | `l`   | right  |\n  | `j`   | down   |\n  | `h`   | left   |\n  | `esc` | cancel |\n\n### Patch Changes\n\n- 51e12bc: Improves types for events and interaction states.\n\n## 0.3.5\n\n### Patch Changes\n\n- 4845f4f: Fixes a bug which kept the terminal cursor hidden after a prompt is cancelled\n- d7b2fb9: Adds missing `LICENSE` file. Since the `package.json` file has always included `\"license\": \"MIT\"`, please consider this a licensing clarification rather than a licensing change.\n\n## 0.3.4\n\n### Patch Changes\n\n- a04e418: fix(@clack/core): keyboard input not working after await in spinner\n- 4f6fcf5: feat(@clack/core): allow tab completion for placeholders\n\n## 0.3.3\n\n### Patch Changes\n\n- cd79076: fix: restore raw mode on unblock\n\n## 0.3.2\n\n### Patch Changes\n\n- c96eda5: Enable hard line-wrapping behavior for long words without spaces\n\n## 0.3.1\n\n### Patch Changes\n\n- 58a1df1: Fix line duplication bug by automatically wrapping prompts to `process.stdout.columns`\n\n## 0.3.0\n\n### Minor Changes\n\n- 8a4a12f: Add `GroupMultiSelect` prompt\n\n### Patch Changes\n\n- 8a4a12f: add `groupMultiselect` prompt\n\n## 0.2.1\n\n### Patch Changes\n\n- ec812b6: fix `readline` hang on Windows\n\n## 0.2.0\n\n### Minor Changes\n\n- d74dd05: Adds a `selectKey` prompt type\n- 54c1bc3: **Breaking Change** `multiselect` has renamed `initialValue` to `initialValues`\n\n## 0.1.9\n\n### Patch Changes\n\n- 1251132: Multiselect: return `Value[]` instead of `Option[]`.\n- 8994382: Add a password prompt to `@clack/prompts`\n\n## 0.1.8\n\n### Patch Changes\n\n- d96071c: Don't mutate `initialValue` in `multiselect`, fix parameter type for `validate()`.\n\n  Credits to @banjo for the bug report and initial PR!\n\n## 0.1.7\n\n### Patch Changes\n\n- 6d9e675: Add support for neovim cursor motion (`hjkl`)\n\n  Thanks [@esau-morais](https://github.com/esau-morais) for the assist!\n\n## 0.1.6\n\n### Patch Changes\n\n- 7fb5375: Adds a new `defaultValue` option to the text prompt, removes automatic usage of the placeholder value.\n\n## 0.1.5\n\n### Patch Changes\n\n- de1314e: Support `required` option for multi-select\n\n## 0.1.4\n\n### Patch Changes\n\n- ca77da1: Fix multiselect initial value logic\n- 8aed606: Fix `MaxListenersExceededWarning` by detaching `stdin` listeners on close\n\n## 0.1.3\n\n### Patch Changes\n\n- a99c458: Support `initialValue` option for text prompt\n\n## 0.1.2\n\n### Patch Changes\n\n- Allow isCancel to type guard any unknown value\n- 7dcad8f: Allow placeholder to be passed to TextPrompt\n- 2242f13: Fix multiselect returning undefined\n- b1341d6: Improved placeholder handling\n\n## 0.1.1\n\n### Patch Changes\n\n- 4be7dbf: Ensure raw mode is unset on submit\n- b480679: Preserve value if validation fails\n\n## 0.1.0\n\n### Minor Changes\n\n- 7015ec9: Create new prompt: multi-select\n\n## 0.0.12\n\n### Patch Changes\n\n- 9d371c3: Fix rendering bug when using y/n to confirm\n\n## 0.0.11\n\n### Patch Changes\n\n- 441d5b7: fix select return undefined\n- d20ef2a: Update keywords, URLs\n- fe13c2f: fix cursor missing after submit\n\n## 0.0.10\n\n### Patch Changes\n\n- a0cb382: Add `main` entrypoint\n\n## 0.0.9\n\n### Patch Changes\n\n- Fix node@16 issue (cannot read \"createInterface\" of undefined)\n\n## 0.0.8\n\n### Patch Changes\n\n- a4b5e13: Bug fixes, exposes `block` utility\n\n## 0.0.7\n\n### Patch Changes\n\n- Fix cursor bug\n\n## 0.0.6\n\n### Patch Changes\n\n- Fix error with character check\n\n## 0.0.5\n\n### Patch Changes\n\n- 491f9e0: update readme\n\n## 0.0.4\n\n### Patch Changes\n\n- 7372d5c: Fix bug with line deletion\n\n## 0.0.3\n\n### Patch Changes\n\n- 5605d28: Do not bundle dependencies (take II)\n\n## 0.0.2\n\n### Patch Changes\n\n- 2ee67cb: don't bundle deps\n\n## 0.0.1\n\n### Patch Changes\n\n- 306598e: Initial publish, still WIP\n"
  },
  {
    "path": "packages/core/LICENSE",
    "content": "MIT License\n\nCopyright (c) Nate Moore\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "packages/core/README.md",
    "content": "# `@clack/core`\n\nClack contains low-level primitives for implementing your own command-line applications.\n\nCurrently, `TextPrompt`, `SelectPrompt`, and `ConfirmPrompt` are exposed as well as the base `Prompt` class.\n\nEach `Prompt` accepts a `render` function.\n\n```js\nimport { TextPrompt, isCancel } from '@clack/core';\n\nconst p = new TextPrompt({\n  render() {\n    return `What's your name?\\n${this.userInputWithCursor}`;\n  },\n});\n\nconst name = await p.prompt();\nif (isCancel(name)) {\n  process.exit(0);\n}\n```\n"
  },
  {
    "path": "packages/core/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\n// @see https://github.com/unjs/unbuild\nexport default defineBuildConfig({\n\tpreset: '../../build.preset',\n\tentries: ['src/index'],\n});\n"
  },
  {
    "path": "packages/core/package.json",
    "content": "{\n  \"name\": \"@clack/core\",\n  \"version\": \"1.1.0\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.mts\",\n      \"default\": \"./dist/index.mjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"types\": \"./dist/index.d.mts\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/bombshell-dev/clack.git\",\n    \"directory\": \"packages/core\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/bombshell-dev/clack/issues\"\n  },\n  \"homepage\": \"https://github.com/bombshell-dev/clack/tree/main/packages/core#readme\",\n  \"files\": [\n    \"dist\",\n    \"CHANGELOG.md\"\n  ],\n  \"keywords\": [\n    \"ask\",\n    \"clack\",\n    \"cli\",\n    \"command-line\",\n    \"command\",\n    \"input\",\n    \"interact\",\n    \"interface\",\n    \"menu\",\n    \"prompt\",\n    \"prompts\",\n    \"stdin\",\n    \"ui\"\n  ],\n  \"author\": {\n    \"name\": \"Nate Moore\",\n    \"email\": \"nate@natemoo.re\",\n    \"url\": \"https://twitter.com/n_moore\"\n  },\n  \"license\": \"MIT\",\n  \"packageManager\": \"pnpm@9.14.2\",\n  \"scripts\": {\n    \"build\": \"unbuild\",\n    \"prepack\": \"pnpm build\",\n    \"test\": \"vitest run\"\n  },\n  \"dependencies\": {\n    \"fast-wrap-ansi\": \"^0.1.3\",\n    \"sisteransi\": \"^1.0.5\"\n  },\n  \"devDependencies\": {\n    \"vitest\": \"^3.2.4\"\n  }\n}\n"
  },
  {
    "path": "packages/core/src/index.ts",
    "content": "export type { AutocompleteOptions } from './prompts/autocomplete.js';\nexport { default as AutocompletePrompt } from './prompts/autocomplete.js';\nexport type { ConfirmOptions } from './prompts/confirm.js';\nexport { default as ConfirmPrompt } from './prompts/confirm.js';\nexport type { DateFormat, DateOptions, DateParts } from './prompts/date.js';\nexport { default as DatePrompt } from './prompts/date.js';\nexport type { GroupMultiSelectOptions } from './prompts/group-multiselect.js';\nexport { default as GroupMultiSelectPrompt } from './prompts/group-multiselect.js';\nexport type { MultiSelectOptions } from './prompts/multi-select.js';\nexport { default as MultiSelectPrompt } from './prompts/multi-select.js';\nexport type { PasswordOptions } from './prompts/password.js';\nexport { default as PasswordPrompt } from './prompts/password.js';\nexport type { PromptOptions } from './prompts/prompt.js';\nexport { default as Prompt } from './prompts/prompt.js';\nexport type { SelectOptions } from './prompts/select.js';\nexport { default as SelectPrompt } from './prompts/select.js';\nexport type { SelectKeyOptions } from './prompts/select-key.js';\nexport { default as SelectKeyPrompt } from './prompts/select-key.js';\nexport type { TextOptions } from './prompts/text.js';\nexport { default as TextPrompt } from './prompts/text.js';\nexport type { ClackState as State } from './types.js';\nexport { block, getColumns, getRows, isCancel, wrapTextWithPrefix } from './utils/index.js';\nexport type { ClackSettings } from './utils/settings.js';\nexport { settings, updateSettings } from './utils/settings.js';\n"
  },
  {
    "path": "packages/core/src/prompts/autocomplete.ts",
    "content": "import type { Key } from 'node:readline';\nimport { styleText } from 'node:util';\nimport { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface OptionLike {\n\tvalue: unknown;\n\tlabel?: string;\n\tdisabled?: boolean;\n}\n\ntype FilterFunction<T extends OptionLike> = (search: string, opt: T) => boolean;\n\nfunction getCursorForValue<T extends OptionLike>(\n\tselected: T['value'] | undefined,\n\titems: T[]\n): number {\n\tif (selected === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst currLength = items.length;\n\n\t// If filtering changed the available options, update cursor\n\tif (currLength === 0) {\n\t\treturn 0;\n\t}\n\n\t// Try to maintain the same selected item\n\tconst index = items.findIndex((item) => item.value === selected);\n\treturn index !== -1 ? index : 0;\n}\n\nfunction defaultFilter<T extends OptionLike>(input: string, option: T): boolean {\n\tconst label = option.label ?? String(option.value);\n\treturn label.toLowerCase().includes(input.toLowerCase());\n}\n\nfunction normalisedValue<T>(multiple: boolean, values: T[] | undefined): T | T[] | undefined {\n\tif (!values) {\n\t\treturn undefined;\n\t}\n\tif (multiple) {\n\t\treturn values;\n\t}\n\treturn values[0];\n}\n\nexport interface AutocompleteOptions<T extends OptionLike>\n\textends PromptOptions<T['value'] | T['value'][], AutocompletePrompt<T>> {\n\toptions: T[] | ((this: AutocompletePrompt<T>) => T[]);\n\tfilter?: FilterFunction<T>;\n\tmultiple?: boolean;\n\t/**\n\t * When set (non-empty), pressing Tab with no input fills the field with this value\n\t * and runs the normal filter/selection logic so the user can confirm with Enter.\n\t * Tab only fills the input when the placeholder matches at least one option under\n\t * the prompt's filter (so the value remains selectable).\n\t */\n\tplaceholder?: string;\n}\n\nexport default class AutocompletePrompt<T extends OptionLike> extends Prompt<\n\tT['value'] | T['value'][]\n> {\n\tfilteredOptions: T[];\n\tmultiple: boolean;\n\tisNavigating = false;\n\tselectedValues: Array<T['value']> = [];\n\n\tfocusedValue: T['value'] | undefined;\n\t#cursor = 0;\n\t#lastUserInput = '';\n\t#filterFn: FilterFunction<T>;\n\t#options: T[] | (() => T[]);\n\t#placeholder: string | undefined;\n\n\tget cursor(): number {\n\t\treturn this.#cursor;\n\t}\n\n\tget userInputWithCursor() {\n\t\tif (!this.userInput) {\n\t\t\treturn styleText(['inverse', 'hidden'], '_');\n\t\t}\n\t\tif (this._cursor >= this.userInput.length) {\n\t\t\treturn `${this.userInput}█`;\n\t\t}\n\t\tconst s1 = this.userInput.slice(0, this._cursor);\n\t\tconst [s2, ...s3] = this.userInput.slice(this._cursor);\n\t\treturn `${s1}${styleText('inverse', s2)}${s3.join('')}`;\n\t}\n\n\tget options(): T[] {\n\t\tif (typeof this.#options === 'function') {\n\t\t\treturn this.#options();\n\t\t}\n\t\treturn this.#options;\n\t}\n\n\tconstructor(opts: AutocompleteOptions<T>) {\n\t\tsuper(opts);\n\n\t\tthis.#options = opts.options;\n\t\tthis.#placeholder = opts.placeholder;\n\t\tconst options = this.options;\n\t\tthis.filteredOptions = [...options];\n\t\tthis.multiple = opts.multiple === true;\n\t\tthis.#filterFn = opts.filter ?? defaultFilter;\n\t\tlet initialValues: unknown[] | undefined;\n\t\tif (opts.initialValue && Array.isArray(opts.initialValue)) {\n\t\t\tif (this.multiple) {\n\t\t\t\tinitialValues = opts.initialValue;\n\t\t\t} else {\n\t\t\t\tinitialValues = opts.initialValue.slice(0, 1);\n\t\t\t}\n\t\t} else {\n\t\t\tif (!this.multiple && this.options.length > 0) {\n\t\t\t\tinitialValues = [this.options[0].value];\n\t\t\t}\n\t\t}\n\n\t\tif (initialValues) {\n\t\t\tfor (const selectedValue of initialValues) {\n\t\t\t\tconst selectedIndex = options.findIndex((opt) => opt.value === selectedValue);\n\t\t\t\tif (selectedIndex !== -1) {\n\t\t\t\t\tthis.toggleSelected(selectedValue);\n\t\t\t\t\tthis.#cursor = selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.focusedValue = this.options[this.#cursor]?.value;\n\n\t\tthis.on('key', (char, key) => this.#onKey(char, key));\n\t\tthis.on('userInput', (value) => this.#onUserInputChanged(value));\n\t}\n\n\tprotected override _isActionKey(char: string | undefined, key: Key): boolean {\n\t\treturn (\n\t\t\tchar === '\\t' ||\n\t\t\t(this.multiple &&\n\t\t\t\tthis.isNavigating &&\n\t\t\t\tkey.name === 'space' &&\n\t\t\t\tchar !== undefined &&\n\t\t\t\tchar !== '')\n\t\t);\n\t}\n\n\t#onKey(_char: string | undefined, key: Key): void {\n\t\tconst isUpKey = key.name === 'up';\n\t\tconst isDownKey = key.name === 'down';\n\t\tconst isReturnKey = key.name === 'return';\n\n\t\t// Tab with empty input and placeholder: fill input with placeholder to trigger autocomplete\n\t\t// Only when the placeholder matches at least one (non-disabled) option so the value remains selectable\n\t\tconst isEmptyOrOnlyTab = this.userInput === '' || this.userInput === '\\t';\n\t\tconst placeholder = this.#placeholder;\n\t\tconst options = this.options;\n\t\tconst placeholderMatchesOption =\n\t\t\tplaceholder !== undefined &&\n\t\t\tplaceholder !== '' &&\n\t\t\toptions.some((opt) => !opt.disabled && this.#filterFn(placeholder, opt));\n\t\tif (key.name === 'tab' && isEmptyOrOnlyTab && placeholderMatchesOption) {\n\t\t\tif (this.userInput === '\\t') {\n\t\t\t\tthis._clearUserInput();\n\t\t\t}\n\t\t\tthis._setUserInput(placeholder, true);\n\t\t\tthis.isNavigating = false;\n\t\t\treturn;\n\t\t}\n\n\t\t// Start navigation mode with up/down arrows\n\t\tif (isUpKey || isDownKey) {\n\t\t\tthis.#cursor = findCursor(this.#cursor, isUpKey ? -1 : 1, this.filteredOptions);\n\t\t\tthis.focusedValue = this.filteredOptions[this.#cursor]?.value;\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.selectedValues = [this.focusedValue];\n\t\t\t}\n\t\t\tthis.isNavigating = true;\n\t\t} else if (isReturnKey) {\n\t\t\tthis.value = normalisedValue(this.multiple, this.selectedValues);\n\t\t} else {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (\n\t\t\t\t\tthis.focusedValue !== undefined &&\n\t\t\t\t\t(key.name === 'tab' || (this.isNavigating && key.name === 'space'))\n\t\t\t\t) {\n\t\t\t\t\tthis.toggleSelected(this.focusedValue);\n\t\t\t\t} else {\n\t\t\t\t\tthis.isNavigating = false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.focusedValue) {\n\t\t\t\t\tthis.selectedValues = [this.focusedValue];\n\t\t\t\t}\n\t\t\t\tthis.isNavigating = false;\n\t\t\t}\n\t\t}\n\t}\n\n\tdeselectAll() {\n\t\tthis.selectedValues = [];\n\t}\n\n\ttoggleSelected(value: T['value']) {\n\t\tif (this.filteredOptions.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.multiple) {\n\t\t\tif (this.selectedValues.includes(value)) {\n\t\t\t\tthis.selectedValues = this.selectedValues.filter((v) => v !== value);\n\t\t\t} else {\n\t\t\t\tthis.selectedValues = [...this.selectedValues, value];\n\t\t\t}\n\t\t} else {\n\t\t\tthis.selectedValues = [value];\n\t\t}\n\t}\n\n\t#onUserInputChanged(value: string): void {\n\t\tif (value !== this.#lastUserInput) {\n\t\t\tthis.#lastUserInput = value;\n\n\t\t\tconst options = this.options;\n\n\t\t\tif (value) {\n\t\t\t\tthis.filteredOptions = options.filter((opt) => this.#filterFn(value, opt));\n\t\t\t} else {\n\t\t\t\tthis.filteredOptions = [...options];\n\t\t\t}\n\t\t\tconst valueCursor = getCursorForValue(this.focusedValue, this.filteredOptions);\n\t\t\tthis.#cursor = findCursor(valueCursor, 0, this.filteredOptions);\n\t\t\tconst focusedOption = this.filteredOptions[this.#cursor];\n\t\t\tif (focusedOption && !focusedOption.disabled) {\n\t\t\t\tthis.focusedValue = focusedOption.value;\n\t\t\t} else {\n\t\t\t\tthis.focusedValue = undefined;\n\t\t\t}\n\t\t\tif (!this.multiple) {\n\t\t\t\tif (this.focusedValue !== undefined) {\n\t\t\t\t\tthis.toggleSelected(this.focusedValue);\n\t\t\t\t} else {\n\t\t\t\t\tthis.deselectAll();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/confirm.ts",
    "content": "import { cursor } from 'sisteransi';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface ConfirmOptions extends PromptOptions<boolean, ConfirmPrompt> {\n\tactive: string;\n\tinactive: string;\n\tinitialValue?: boolean;\n}\n\nexport default class ConfirmPrompt extends Prompt<boolean> {\n\tget cursor() {\n\t\treturn this.value ? 0 : 1;\n\t}\n\n\tprivate get _value() {\n\t\treturn this.cursor === 0;\n\t}\n\n\tconstructor(opts: ConfirmOptions) {\n\t\tsuper(opts, false);\n\t\tthis.value = !!opts.initialValue;\n\n\t\tthis.on('userInput', () => {\n\t\t\tthis.value = this._value;\n\t\t});\n\n\t\tthis.on('confirm', (confirm) => {\n\t\t\tthis.output.write(cursor.move(0, -1));\n\t\t\tthis.value = confirm;\n\t\t\tthis.state = 'submit';\n\t\t\tthis.close();\n\t\t});\n\n\t\tthis.on('cursor', () => {\n\t\t\tthis.value = !this.value;\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/date.ts",
    "content": "import type { Key } from 'node:readline';\nimport { settings } from '../utils/settings.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface SegmentConfig {\n\ttype: 'year' | 'month' | 'day';\n\tlen: number;\n}\n\nexport interface DateParts {\n\tyear: string;\n\tmonth: string;\n\tday: string;\n}\n\nexport type DateFormat = 'YMD' | 'MDY' | 'DMY';\n\nconst SEGMENTS: Record<string, SegmentConfig> = {\n\tY: { type: 'year', len: 4 },\n\tM: { type: 'month', len: 2 },\n\tD: { type: 'day', len: 2 },\n} as const;\n\nfunction segmentsFor(fmt: DateFormat): SegmentConfig[] {\n\treturn [...fmt].map((c) => SEGMENTS[c as keyof typeof SEGMENTS]);\n}\n\nfunction detectLocaleFormat(locale?: string): { segments: SegmentConfig[]; separator: string } {\n\tconst fmt = new Intl.DateTimeFormat(locale, {\n\t\tyear: 'numeric',\n\t\tmonth: '2-digit',\n\t\tday: '2-digit',\n\t});\n\tconst parts = fmt.formatToParts(new Date(2000, 0, 15));\n\tconst segments: SegmentConfig[] = [];\n\tlet separator = '/';\n\tfor (const p of parts) {\n\t\tif (p.type === 'literal') {\n\t\t\tseparator = p.value.trim() || p.value;\n\t\t} else if (p.type === 'year' || p.type === 'month' || p.type === 'day') {\n\t\t\tsegments.push({ type: p.type, len: p.type === 'year' ? 4 : 2 });\n\t\t}\n\t}\n\treturn { segments, separator };\n}\n\n/** Parse string segment values to numbers, treating blanks as 0 */\nfunction parseSegmentToNum(s: string): number {\n\treturn Number.parseInt((s || '0').replace(/_/g, '0'), 10) || 0;\n}\n\nfunction parse(parts: DateParts): { year: number; month: number; day: number } {\n\treturn {\n\t\tyear: parseSegmentToNum(parts.year),\n\t\tmonth: parseSegmentToNum(parts.month),\n\t\tday: parseSegmentToNum(parts.day),\n\t};\n}\n\nfunction daysInMonth(year: number, month: number): number {\n\treturn new Date(year || 2001, month || 1, 0).getDate();\n}\n\n/** Validate and return calendar parts, or undefined if invalid */\nfunction validParts(parts: DateParts): { year: number; month: number; day: number } | undefined {\n\tconst { year, month, day } = parse(parts);\n\tif (!year || year < 0 || year > 9999) return undefined;\n\tif (!month || month < 1 || month > 12) return undefined;\n\tif (!day || day < 1) return undefined;\n\tconst d = new Date(Date.UTC(year, month - 1, day));\n\tif (d.getUTCFullYear() !== year || d.getUTCMonth() !== month - 1 || d.getUTCDate() !== day)\n\t\treturn undefined;\n\treturn { year, month, day };\n}\n\nfunction toDate(parts: DateParts): Date | undefined {\n\tconst p = validParts(parts);\n\treturn p ? new Date(Date.UTC(p.year, p.month - 1, p.day)) : undefined;\n}\n\nfunction segmentBounds(\n\ttype: 'year' | 'month' | 'day',\n\tctx: { year: number; month: number },\n\tminDate: Date | undefined,\n\tmaxDate: Date | undefined\n): { min: number; max: number } {\n\tconst minP = minDate\n\t\t? {\n\t\t\t\tyear: minDate.getUTCFullYear(),\n\t\t\t\tmonth: minDate.getUTCMonth() + 1,\n\t\t\t\tday: minDate.getUTCDate(),\n\t\t\t}\n\t\t: null;\n\tconst maxP = maxDate\n\t\t? {\n\t\t\t\tyear: maxDate.getUTCFullYear(),\n\t\t\t\tmonth: maxDate.getUTCMonth() + 1,\n\t\t\t\tday: maxDate.getUTCDate(),\n\t\t\t}\n\t\t: null;\n\n\tif (type === 'year') {\n\t\treturn { min: minP?.year ?? 1, max: maxP?.year ?? 9999 };\n\t}\n\tif (type === 'month') {\n\t\treturn {\n\t\t\tmin: minP && ctx.year === minP.year ? minP.month : 1,\n\t\t\tmax: maxP && ctx.year === maxP.year ? maxP.month : 12,\n\t\t};\n\t}\n\treturn {\n\t\tmin: minP && ctx.year === minP.year && ctx.month === minP.month ? minP.day : 1,\n\t\tmax:\n\t\t\tmaxP && ctx.year === maxP.year && ctx.month === maxP.month\n\t\t\t\t? maxP.day\n\t\t\t\t: daysInMonth(ctx.year, ctx.month),\n\t};\n}\n\nexport interface DateOptions extends PromptOptions<Date, DatePrompt> {\n\tformat?: DateFormat;\n\tlocale?: string;\n\tseparator?: string;\n\tdefaultValue?: Date;\n\tinitialValue?: Date;\n\tminDate?: Date;\n\tmaxDate?: Date;\n}\n\nexport default class DatePrompt extends Prompt<Date> {\n\t#segments: SegmentConfig[];\n\t#separator: string;\n\t#segmentValues: DateParts;\n\t#minDate: Date | undefined;\n\t#maxDate: Date | undefined;\n\t#cursor = { segmentIndex: 0, positionInSegment: 0 };\n\t#segmentSelected = true;\n\t#pendingTensDigit: string | null = null;\n\n\tinlineError = '';\n\n\tget segmentCursor() {\n\t\treturn { ...this.#cursor };\n\t}\n\n\tget segmentValues(): DateParts {\n\t\treturn { ...this.#segmentValues };\n\t}\n\n\tget segments(): readonly SegmentConfig[] {\n\t\treturn this.#segments;\n\t}\n\n\tget separator(): string {\n\t\treturn this.#separator;\n\t}\n\n\tget formattedValue(): string {\n\t\treturn this.#format(this.#segmentValues);\n\t}\n\n\t#format(parts: DateParts): string {\n\t\treturn this.#segments.map((s) => parts[s.type]).join(this.#separator);\n\t}\n\n\t#refresh() {\n\t\tthis._setUserInput(this.#format(this.#segmentValues));\n\t\tthis._setValue(toDate(this.#segmentValues) ?? undefined);\n\t}\n\n\tconstructor(opts: DateOptions) {\n\t\tconst detected = opts.format\n\t\t\t? { segments: segmentsFor(opts.format), separator: opts.separator ?? '/' }\n\t\t\t: detectLocaleFormat(opts.locale);\n\t\tconst sep = opts.separator ?? detected.separator;\n\t\tconst segments = opts.format ? segmentsFor(opts.format) : detected.segments;\n\n\t\tconst initialDate = opts.initialValue ?? opts.defaultValue;\n\t\tconst segmentValues: DateParts = initialDate\n\t\t\t? {\n\t\t\t\t\tyear: String(initialDate.getUTCFullYear()).padStart(4, '0'),\n\t\t\t\t\tmonth: String(initialDate.getUTCMonth() + 1).padStart(2, '0'),\n\t\t\t\t\tday: String(initialDate.getUTCDate()).padStart(2, '0'),\n\t\t\t\t}\n\t\t\t: { year: '____', month: '__', day: '__' };\n\n\t\tconst initialDisplay = segments.map((s) => segmentValues[s.type]).join(sep);\n\n\t\tsuper({ ...opts, initialUserInput: initialDisplay }, false);\n\t\tthis.#segments = segments;\n\t\tthis.#separator = sep;\n\t\tthis.#segmentValues = segmentValues;\n\t\tthis.#minDate = opts.minDate;\n\t\tthis.#maxDate = opts.maxDate;\n\t\tthis.#refresh();\n\n\t\tthis.on('cursor', (key) => this.#onCursor(key));\n\t\tthis.on('key', (char, key) => this.#onKey(char, key));\n\t\tthis.on('finalize', () => this.#onFinalize(opts));\n\t}\n\n\t#seg(): { segment: SegmentConfig; index: number } | undefined {\n\t\tconst index = Math.max(0, Math.min(this.#cursor.segmentIndex, this.#segments.length - 1));\n\t\tconst segment = this.#segments[index];\n\t\tif (!segment) return undefined;\n\t\tthis.#cursor.positionInSegment = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.#cursor.positionInSegment, segment.len - 1)\n\t\t);\n\t\treturn { segment, index };\n\t}\n\n\t#navigate(direction: 1 | -1) {\n\t\tthis.inlineError = '';\n\t\tthis.#pendingTensDigit = null;\n\t\tconst ctx = this.#seg();\n\t\tif (!ctx) return;\n\t\tthis.#cursor.segmentIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.#segments.length - 1, ctx.index + direction)\n\t\t);\n\t\tthis.#cursor.positionInSegment = 0;\n\t\tthis.#segmentSelected = true;\n\t}\n\n\t#adjust(direction: 1 | -1) {\n\t\tconst ctx = this.#seg();\n\t\tif (!ctx) return;\n\t\tconst { segment } = ctx;\n\t\tconst raw = this.#segmentValues[segment.type];\n\t\tconst isBlank = !raw || raw.replace(/_/g, '') === '';\n\t\tconst num = Number.parseInt((raw || '0').replace(/_/g, '0'), 10) || 0;\n\t\tconst bounds = segmentBounds(\n\t\t\tsegment.type,\n\t\t\tparse(this.#segmentValues),\n\t\t\tthis.#minDate,\n\t\t\tthis.#maxDate\n\t\t);\n\n\t\tlet next: number;\n\t\tif (isBlank) {\n\t\t\tnext = direction === 1 ? bounds.min : bounds.max;\n\t\t} else {\n\t\t\tnext = Math.max(Math.min(bounds.max, num + direction), bounds.min);\n\t\t}\n\n\t\tthis.#segmentValues = {\n\t\t\t...this.#segmentValues,\n\t\t\t[segment.type]: next.toString().padStart(segment.len, '0'),\n\t\t};\n\t\tthis.#segmentSelected = true;\n\t\tthis.#pendingTensDigit = null;\n\t\tthis.#refresh();\n\t}\n\n\t#onCursor(key?: string) {\n\t\tif (!key) return;\n\t\tswitch (key) {\n\t\t\tcase 'right':\n\t\t\t\treturn this.#navigate(1);\n\t\t\tcase 'left':\n\t\t\t\treturn this.#navigate(-1);\n\t\t\tcase 'up':\n\t\t\t\treturn this.#adjust(1);\n\t\t\tcase 'down':\n\t\t\t\treturn this.#adjust(-1);\n\t\t}\n\t}\n\n\t#onKey(char: string | undefined, key: Key) {\n\t\t// Backspace\n\t\tconst isBackspace =\n\t\t\tkey?.name === 'backspace' ||\n\t\t\tkey?.sequence === '\\x7f' ||\n\t\t\tkey?.sequence === '\\b' ||\n\t\t\tchar === '\\x7f' ||\n\t\t\tchar === '\\b';\n\t\tif (isBackspace) {\n\t\t\tthis.inlineError = '';\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tif (!this.#segmentValues[ctx.segment.type].replace(/_/g, '')) {\n\t\t\t\tthis.#navigate(-1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.#segmentValues[ctx.segment.type] = '_'.repeat(ctx.segment.len);\n\t\t\tthis.#segmentSelected = true;\n\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\tthis.#refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Tab navigation\n\t\tif (key?.name === 'tab') {\n\t\t\tthis.inlineError = '';\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tconst dir = key.shift ? -1 : 1;\n\t\t\tconst next = ctx.index + dir;\n\t\t\tif (next >= 0 && next < this.#segments.length) {\n\t\t\t\tthis.#cursor.segmentIndex = next;\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Digit input\n\t\tif (char && /^[0-9]$/.test(char)) {\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tconst { segment } = ctx;\n\t\t\tconst isBlank = !this.#segmentValues[segment.type].replace(/_/g, '');\n\n\t\t\t// Pending tens digit: complete the two-digit entry\n\t\t\tif (this.#segmentSelected && this.#pendingTensDigit !== null && !isBlank) {\n\t\t\t\tconst newVal = this.#pendingTensDigit + char;\n\t\t\t\tconst newParts = { ...this.#segmentValues, [segment.type]: newVal };\n\t\t\t\tconst err = this.#validateSegment(newParts, segment);\n\t\t\t\tif (err) {\n\t\t\t\t\tthis.inlineError = err;\n\t\t\t\t\tthis.#pendingTensDigit = null;\n\t\t\t\t\tthis.#segmentSelected = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.inlineError = '';\n\t\t\t\tthis.#segmentValues[segment.type] = newVal;\n\t\t\t\tthis.#pendingTensDigit = null;\n\t\t\t\tthis.#segmentSelected = false;\n\t\t\t\tthis.#refresh();\n\t\t\t\tif (ctx.index < this.#segments.length - 1) {\n\t\t\t\t\tthis.#cursor.segmentIndex = ctx.index + 1;\n\t\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\t\tthis.#segmentSelected = true;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear-on-type: typing into a selected filled segment clears it first\n\t\t\tif (this.#segmentSelected && !isBlank) {\n\t\t\t\tthis.#segmentValues[segment.type] = '_'.repeat(segment.len);\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t}\n\t\t\tthis.#segmentSelected = false;\n\t\t\tthis.#pendingTensDigit = null;\n\n\t\t\tconst display = this.#segmentValues[segment.type];\n\t\t\tconst firstBlank = display.indexOf('_');\n\t\t\tconst pos =\n\t\t\t\tfirstBlank >= 0 ? firstBlank : Math.min(this.#cursor.positionInSegment, segment.len - 1);\n\t\t\tif (pos < 0 || pos >= segment.len) return;\n\n\t\t\tlet newVal = display.slice(0, pos) + char + display.slice(pos + 1);\n\n\t\t\t// Smart digit placement\n\t\t\tlet shouldStaySelected = false;\n\t\t\tif (pos === 0 && display === '__' && (segment.type === 'month' || segment.type === 'day')) {\n\t\t\t\tconst digit = Number.parseInt(char, 10);\n\t\t\t\tnewVal = `0${char}`;\n\t\t\t\tshouldStaySelected = digit <= (segment.type === 'month' ? 1 : 2);\n\t\t\t}\n\t\t\tif (segment.type === 'year') {\n\t\t\t\tconst digits = display.replace(/_/g, '');\n\t\t\t\tnewVal = (digits + char).padStart(segment.len, '_');\n\t\t\t}\n\n\t\t\tif (!newVal.includes('_')) {\n\t\t\t\tconst newParts = { ...this.#segmentValues, [segment.type]: newVal };\n\t\t\t\tconst err = this.#validateSegment(newParts, segment);\n\t\t\t\tif (err) {\n\t\t\t\t\tthis.inlineError = err;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.inlineError = '';\n\n\t\t\tthis.#segmentValues[segment.type] = newVal;\n\n\t\t\t// Clamp only when the current segment is fully entered\n\t\t\tconst parsed = !newVal.includes('_') ? validParts(this.#segmentValues) : undefined;\n\t\t\tif (parsed) {\n\t\t\t\tconst { year, month } = parsed;\n\t\t\t\tconst maxDay = daysInMonth(year, month);\n\t\t\t\tthis.#segmentValues = {\n\t\t\t\t\tyear: String(Math.max(0, Math.min(9999, year))).padStart(4, '0'),\n\t\t\t\t\tmonth: String(Math.max(1, Math.min(12, month))).padStart(2, '0'),\n\t\t\t\t\tday: String(Math.max(1, Math.min(maxDay, parsed.day))).padStart(2, '0'),\n\t\t\t\t};\n\t\t\t}\n\t\t\tthis.#refresh();\n\n\t\t\t// Advance cursor\n\t\t\tconst nextBlank = newVal.indexOf('_');\n\t\t\tif (shouldStaySelected) {\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t\tthis.#pendingTensDigit = char;\n\t\t\t} else if (nextBlank >= 0) {\n\t\t\t\tthis.#cursor.positionInSegment = nextBlank;\n\t\t\t} else if (firstBlank >= 0 && ctx.index < this.#segments.length - 1) {\n\t\t\t\tthis.#cursor.segmentIndex = ctx.index + 1;\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t} else {\n\t\t\t\tthis.#cursor.positionInSegment = Math.min(pos + 1, segment.len - 1);\n\t\t\t}\n\t\t}\n\t}\n\n\t#validateSegment(parts: DateParts, seg: SegmentConfig): string | undefined {\n\t\tconst { month, day } = parse(parts);\n\t\tif (seg.type === 'month' && (month < 0 || month > 12)) {\n\t\t\treturn settings.date.messages.invalidMonth;\n\t\t}\n\t\tif (seg.type === 'day' && (day < 0 || day > 31)) {\n\t\t\treturn settings.date.messages.invalidDay(31, 'any month');\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t#onFinalize(opts: DateOptions) {\n\t\tconst { year, month, day } = parse(this.#segmentValues);\n\t\tif (year && month && day) {\n\t\t\tconst maxDay = daysInMonth(year, month);\n\t\t\tthis.#segmentValues = {\n\t\t\t\t...this.#segmentValues,\n\t\t\t\tday: String(Math.min(day, maxDay)).padStart(2, '0'),\n\t\t\t};\n\t\t}\n\t\tthis.value = toDate(this.#segmentValues) ?? opts.defaultValue ?? undefined;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/group-multiselect.ts",
    "content": "import Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface GroupMultiSelectOptions<T extends { value: any }>\n\textends PromptOptions<T['value'][], GroupMultiSelectPrompt<T>> {\n\toptions: Record<string, T[]>;\n\tinitialValues?: T['value'][];\n\trequired?: boolean;\n\tcursorAt?: T['value'];\n\tselectableGroups?: boolean;\n}\nexport default class GroupMultiSelectPrompt<T extends { value: any }> extends Prompt<T['value'][]> {\n\toptions: (T & { group: string | boolean })[];\n\tcursor = 0;\n\t#selectableGroups: boolean;\n\n\tgetGroupItems(group: string): T[] {\n\t\treturn this.options.filter((o) => o.group === group);\n\t}\n\n\tisGroupSelected(group: string) {\n\t\tconst items = this.getGroupItems(group);\n\t\tconst value = this.value;\n\t\tif (value === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\treturn items.every((i) => value.includes(i.value));\n\t}\n\n\tprivate toggleValue() {\n\t\tconst item = this.options[this.cursor];\n\t\tif (this.value === undefined) {\n\t\t\tthis.value = [];\n\t\t}\n\t\tif (item.group === true) {\n\t\t\tconst group = item.value;\n\t\t\tconst groupedItems = this.getGroupItems(group);\n\t\t\tif (this.isGroupSelected(group)) {\n\t\t\t\tthis.value = this.value.filter(\n\t\t\t\t\t(v: string) => groupedItems.findIndex((i) => i.value === v) === -1\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.value = [...this.value, ...groupedItems.map((i) => i.value)];\n\t\t\t}\n\t\t\tthis.value = Array.from(new Set(this.value));\n\t\t} else {\n\t\t\tconst selected = this.value.includes(item.value);\n\t\t\tthis.value = selected\n\t\t\t\t? this.value.filter((v: T['value']) => v !== item.value)\n\t\t\t\t: [...this.value, item.value];\n\t\t}\n\t}\n\n\tconstructor(opts: GroupMultiSelectOptions<T>) {\n\t\tsuper(opts, false);\n\t\tconst { options } = opts;\n\t\tthis.#selectableGroups = opts.selectableGroups !== false;\n\t\tthis.options = Object.entries(options).flatMap(([key, option]) => [\n\t\t\t{ value: key, group: true, label: key },\n\t\t\t...option.map((opt) => ({ ...opt, group: key })),\n\t\t]) as any;\n\t\tthis.value = [...(opts.initialValues ?? [])];\n\t\tthis.cursor = Math.max(\n\t\t\tthis.options.findIndex(({ value }) => value === opts.cursorAt),\n\t\t\tthis.#selectableGroups ? 0 : 1\n\t\t);\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up': {\n\t\t\t\t\tthis.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;\n\t\t\t\t\tconst currentIsGroup = this.options[this.cursor]?.group === true;\n\t\t\t\t\tif (!this.#selectableGroups && currentIsGroup) {\n\t\t\t\t\t\tthis.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right': {\n\t\t\t\t\tthis.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;\n\t\t\t\t\tconst currentIsGroup = this.options[this.cursor]?.group === true;\n\t\t\t\t\tif (!this.#selectableGroups && currentIsGroup) {\n\t\t\t\t\t\tthis.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'space':\n\t\t\t\t\tthis.toggleValue();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/multi-select.ts",
    "content": "import { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface OptionLike {\n\tvalue: any;\n\tdisabled?: boolean;\n}\n\nexport interface MultiSelectOptions<T extends OptionLike>\n\textends PromptOptions<T['value'][], MultiSelectPrompt<T>> {\n\toptions: T[];\n\tinitialValues?: T['value'][];\n\trequired?: boolean;\n\tcursorAt?: T['value'];\n}\nexport default class MultiSelectPrompt<T extends OptionLike> extends Prompt<T['value'][]> {\n\toptions: T[];\n\tcursor = 0;\n\n\tprivate get _value(): T['value'] {\n\t\treturn this.options[this.cursor].value;\n\t}\n\n\tprivate get _enabledOptions(): T[] {\n\t\treturn this.options.filter((option) => option.disabled !== true);\n\t}\n\n\tprivate toggleAll() {\n\t\tconst enabledOptions = this._enabledOptions;\n\t\tconst allSelected = this.value !== undefined && this.value.length === enabledOptions.length;\n\t\tthis.value = allSelected ? [] : enabledOptions.map((v) => v.value);\n\t}\n\n\tprivate toggleInvert() {\n\t\tconst value = this.value;\n\t\tif (!value) {\n\t\t\treturn;\n\t\t}\n\t\tconst notSelected = this._enabledOptions.filter((v) => !value.includes(v.value));\n\t\tthis.value = notSelected.map((v) => v.value);\n\t}\n\n\tprivate toggleValue() {\n\t\tif (this.value === undefined) {\n\t\t\tthis.value = [];\n\t\t}\n\t\tconst selected = this.value.includes(this._value);\n\t\tthis.value = selected\n\t\t\t? this.value.filter((value) => value !== this._value)\n\t\t\t: [...this.value, this._value];\n\t}\n\n\tconstructor(opts: MultiSelectOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\t\tthis.value = [...(opts.initialValues ?? [])];\n\t\tconst cursor = Math.max(\n\t\t\tthis.options.findIndex(({ value }) => value === opts.cursorAt),\n\t\t\t0\n\t\t);\n\t\tthis.cursor = this.options[cursor].disabled ? findCursor<T>(cursor, 1, this.options) : cursor;\n\t\tthis.on('key', (char) => {\n\t\t\tif (char === 'a') {\n\t\t\t\tthis.toggleAll();\n\t\t\t}\n\t\t\tif (char === 'i') {\n\t\t\t\tthis.toggleInvert();\n\t\t\t}\n\t\t});\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, -1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, 1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'space':\n\t\t\t\t\tthis.toggleValue();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/password.ts",
    "content": "import { styleText } from 'node:util';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface PasswordOptions extends PromptOptions<string, PasswordPrompt> {\n\tmask?: string;\n}\nexport default class PasswordPrompt extends Prompt<string> {\n\tprivate _mask = '•';\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\tget masked() {\n\t\treturn this.userInput.replaceAll(/./g, this._mask);\n\t}\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\treturn this.masked;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${this.masked}${styleText(['inverse', 'hidden'], '_')}`;\n\t\t}\n\t\tconst masked = this.masked;\n\t\tconst s1 = masked.slice(0, this.cursor);\n\t\tconst s2 = masked.slice(this.cursor);\n\t\treturn `${s1}${styleText('inverse', s2[0])}${s2.slice(1)}`;\n\t}\n\tclear() {\n\t\tthis._clearUserInput();\n\t}\n\tconstructor({ mask, ...opts }: PasswordOptions) {\n\t\tsuper(opts);\n\t\tthis._mask = mask ?? '•';\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/prompt.ts",
    "content": "import { stdin, stdout } from 'node:process';\nimport readline, { type Key, type ReadLine } from 'node:readline';\nimport type { Readable, Writable } from 'node:stream';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor, erase } from 'sisteransi';\nimport type { ClackEvents, ClackState } from '../types.js';\nimport type { Action } from '../utils/index.js';\nimport {\n\tCANCEL_SYMBOL,\n\tdiffLines,\n\tgetRows,\n\tisActionKey,\n\tsetRawMode,\n\tsettings,\n} from '../utils/index.js';\n\nexport interface PromptOptions<TValue, Self extends Prompt<TValue>> {\n\trender(this: Omit<Self, 'prompt'>): string | undefined;\n\tinitialValue?: any;\n\tinitialUserInput?: string;\n\tvalidate?: ((value: TValue | undefined) => string | Error | undefined) | undefined;\n\tinput?: Readable;\n\toutput?: Writable;\n\tdebug?: boolean;\n\tsignal?: AbortSignal;\n}\n\nexport default class Prompt<TValue> {\n\tprotected input: Readable;\n\tprotected output: Writable;\n\tprivate _abortSignal?: AbortSignal;\n\n\tprivate rl: ReadLine | undefined;\n\tprivate opts: Omit<PromptOptions<TValue, Prompt<TValue>>, 'render' | 'input' | 'output'>;\n\tprivate _render: (context: Omit<Prompt<TValue>, 'prompt'>) => string | undefined;\n\tprivate _track = false;\n\tprivate _prevFrame = '';\n\tprivate _subscribers = new Map<string, { cb: (...args: any) => any; once?: boolean }[]>();\n\tprotected _cursor = 0;\n\n\tpublic state: ClackState = 'initial';\n\tpublic error = '';\n\tpublic value: TValue | undefined;\n\tpublic userInput = '';\n\n\tconstructor(options: PromptOptions<TValue, Prompt<TValue>>, trackValue = true) {\n\t\tconst { input = stdin, output = stdout, render, signal, ...opts } = options;\n\n\t\tthis.opts = opts;\n\t\tthis.onKeypress = this.onKeypress.bind(this);\n\t\tthis.close = this.close.bind(this);\n\t\tthis.render = this.render.bind(this);\n\t\tthis._render = render.bind(this);\n\t\tthis._track = trackValue;\n\t\tthis._abortSignal = signal;\n\n\t\tthis.input = input;\n\t\tthis.output = output;\n\t}\n\n\t/**\n\t * Unsubscribe all listeners\n\t */\n\tprotected unsubscribe() {\n\t\tthis._subscribers.clear();\n\t}\n\n\t/**\n\t * Set a subscriber with opts\n\t * @param event - The event name\n\t */\n\tprivate setSubscriber<T extends keyof ClackEvents<TValue>>(\n\t\tevent: T,\n\t\topts: { cb: ClackEvents<TValue>[T]; once?: boolean }\n\t) {\n\t\tconst params = this._subscribers.get(event) ?? [];\n\t\tparams.push(opts);\n\t\tthis._subscribers.set(event, params);\n\t}\n\n\t/**\n\t * Subscribe to an event\n\t * @param event - The event name\n\t * @param cb - The callback\n\t */\n\tpublic on<T extends keyof ClackEvents<TValue>>(event: T, cb: ClackEvents<TValue>[T]) {\n\t\tthis.setSubscriber(event, { cb });\n\t}\n\n\t/**\n\t * Subscribe to an event once\n\t * @param event - The event name\n\t * @param cb - The callback\n\t */\n\tpublic once<T extends keyof ClackEvents<TValue>>(event: T, cb: ClackEvents<TValue>[T]) {\n\t\tthis.setSubscriber(event, { cb, once: true });\n\t}\n\n\t/**\n\t * Emit an event with data\n\t * @param event - The event name\n\t * @param data - The data to pass to the callback\n\t */\n\tpublic emit<T extends keyof ClackEvents<TValue>>(\n\t\tevent: T,\n\t\t...data: Parameters<ClackEvents<TValue>[T]>\n\t) {\n\t\tconst cbs = this._subscribers.get(event) ?? [];\n\t\tconst cleanup: (() => void)[] = [];\n\n\t\tfor (const subscriber of cbs) {\n\t\t\tsubscriber.cb(...data);\n\n\t\t\tif (subscriber.once) {\n\t\t\t\tcleanup.push(() => cbs.splice(cbs.indexOf(subscriber), 1));\n\t\t\t}\n\t\t}\n\n\t\tfor (const cb of cleanup) {\n\t\t\tcb();\n\t\t}\n\t}\n\n\tpublic prompt() {\n\t\treturn new Promise<TValue | symbol | undefined>((resolve) => {\n\t\t\tif (this._abortSignal) {\n\t\t\t\tif (this._abortSignal.aborted) {\n\t\t\t\t\tthis.state = 'cancel';\n\n\t\t\t\t\tthis.close();\n\t\t\t\t\treturn resolve(CANCEL_SYMBOL);\n\t\t\t\t}\n\n\t\t\t\tthis._abortSignal.addEventListener(\n\t\t\t\t\t'abort',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.state = 'cancel';\n\t\t\t\t\t\tthis.close();\n\t\t\t\t\t},\n\t\t\t\t\t{ once: true }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.rl = readline.createInterface({\n\t\t\t\tinput: this.input,\n\t\t\t\ttabSize: 2,\n\t\t\t\tprompt: '',\n\t\t\t\tescapeCodeTimeout: 50,\n\t\t\t\tterminal: true,\n\t\t\t});\n\t\t\tthis.rl.prompt();\n\n\t\t\tif (this.opts.initialUserInput !== undefined) {\n\t\t\t\tthis._setUserInput(this.opts.initialUserInput, true);\n\t\t\t}\n\n\t\t\tthis.input.on('keypress', this.onKeypress);\n\t\t\tsetRawMode(this.input, true);\n\t\t\tthis.output.on('resize', this.render);\n\n\t\t\tthis.render();\n\n\t\t\tthis.once('submit', () => {\n\t\t\t\tthis.output.write(cursor.show);\n\t\t\t\tthis.output.off('resize', this.render);\n\t\t\t\tsetRawMode(this.input, false);\n\t\t\t\tresolve(this.value);\n\t\t\t});\n\t\t\tthis.once('cancel', () => {\n\t\t\t\tthis.output.write(cursor.show);\n\t\t\t\tthis.output.off('resize', this.render);\n\t\t\t\tsetRawMode(this.input, false);\n\t\t\t\tresolve(CANCEL_SYMBOL);\n\t\t\t});\n\t\t});\n\t}\n\n\tprotected _isActionKey(char: string | undefined, _key: Key): boolean {\n\t\treturn char === '\\t';\n\t}\n\n\tprotected _setValue(value: TValue | undefined): void {\n\t\tthis.value = value;\n\t\tthis.emit('value', this.value);\n\t}\n\n\tprotected _setUserInput(value: string | undefined, write?: boolean): void {\n\t\tthis.userInput = value ?? '';\n\t\tthis.emit('userInput', this.userInput);\n\t\tif (write && this._track && this.rl) {\n\t\t\tthis.rl.write(this.userInput);\n\t\t\tthis._cursor = this.rl.cursor;\n\t\t}\n\t}\n\n\tprotected _clearUserInput(): void {\n\t\tthis.rl?.write(null, { ctrl: true, name: 'u' });\n\t\tthis._setUserInput('');\n\t}\n\n\tprivate onKeypress(char: string | undefined, key: Key) {\n\t\tif (this._track && key.name !== 'return') {\n\t\t\tif (key.name && this._isActionKey(char, key)) {\n\t\t\t\tthis.rl?.write(null, { ctrl: true, name: 'h' });\n\t\t\t}\n\t\t\tthis._cursor = this.rl?.cursor ?? 0;\n\t\t\tthis._setUserInput(this.rl?.line);\n\t\t}\n\n\t\tif (this.state === 'error') {\n\t\t\tthis.state = 'active';\n\t\t}\n\t\tif (key?.name) {\n\t\t\tif (!this._track && settings.aliases.has(key.name)) {\n\t\t\t\tthis.emit('cursor', settings.aliases.get(key.name));\n\t\t\t}\n\t\t\tif (settings.actions.has(key.name as Action)) {\n\t\t\t\tthis.emit('cursor', key.name as Action);\n\t\t\t}\n\t\t}\n\t\tif (char && (char.toLowerCase() === 'y' || char.toLowerCase() === 'n')) {\n\t\t\tthis.emit('confirm', char.toLowerCase() === 'y');\n\t\t}\n\n\t\t// Call the key event handler and emit the key event\n\t\tthis.emit('key', char?.toLowerCase(), key);\n\n\t\tif (key?.name === 'return') {\n\t\t\tif (this.opts.validate) {\n\t\t\t\tconst problem = this.opts.validate(this.value);\n\t\t\t\tif (problem) {\n\t\t\t\t\tthis.error = problem instanceof Error ? problem.message : problem;\n\t\t\t\t\tthis.state = 'error';\n\t\t\t\t\tthis.rl?.write(this.userInput);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.state !== 'error') {\n\t\t\t\tthis.state = 'submit';\n\t\t\t}\n\t\t}\n\n\t\tif (isActionKey([char, key?.name, key?.sequence], 'cancel')) {\n\t\t\tthis.state = 'cancel';\n\t\t}\n\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\tthis.emit('finalize');\n\t\t}\n\t\tthis.render();\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\tprotected close() {\n\t\tthis.input.unpipe();\n\t\tthis.input.removeListener('keypress', this.onKeypress);\n\t\tthis.output.write('\\n');\n\t\tsetRawMode(this.input, false);\n\t\tthis.rl?.close();\n\t\tthis.rl = undefined;\n\t\tthis.emit(`${this.state}`, this.value);\n\t\tthis.unsubscribe();\n\t}\n\n\tprivate restoreCursor() {\n\t\tconst lines =\n\t\t\twrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split('\\n')\n\t\t\t\t.length - 1;\n\t\tthis.output.write(cursor.move(-999, lines * -1));\n\t}\n\n\tprivate render() {\n\t\tconst frame = wrapAnsi(this._render(this) ?? '', process.stdout.columns, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t});\n\t\tif (frame === this._prevFrame) return;\n\n\t\tif (this.state === 'initial') {\n\t\t\tthis.output.write(cursor.hide);\n\t\t} else {\n\t\t\tconst diff = diffLines(this._prevFrame, frame);\n\t\t\tconst rows = getRows(this.output);\n\t\t\tthis.restoreCursor();\n\t\t\tif (diff) {\n\t\t\t\tconst diffOffsetAfter = Math.max(0, diff.numLinesAfter - rows);\n\t\t\t\tconst diffOffsetBefore = Math.max(0, diff.numLinesBefore - rows);\n\t\t\t\tlet diffLine = diff.lines.find((line) => line >= diffOffsetAfter);\n\n\t\t\t\tif (diffLine === undefined) {\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If a single line has changed, only update that line\n\t\t\t\tif (diff.lines.length === 1) {\n\t\t\t\t\tthis.output.write(cursor.move(0, diffLine - diffOffsetBefore));\n\t\t\t\t\tthis.output.write(erase.lines(1));\n\t\t\t\t\tconst lines = frame.split('\\n');\n\t\t\t\t\tthis.output.write(lines[diffLine]);\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\tthis.output.write(cursor.move(0, lines.length - diffLine - 1));\n\t\t\t\t\treturn;\n\t\t\t\t\t// If many lines have changed, rerender everything past the first line\n\t\t\t\t} else if (diff.lines.length > 1) {\n\t\t\t\t\tif (diffOffsetAfter < diffOffsetBefore) {\n\t\t\t\t\t\tdiffLine = diffOffsetAfter;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst adjustedDiffLine = diffLine - diffOffsetBefore;\n\t\t\t\t\t\tif (adjustedDiffLine > 0) {\n\t\t\t\t\t\t\tthis.output.write(cursor.move(0, adjustedDiffLine));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.output.write(erase.down());\n\t\t\t\t\tconst lines = frame.split('\\n');\n\t\t\t\t\tconst newLines = lines.slice(diffLine);\n\t\t\t\t\tthis.output.write(newLines.join('\\n'));\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.output.write(erase.down());\n\t\t}\n\n\t\tthis.output.write(frame);\n\t\tif (this.state === 'initial') {\n\t\t\tthis.state = 'active';\n\t\t}\n\t\tthis._prevFrame = frame;\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/select-key.ts",
    "content": "import Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface SelectKeyOptions<T extends { value: string }>\n\textends PromptOptions<T['value'], SelectKeyPrompt<T>> {\n\toptions: T[];\n\tcaseSensitive?: boolean;\n}\nexport default class SelectKeyPrompt<T extends { value: string }> extends Prompt<T['value']> {\n\toptions: T[];\n\tcursor = 0;\n\n\tconstructor(opts: SelectKeyOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\t\tconst caseSensitive = opts.caseSensitive === true;\n\t\tconst keys = this.options.map(({ value: [initial] }) => {\n\t\t\treturn caseSensitive ? initial : initial?.toLowerCase();\n\t\t});\n\t\tthis.cursor = Math.max(keys.indexOf(opts.initialValue), 0);\n\n\t\tthis.on('key', (key, keyInfo) => {\n\t\t\tif (!key) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst casedKey = caseSensitive && keyInfo.shift ? key.toUpperCase() : key;\n\t\t\tif (!keys.includes(casedKey)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst value = this.options.find(({ value: [initial] }) => {\n\t\t\t\treturn caseSensitive ? initial === casedKey : initial?.toLowerCase() === key;\n\t\t\t});\n\t\t\tif (value) {\n\t\t\t\tthis.value = value.value;\n\t\t\t\tthis.state = 'submit';\n\t\t\t\tthis.emit('submit');\n\t\t\t}\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/select.ts",
    "content": "import { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface SelectOptions<T extends { value: any; disabled?: boolean }>\n\textends PromptOptions<T['value'], SelectPrompt<T>> {\n\toptions: T[];\n\tinitialValue?: T['value'];\n}\nexport default class SelectPrompt<T extends { value: any; disabled?: boolean }> extends Prompt<\n\tT['value']\n> {\n\toptions: T[];\n\tcursor = 0;\n\n\tprivate get _selectedValue() {\n\t\treturn this.options[this.cursor];\n\t}\n\n\tprivate changeValue() {\n\t\tthis.value = this._selectedValue.value;\n\t}\n\n\tconstructor(opts: SelectOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\n\t\tconst initialCursor = this.options.findIndex(({ value }) => value === opts.initialValue);\n\t\tconst cursor = initialCursor === -1 ? 0 : initialCursor;\n\t\tthis.cursor = this.options[cursor].disabled ? findCursor<T>(cursor, 1, this.options) : cursor;\n\t\tthis.changeValue();\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, -1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, 1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.changeValue();\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/prompts/text.ts",
    "content": "import { styleText } from 'node:util';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface TextOptions extends PromptOptions<string, TextPrompt> {\n\tplaceholder?: string;\n\tdefaultValue?: string;\n}\n\nexport default class TextPrompt extends Prompt<string> {\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit') {\n\t\t\treturn this.userInput;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${this.userInput}█`;\n\t\t}\n\t\tconst s1 = userInput.slice(0, this.cursor);\n\t\tconst [s2, ...s3] = userInput.slice(this.cursor);\n\t\treturn `${s1}${styleText('inverse', s2)}${s3.join('')}`;\n\t}\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\tconstructor(opts: TextOptions) {\n\t\tsuper({\n\t\t\t...opts,\n\t\t\tinitialUserInput: opts.initialUserInput ?? opts.initialValue,\n\t\t});\n\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t\tthis.on('finalize', () => {\n\t\t\tif (!this.value) {\n\t\t\t\tthis.value = opts.defaultValue;\n\t\t\t}\n\t\t\tif (this.value === undefined) {\n\t\t\t\tthis.value = '';\n\t\t\t}\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "packages/core/src/types.ts",
    "content": "import type { Key } from 'node:readline';\nimport type { Action } from './utils/settings.js';\n\n/**\n * The state of the prompt\n */\nexport type ClackState = 'initial' | 'active' | 'cancel' | 'submit' | 'error';\n\n/**\n * Typed event emitter for clack\n */\nexport interface ClackEvents<TValue> {\n\tinitial: (value?: any) => void;\n\tactive: (value?: any) => void;\n\tcancel: (value?: any) => void;\n\tsubmit: (value?: any) => void;\n\terror: (value?: any) => void;\n\tcursor: (key?: Action) => void;\n\tkey: (key: string | undefined, info: Key) => void;\n\tvalue: (value?: TValue) => void;\n\tuserInput: (value: string) => void;\n\tconfirm: (value?: boolean) => void;\n\tfinalize: () => void;\n\tbeforePrompt: () => void;\n}\n"
  },
  {
    "path": "packages/core/src/utils/cursor.ts",
    "content": "export function findCursor<T extends { disabled?: boolean }>(\n\tcursor: number,\n\tdelta: number,\n\toptions: T[]\n) {\n\tconst hasEnabledOptions = options.some((opt) => !opt.disabled);\n\tif (!hasEnabledOptions) {\n\t\treturn cursor;\n\t}\n\tconst newCursor = cursor + delta;\n\tconst maxCursor = Math.max(options.length - 1, 0);\n\tconst clampedCursor = newCursor < 0 ? maxCursor : newCursor > maxCursor ? 0 : newCursor;\n\tconst newOption = options[clampedCursor];\n\tif (newOption.disabled) {\n\t\treturn findCursor(clampedCursor, delta < 0 ? -1 : 1, options);\n\t}\n\treturn clampedCursor;\n}\n"
  },
  {
    "path": "packages/core/src/utils/index.ts",
    "content": "import { stdin, stdout } from 'node:process';\nimport type { Key } from 'node:readline';\nimport * as readline from 'node:readline';\nimport type { Readable, Writable } from 'node:stream';\nimport { ReadStream } from 'node:tty';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor } from 'sisteransi';\nimport { isActionKey } from './settings.js';\n\nexport * from './settings.js';\nexport * from './string.js';\n\nconst isWindows = globalThis.process.platform.startsWith('win');\n\nexport const CANCEL_SYMBOL = Symbol('clack:cancel');\n\nexport function isCancel(value: unknown): value is symbol {\n\treturn value === CANCEL_SYMBOL;\n}\n\nexport function setRawMode(input: Readable, value: boolean) {\n\tconst i = input as typeof stdin;\n\n\tif (i.isTTY) i.setRawMode(value);\n}\n\ninterface BlockOptions {\n\tinput?: Readable;\n\toutput?: Writable;\n\toverwrite?: boolean;\n\thideCursor?: boolean;\n}\n\nexport function block({\n\tinput = stdin,\n\toutput = stdout,\n\toverwrite = true,\n\thideCursor = true,\n}: BlockOptions = {}) {\n\tconst rl = readline.createInterface({\n\t\tinput,\n\t\toutput,\n\t\tprompt: '',\n\t\ttabSize: 1,\n\t});\n\treadline.emitKeypressEvents(input, rl);\n\n\tif (input instanceof ReadStream && input.isTTY) {\n\t\tinput.setRawMode(true);\n\t}\n\n\tconst clear = (data: Buffer, { name, sequence }: Key) => {\n\t\tconst str = String(data);\n\t\tif (isActionKey([str, name, sequence], 'cancel')) {\n\t\t\tif (hideCursor) output.write(cursor.show);\n\t\t\tprocess.exit(0);\n\t\t\treturn;\n\t\t}\n\t\tif (!overwrite) return;\n\t\tconst dx = name === 'return' ? 0 : -1;\n\t\tconst dy = name === 'return' ? -1 : 0;\n\n\t\treadline.moveCursor(output, dx, dy, () => {\n\t\t\treadline.clearLine(output, 1, () => {\n\t\t\t\tinput.once('keypress', clear);\n\t\t\t});\n\t\t});\n\t};\n\tif (hideCursor) output.write(cursor.hide);\n\tinput.once('keypress', clear);\n\n\treturn () => {\n\t\tinput.off('keypress', clear);\n\t\tif (hideCursor) output.write(cursor.show);\n\n\t\t// Prevent Windows specific issues: https://github.com/bombshell-dev/clack/issues/176\n\t\tif (input instanceof ReadStream && input.isTTY && !isWindows) {\n\t\t\tinput.setRawMode(false);\n\t\t}\n\n\t\t// @ts-expect-error fix for https://github.com/nodejs/node/issues/31762#issuecomment-1441223907\n\t\trl.terminal = false;\n\t\trl.close();\n\t};\n}\n\nexport const getColumns = (output: Writable): number => {\n\tif ('columns' in output && typeof output.columns === 'number') {\n\t\treturn output.columns;\n\t}\n\treturn 80;\n};\n\nexport const getRows = (output: Writable): number => {\n\tif ('rows' in output && typeof output.rows === 'number') {\n\t\treturn output.rows;\n\t}\n\treturn 20;\n};\n\nexport function wrapTextWithPrefix(\n\toutput: Writable | undefined,\n\ttext: string,\n\tprefix: string,\n\tstartPrefix: string = prefix\n): string {\n\tconst columns = getColumns(output ?? stdout);\n\tconst wrapped = wrapAnsi(text, columns - prefix.length, {\n\t\thard: true,\n\t\ttrim: false,\n\t});\n\tconst lines = wrapped\n\t\t.split('\\n')\n\t\t.map((line, index) => {\n\t\t\treturn `${index === 0 ? startPrefix : prefix}${line}`;\n\t\t})\n\t\t.join('\\n');\n\treturn lines;\n}\n"
  },
  {
    "path": "packages/core/src/utils/settings.ts",
    "content": "const actions = ['up', 'down', 'left', 'right', 'space', 'enter', 'cancel'] as const;\nexport type Action = (typeof actions)[number];\n\nconst DEFAULT_MONTH_NAMES = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\n\n/** Global settings for Clack programs, stored in memory */\ninterface InternalClackSettings {\n\tactions: Set<Action>;\n\taliases: Map<string, Action>;\n\tmessages: {\n\t\tcancel: string;\n\t\terror: string;\n\t};\n\twithGuide: boolean;\n\tdate: {\n\t\tmonthNames: string[];\n\t\tmessages: {\n\t\t\tinvalidMonth: string;\n\t\t\trequired: string;\n\t\t\tinvalidDay: (days: number, month: string) => string;\n\t\t\tafterMin: (min: Date) => string;\n\t\t\tbeforeMax: (max: Date) => string;\n\t\t};\n\t};\n}\n\nexport const settings: InternalClackSettings = {\n\tactions: new Set(actions),\n\taliases: new Map<string, Action>([\n\t\t// vim support\n\t\t['k', 'up'],\n\t\t['j', 'down'],\n\t\t['h', 'left'],\n\t\t['l', 'right'],\n\t\t['\\x03', 'cancel'],\n\t\t// opinionated defaults!\n\t\t['escape', 'cancel'],\n\t]),\n\tmessages: {\n\t\tcancel: 'Canceled',\n\t\terror: 'Something went wrong',\n\t},\n\twithGuide: true,\n\tdate: {\n\t\tmonthNames: [...DEFAULT_MONTH_NAMES],\n\t\tmessages: {\n\t\t\trequired: 'Please enter a valid date',\n\t\t\tinvalidMonth: 'There are only 12 months in a year',\n\t\t\tinvalidDay: (days, month) => `There are only ${days} days in ${month}`,\n\t\t\tafterMin: (min) => `Date must be on or after ${min.toISOString().slice(0, 10)}`,\n\t\t\tbeforeMax: (max) => `Date must be on or before ${max.toISOString().slice(0, 10)}`,\n\t\t},\n\t},\n};\n\nexport interface ClackSettings {\n\t/**\n\t * Set custom global aliases for the default actions.\n\t * This will not overwrite existing aliases, it will only add new ones!\n\t *\n\t * @param aliases - An object that maps aliases to actions\n\t * @default { k: 'up', j: 'down', h: 'left', l: 'right', '\\x03': 'cancel', 'escape': 'cancel' }\n\t */\n\taliases?: Record<string, Action>;\n\n\t/**\n\t * Custom messages for prompts\n\t */\n\tmessages?: {\n\t\t/**\n\t\t * Custom message to display when a spinner is cancelled\n\t\t * @default \"Canceled\"\n\t\t */\n\t\tcancel?: string;\n\t\t/**\n\t\t * Custom message to display when a spinner encounters an error\n\t\t * @default \"Something went wrong\"\n\t\t */\n\t\terror?: string;\n\t};\n\n\twithGuide?: boolean;\n\n\t/**\n\t * Date prompt localization\n\t */\n\tdate?: {\n\t\t/** Month names for validation messages (January, February, ...) */\n\t\tmonthNames?: string[];\n\t\tmessages?: {\n\t\t\t/** Shown when date is missing */\n\t\t\trequired?: string;\n\t\t\t/** Shown when month > 12 */\n\t\t\tinvalidMonth?: string;\n\t\t\t/** (days, monthName) => message for invalid day */\n\t\t\tinvalidDay?: (days: number, month: string) => string;\n\t\t\t/** (min) => message when date is before minDate */\n\t\t\tafterMin?: (min: Date) => string;\n\t\t\t/** (max) => message when date is after maxDate */\n\t\t\tbeforeMax?: (max: Date) => string;\n\t\t};\n\t};\n}\n\nexport function updateSettings(updates: ClackSettings) {\n\t// Handle each property in the updates\n\tif (updates.aliases !== undefined) {\n\t\tconst aliases = updates.aliases;\n\t\tfor (const alias in aliases) {\n\t\t\tif (!Object.hasOwn(aliases, alias)) continue;\n\n\t\t\tconst action = aliases[alias];\n\t\t\tif (!settings.actions.has(action)) continue;\n\n\t\t\tif (!settings.aliases.has(alias)) {\n\t\t\t\tsettings.aliases.set(alias, action);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (updates.messages !== undefined) {\n\t\tconst messages = updates.messages;\n\t\tif (messages.cancel !== undefined) {\n\t\t\tsettings.messages.cancel = messages.cancel;\n\t\t}\n\t\tif (messages.error !== undefined) {\n\t\t\tsettings.messages.error = messages.error;\n\t\t}\n\t}\n\n\tif (updates.withGuide !== undefined) {\n\t\tsettings.withGuide = updates.withGuide !== false;\n\t}\n\n\tif (updates.date !== undefined) {\n\t\tconst date = updates.date;\n\t\tif (date.monthNames !== undefined) {\n\t\t\tsettings.date.monthNames = [...date.monthNames];\n\t\t}\n\t\tif (date.messages !== undefined) {\n\t\t\tif (date.messages.required !== undefined) {\n\t\t\t\tsettings.date.messages.required = date.messages.required;\n\t\t\t}\n\t\t\tif (date.messages.invalidMonth !== undefined) {\n\t\t\t\tsettings.date.messages.invalidMonth = date.messages.invalidMonth;\n\t\t\t}\n\t\t\tif (date.messages.invalidDay !== undefined) {\n\t\t\t\tsettings.date.messages.invalidDay = date.messages.invalidDay;\n\t\t\t}\n\t\t\tif (date.messages.afterMin !== undefined) {\n\t\t\t\tsettings.date.messages.afterMin = date.messages.afterMin;\n\t\t\t}\n\t\t\tif (date.messages.beforeMax !== undefined) {\n\t\t\t\tsettings.date.messages.beforeMax = date.messages.beforeMax;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Check if a key is an alias for a default action\n * @param key - The raw key which might match to an action\n * @param action - The action to match\n * @returns boolean\n */\nexport function isActionKey(key: string | Array<string | undefined>, action: Action) {\n\tif (typeof key === 'string') {\n\t\treturn settings.aliases.get(key) === action;\n\t}\n\n\tfor (const value of key) {\n\t\tif (value === undefined) continue;\n\t\tif (isActionKey(value, action)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n"
  },
  {
    "path": "packages/core/src/utils/string.ts",
    "content": "export function diffLines(a: string, b: string) {\n\tif (a === b) return;\n\n\tconst aLines = a.split('\\n');\n\tconst bLines = b.split('\\n');\n\tconst numLines = Math.max(aLines.length, bLines.length);\n\tconst diff: number[] = [];\n\n\tfor (let i = 0; i < numLines; i++) {\n\t\tif (aLines[i] !== bLines[i]) diff.push(i);\n\t}\n\n\treturn {\n\t\tlines: diff,\n\t\tnumLinesBefore: aLines.length,\n\t\tnumLinesAfter: bLines.length,\n\t\tnumLines,\n\t};\n}\n"
  },
  {
    "path": "packages/core/test/mock-readable.ts",
    "content": "import { Readable } from 'node:stream';\n\nexport class MockReadable extends Readable {\n\tprotected _buffer: unknown[] | null = [];\n\n\t_read() {\n\t\tif (this._buffer === null) {\n\t\t\tthis.push(null);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const val of this._buffer) {\n\t\t\tthis.push(val);\n\t\t}\n\n\t\tthis._buffer = [];\n\t}\n\n\tpushValue(val: unknown): void {\n\t\tthis._buffer?.push(val);\n\t}\n\n\tclose(): void {\n\t\tthis._buffer = null;\n\t}\n}\n"
  },
  {
    "path": "packages/core/test/mock-writable.ts",
    "content": "import { Writable } from 'node:stream';\n\nexport class MockWritable extends Writable {\n\tpublic buffer: string[] = [];\n\n\t_write(\n\t\tchunk: any,\n\t\t_encoding: BufferEncoding,\n\t\tcallback: (error?: Error | null | undefined) => void\n\t): void {\n\t\tthis.buffer.push(chunk.toString());\n\t\tcallback();\n\t}\n}\n"
  },
  {
    "path": "packages/core/test/prompts/autocomplete.test.ts",
    "content": "import { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as AutocompletePrompt } from '../../src/prompts/autocomplete.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\ndescribe('AutocompletePrompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\tconst testOptions = [\n\t\t{ value: 'apple', label: 'Apple' },\n\t\t{ value: 'banana', label: 'Banana' },\n\t\t{ value: 'cherry', label: 'Cherry' },\n\t\t{ value: 'grape', label: 'Grape' },\n\t\t{ value: 'orange', label: 'Orange' },\n\t];\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\ttest('initial options match provided options', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t});\n\n\t\tinstance.prompt();\n\n\t\t// Initial state should have all options\n\t\texpect(instance.filteredOptions.length).to.equal(testOptions.length);\n\t\texpect(instance.cursor).to.equal(0);\n\t});\n\n\ttest('cursor navigation with event emitter', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t});\n\n\t\tinstance.prompt();\n\n\t\t// Initial cursor should be at 0\n\t\texpect(instance.cursor).to.equal(0);\n\n\t\t// Directly trigger the cursor event with 'down'\n\t\tinstance.emit('key', '', { name: 'down' });\n\n\t\t// After down event, cursor should be 1\n\t\texpect(instance.cursor).to.equal(1);\n\n\t\t// Trigger cursor event with 'up'\n\t\tinstance.emit('key', '', { name: 'up' });\n\n\t\t// After up event, cursor should be back to 0\n\t\texpect(instance.cursor).to.equal(0);\n\t});\n\n\ttest('initialValue selects correct option', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t\tinitialValue: ['cherry'],\n\t\t});\n\n\t\t// The cursor should be initialized to the cherry index\n\t\tconst cherryIndex = testOptions.findIndex((opt) => opt.value === 'cherry');\n\t\texpect(instance.cursor).to.equal(cherryIndex);\n\n\t\t// The selectedValue should be cherry\n\t\texpect(instance.selectedValues).to.deep.equal(['cherry']);\n\t});\n\n\ttest('initialValue defaults to first option when non-multiple', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t});\n\n\t\texpect(instance.cursor).to.equal(0);\n\t\texpect(instance.selectedValues).to.deep.equal(['apple']);\n\t});\n\n\ttest('initialValue is empty when multiple', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t\tmultiple: true,\n\t\t});\n\n\t\texpect(instance.cursor).to.equal(0);\n\t\texpect(instance.selectedValues).to.deep.equal([]);\n\t});\n\n\ttest('filtering through user input', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t});\n\n\t\tinstance.prompt();\n\n\t\t// Initial state should have all options\n\t\texpect(instance.filteredOptions.length).to.equal(testOptions.length);\n\n\t\t// Simulate typing 'a' by emitting keypress event\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\n\t\t// Check that filtered options are updated to include options with 'a'\n\t\texpect(instance.filteredOptions.length).to.be.lessThan(testOptions.length);\n\n\t\t// Check that 'apple' is in the filtered options\n\t\tconst hasApple = instance.filteredOptions.some((opt) => opt.value === 'apple');\n\t\texpect(hasApple).to.equal(true);\n\t});\n\n\ttest('default filter function works correctly', () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t});\n\n\t\tinstance.prompt();\n\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\tinput.emit('keypress', 'p', { name: 'p' });\n\n\t\texpect(instance.filteredOptions).toEqual([\n\t\t\t{ value: 'apple', label: 'Apple' },\n\t\t\t{ value: 'grape', label: 'Grape' },\n\t\t]);\n\n\t\tinput.emit('keypress', 'z', { name: 'z' });\n\n\t\texpect(instance.filteredOptions).toEqual([]);\n\t});\n\n\ttest('submit without nav resolves to first option in non-multiple', async () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t});\n\n\t\tconst promise = instance.prompt();\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst result = await promise;\n\n\t\texpect(instance.selectedValues).to.deep.equal(['apple']);\n\t\texpect(result).to.equal('apple');\n\t});\n\n\ttest('submit without nav resolves to [] in multiple', async () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t\tmultiple: true,\n\t\t});\n\n\t\tconst promise = instance.prompt();\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst result = await promise;\n\n\t\texpect(instance.selectedValues).to.deep.equal([]);\n\t\texpect(result).to.deep.equal([]);\n\t});\n\n\ttest('Tab with empty input and placeholder fills input and submit returns matching option', async () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t\tplaceholder: 'apple',\n\t\t});\n\n\t\tconst promise = instance.prompt();\n\t\tinput.emit('keypress', '\\t', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst result = await promise;\n\n\t\texpect(instance.userInput).to.equal('apple');\n\t\texpect(result).to.equal('apple');\n\t});\n\n\ttest('Tab with non-matching placeholder does not fill input', async () => {\n\t\tconst instance = new AutocompletePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: testOptions,\n\t\t\tplaceholder: 'Type to search...',\n\t\t});\n\n\t\tinstance.prompt();\n\t\tinput.emit('keypress', '\\t', { name: 'tab' });\n\n\t\t// Placeholder does not match any option, so input must not be filled with placeholder\n\t\texpect(instance.userInput).not.to.equal('Type to search...');\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/prompts/confirm.test.ts",
    "content": "import { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as ConfirmPrompt } from '../../src/prompts/confirm.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\ndescribe('ConfirmPrompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new ConfirmPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tactive: 'yes',\n\t\t\tinactive: 'no',\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\ttest('sets value and submits on confirm (y)', () => {\n\t\tconst instance = new ConfirmPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tactive: 'yes',\n\t\t\tinactive: 'no',\n\t\t\tinitialValue: true,\n\t\t});\n\n\t\tinstance.prompt();\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\n\t\texpect(instance.value).to.equal(true);\n\t\texpect(instance.state).to.equal('submit');\n\t});\n\n\ttest('sets value and submits on confirm (n)', () => {\n\t\tconst instance = new ConfirmPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tactive: 'yes',\n\t\t\tinactive: 'no',\n\t\t\tinitialValue: true,\n\t\t});\n\n\t\tinstance.prompt();\n\t\tinput.emit('keypress', 'n', { name: 'n' });\n\n\t\texpect(instance.value).to.equal(false);\n\t\texpect(instance.state).to.equal('submit');\n\t});\n\n\tdescribe('cursor', () => {\n\t\ttest('cursor is 1 when inactive', () => {\n\t\t\tconst instance = new ConfirmPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tactive: 'yes',\n\t\t\t\tinactive: 'no',\n\t\t\t\tinitialValue: false,\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t\texpect(instance.cursor).to.equal(1);\n\t\t});\n\n\t\ttest('cursor is 0 when active', () => {\n\t\t\tconst instance = new ConfirmPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tactive: 'yes',\n\t\t\t\tinactive: 'no',\n\t\t\t\tinitialValue: true,\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/prompts/date.test.ts",
    "content": "import { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as DatePrompt } from '../../src/prompts/date.js';\nimport { isCancel } from '../../src/utils/index.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\nconst d = (iso: string) => {\n\tconst [y, m, day] = iso.slice(0, 10).split('-').map(Number);\n\treturn new Date(Date.UTC(y, m - 1, day));\n};\n\ndescribe('DatePrompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\ttest('initial value displays correctly', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.userInput).to.equal('2025/01/15');\n\t\texpect(instance.value).toBeInstanceOf(Date);\n\t\texpect(instance.value!.toISOString().slice(0, 10)).to.equal('2025-01-15');\n\t});\n\n\ttest('left/right navigates between segments', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 0, positionInSegment: 0 });\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 1, positionInSegment: 0 });\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 2, positionInSegment: 0 });\n\t\tinput.emit('keypress', undefined, { name: 'left' });\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 1, positionInSegment: 0 });\n\t});\n\n\ttest('up/down increments and decrements segment', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t});\n\t\tinstance.prompt();\n\t\tinput.emit('keypress', undefined, { name: 'right' }); // move to month\n\t\tinput.emit('keypress', undefined, { name: 'up' });\n\t\texpect(instance.userInput).to.equal('2025/02/15');\n\t\tinput.emit('keypress', undefined, { name: 'down' });\n\t\texpect(instance.userInput).to.equal('2025/01/15');\n\t});\n\n\ttest('up/down on one segment leaves other segments blank', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.userInput).to.equal('____/__/__');\n\t\tinput.emit('keypress', undefined, { name: 'up' }); // up on year (first segment)\n\t\texpect(instance.userInput).to.equal('0001/__/__');\n\t\tinput.emit('keypress', undefined, { name: 'right' }); // move to month\n\t\tinput.emit('keypress', undefined, { name: 'up' });\n\t\texpect(instance.userInput).to.equal('0001/01/__');\n\t});\n\n\ttest('with minDate/maxDate, up on blank segment starts at min', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tminDate: d('2025-03-10'),\n\t\t\tmaxDate: d('2025-11-20'),\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.userInput).to.equal('____/__/__');\n\t\tinput.emit('keypress', undefined, { name: 'up' });\n\t\texpect(instance.userInput).to.equal('2025/__/__');\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\tinput.emit('keypress', undefined, { name: 'up' });\n\t\texpect(instance.userInput).to.equal('2025/03/__');\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\tinput.emit('keypress', undefined, { name: 'up' });\n\t\texpect(instance.userInput).to.equal('2025/03/10');\n\t});\n\n\ttest('with minDate/maxDate, down on blank segment starts at max', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tminDate: d('2025-03-10'),\n\t\t\tmaxDate: d('2025-11-20'),\n\t\t});\n\t\tinstance.prompt();\n\t\tinput.emit('keypress', undefined, { name: 'down' });\n\t\texpect(instance.userInput).to.equal('2025/__/__');\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\tinput.emit('keypress', undefined, { name: 'down' });\n\t\texpect(instance.userInput).to.equal('2025/11/__');\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\tinput.emit('keypress', undefined, { name: 'down' });\n\t\texpect(instance.userInput).to.equal('2025/11/20');\n\t});\n\n\ttest('digit-by-digit editing from left to right', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 0, positionInSegment: 0 });\n\t\t// Type 2,0,2,3 to change year to 2023 (right-to-left fill)\n\t\tinput.emit('keypress', '2', { name: undefined, sequence: '2' });\n\t\texpect(instance.userInput).to.equal('___2/01/15');\n\t\tinput.emit('keypress', '0', { name: undefined, sequence: '0' });\n\t\texpect(instance.userInput).to.equal('__20/01/15');\n\t\tinput.emit('keypress', '2', { name: undefined, sequence: '2' });\n\t\texpect(instance.userInput).to.equal('_202/01/15');\n\t\tinput.emit('keypress', '3', { name: undefined, sequence: '3' });\n\t\texpect(instance.userInput).to.equal('2023/01/15');\n\t});\n\n\ttest('backspace clears entire segment at any cursor position', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tinitialValue: d('2025-12-21'),\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.userInput).to.equal('2025/12/21');\n\t\tinput.emit('keypress', undefined, { name: 'backspace', sequence: '\\x7f' });\n\t\texpect(instance.userInput).to.equal('____/12/21');\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 0, positionInSegment: 0 });\n\t});\n\n\ttest('backspace clears segment when cursor at first char (2___)', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t});\n\t\tinstance.prompt();\n\t\tinput.emit('keypress', '2', { name: undefined, sequence: '2' });\n\t\texpect(instance.userInput).to.equal('___2/__/__');\n\t\tinput.emit('keypress', '\\x7f', { name: undefined, sequence: '\\x7f' });\n\t\texpect(instance.userInput).to.equal('____/__/__');\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 0, positionInSegment: 0 });\n\t});\n\n\ttest('digit input updates segment and jumps to next when complete', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t});\n\t\tinstance.prompt();\n\t\tfor (const c of '2025') {\n\t\t\tinput.emit('keypress', c, { name: undefined, sequence: c });\n\t\t}\n\t\texpect(instance.userInput).to.equal('2025/__/__');\n\t\texpect(instance.segmentCursor).to.deep.equal({ segmentIndex: 1, positionInSegment: 0 });\n\t});\n\n\ttest('submit returns Date for valid date', async () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tinitialValue: d('2025-01-31'),\n\t\t});\n\t\tconst resultPromise = instance.prompt();\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\t\tconst result = await resultPromise;\n\t\texpect(result).toBeInstanceOf(Date);\n\t\texpect((result as Date).toISOString().slice(0, 10)).to.equal('2025-01-31');\n\t});\n\n\ttest('can cancel', async () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t});\n\t\tconst resultPromise = instance.prompt();\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\t\tconst result = await resultPromise;\n\t\texpect(isCancel(result)).toBe(true);\n\t});\n\n\ttest('defaultValue used when invalid date submitted', async () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t\tdefaultValue: d('2025-06-15'),\n\t\t});\n\t\tconst resultPromise = instance.prompt();\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\t\tconst result = await resultPromise;\n\t\texpect(result).toBeInstanceOf(Date);\n\t\texpect((result as Date).toISOString().slice(0, 10)).to.equal('2025-06-15');\n\t});\n\n\ttest('supports MDY format', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'MDY',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.userInput).to.equal('01/15/2025');\n\t});\n\n\ttest('supports DMY format', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'DMY',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(instance.userInput).to.equal('15/01/2025');\n\t});\n\n\ttest('rejects invalid month via pending tens digit', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t});\n\t\tinstance.prompt();\n\t\t// Navigate to month\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\t// Type '1' → '01' with pending tens digit (since 1 <= 1)\n\t\tinput.emit('keypress', '1', { name: undefined, sequence: '1' });\n\t\texpect(instance.segmentValues.month).to.equal('01');\n\t\t// Type '3' → tries '13' which is > 12 → inline error\n\t\tinput.emit('keypress', '3', { name: undefined, sequence: '3' });\n\t\texpect(instance.inlineError).to.equal('There are only 12 months in a year');\n\t});\n\n\ttest('rejects invalid day via pending tens digit', () => {\n\t\tconst instance = new DatePrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tformat: 'YMD',\n\t\t});\n\t\tinstance.prompt();\n\t\t// Navigate to day\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\t// Type '2' → '02' with pending (2 <= 2)\n\t\tinput.emit('keypress', '2', { name: undefined, sequence: '2' });\n\t\tinput.emit('keypress', '0', { name: undefined, sequence: '0' });\n\t\texpect(instance.inlineError).to.equal('');\n\t});\n\n\tdescribe('segmentValues and segmentCursor', () => {\n\t\ttest('segmentValues reflects current input', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tformat: 'YMD',\n\t\t\t\tinitialValue: d('2025-01-15'),\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tconst segmentValues = instance.segmentValues;\n\t\t\texpect(segmentValues.year).to.equal('2025');\n\t\t\texpect(segmentValues.month).to.equal('01');\n\t\t\texpect(segmentValues.day).to.equal('15');\n\t\t});\n\n\t\ttest('segmentCursor tracks cursor position', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tformat: 'YMD',\n\t\t\t\tinitialValue: d('2025-01-15'),\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', undefined, { name: 'right' }); // move to month\n\t\t\tconst cursor = instance.segmentCursor;\n\t\t\texpect(cursor.segmentIndex).to.equal(1);\n\t\t\texpect(cursor.positionInSegment).to.equal(0);\n\t\t});\n\n\t\ttest('segmentValues updates on submit', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tformat: 'YMD',\n\t\t\t\tinitialValue: d('2025-01-15'),\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', undefined, { name: 'return' });\n\t\t\tconst segmentValues = instance.segmentValues;\n\t\t\texpect(segmentValues.year).to.equal('2025');\n\t\t\texpect(segmentValues.month).to.equal('01');\n\t\t\texpect(segmentValues.day).to.equal('15');\n\t\t});\n\t});\n\n\tdescribe('formattedValue and segments', () => {\n\t\ttest('formattedValue returns formatted string', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tformat: 'MDY',\n\t\t\t\tinitialValue: d('2025-03-15'),\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.formattedValue).to.equal('03/15/2025');\n\t\t});\n\n\t\ttest('segments exposes segment config', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tformat: 'DMY',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.segments).to.deep.equal([\n\t\t\t\t{ type: 'day', len: 2 },\n\t\t\t\t{ type: 'month', len: 2 },\n\t\t\t\t{ type: 'year', len: 4 },\n\t\t\t]);\n\t\t});\n\n\t\ttest('separator defaults to / for explicit format', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tformat: 'YMD',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.separator).to.equal('/');\n\t\t});\n\t});\n\n\tdescribe('locale detection', () => {\n\t\ttest('locale auto-detects format from Intl', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tlocale: 'en-US',\n\t\t\t\tinitialValue: d('2025-03-15'),\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\t// en-US is MDY\n\t\t\texpect(instance.segments[0].type).to.equal('month');\n\t\t\texpect(instance.segments[1].type).to.equal('day');\n\t\t\texpect(instance.segments[2].type).to.equal('year');\n\t\t});\n\n\t\ttest('explicit format overrides locale', () => {\n\t\t\tconst instance = new DatePrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tformat: 'YMD',\n\t\t\t\tlocale: 'en-US', // would be MDY, but format takes precedence\n\t\t\t\tinitialValue: d('2025-03-15'),\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.segments[0].type).to.equal('year');\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/prompts/multi-select.test.ts",
    "content": "import { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as MultiSelectPrompt } from '../../src/prompts/multi-select.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\ndescribe('MultiSelectPrompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new MultiSelectPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\tdescribe('cursor', () => {\n\t\ttest('cursor is index of selected item', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\texpect(instance.cursor).to.equal(1);\n\t\t});\n\n\t\ttest('cursor loops around', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }, { value: 'baz' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t\tinput.emit('keypress', 'up', { name: 'up' });\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t});\n\n\t\ttest('left behaves as up', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }, { value: 'baz' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'left', { name: 'left' });\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t});\n\n\t\ttest('right behaves as down', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'left', { name: 'left' });\n\t\t\texpect(instance.cursor).to.equal(1);\n\t\t});\n\n\t\ttest('initial values is selected', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t\tinitialValues: ['bar'],\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.value).toEqual(['bar']);\n\t\t});\n\n\t\ttest('select all when press \"a\" key', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t});\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\tinput.emit('keypress', 'space', { name: 'space' });\n\t\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\t\texpect(instance.value).toEqual(['foo', 'bar']);\n\t\t});\n\n\t\ttest('select invert when press \"i\" key', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t});\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\tinput.emit('keypress', 'space', { name: 'space' });\n\t\t\tinput.emit('keypress', 'i', { name: 'i' });\n\t\t\texpect(instance.value).toEqual(['foo']);\n\t\t});\n\n\t\ttest('disabled options are skipped', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar', disabled: true }, { value: 'baz' }],\n\t\t\t});\n\t\t\tinstance.prompt();\n\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t\tinput.emit('keypress', 'up', { name: 'up' });\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t});\n\n\t\ttest('initial cursorAt on disabled option', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar', disabled: true }, { value: 'baz' }],\n\t\t\t\tcursorAt: 'bar',\n\t\t\t});\n\t\t\tinstance.prompt();\n\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t});\n\t});\n\n\tdescribe('toggleAll', () => {\n\t\ttest('selects all enabled options', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar', disabled: true }, { value: 'baz' }],\n\t\t\t});\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\t\texpect(instance.value).toEqual(['foo', 'baz']);\n\t\t});\n\n\t\ttest('unselects all enabled options if all selected', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar', disabled: true }, { value: 'baz' }],\n\t\t\t\tinitialValues: ['foo', 'baz'],\n\t\t\t});\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\t\texpect(instance.value).toEqual([]);\n\t\t});\n\t});\n\n\tdescribe('toggleInvert', () => {\n\t\ttest('inverts selection of enabled options', () => {\n\t\t\tconst instance = new MultiSelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [\n\t\t\t\t\t{ value: 'foo' },\n\t\t\t\t\t{ value: 'bar', disabled: true },\n\t\t\t\t\t{ value: 'baz' },\n\t\t\t\t\t{ value: 'qux' },\n\t\t\t\t],\n\t\t\t\tinitialValues: ['foo', 'baz'],\n\t\t\t});\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'i', { name: 'i' });\n\t\t\texpect(instance.value).toEqual(['qux']);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/prompts/password.test.ts",
    "content": "import { styleText } from 'node:util';\nimport { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as PasswordPrompt } from '../../src/prompts/password.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\ndescribe('PasswordPrompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new PasswordPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\t\t// leave the promise hanging since we don't want to submit in this test\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\tdescribe('cursor', () => {\n\t\ttest('can get cursor', () => {\n\t\t\tconst instance = new PasswordPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t});\n\t});\n\n\tdescribe('userInputWithCursor', () => {\n\t\ttest('returns masked value on submit', () => {\n\t\t\tconst instance = new PasswordPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tconst keys = 'foo';\n\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\tinput.emit('keypress', keys[i], { name: keys[i] });\n\t\t\t}\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t\texpect(instance.userInputWithCursor).to.equal('•••');\n\t\t});\n\n\t\ttest('renders marker at end', () => {\n\t\t\tconst instance = new PasswordPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\t\texpect(instance.userInputWithCursor).to.equal(`•${styleText(['inverse', 'hidden'], '_')}`);\n\t\t});\n\n\t\ttest('renders cursor inside value', () => {\n\t\t\tconst instance = new PasswordPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\t\tinput.emit('keypress', 'z', { name: 'z' });\n\t\t\tinput.emit('keypress', undefined, { name: 'left' });\n\t\t\tinput.emit('keypress', undefined, { name: 'left' });\n\t\t\texpect(instance.userInputWithCursor).to.equal(`•${styleText('inverse', '•')}•`);\n\t\t});\n\n\t\ttest('renders custom mask', () => {\n\t\t\tconst instance = new PasswordPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tmask: 'X',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\t\texpect(instance.userInputWithCursor).to.equal(`X${styleText(['inverse', 'hidden'], '_')}`);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/prompts/prompt.test.ts",
    "content": "import { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as Prompt } from '../../src/prompts/prompt.js';\nimport { isCancel } from '../../src/utils/index.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\ndescribe('Prompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\t\t// leave the promise hanging since we don't want to submit in this test\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\ttest('submits on return key', async () => {\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\t\tconst resultPromise = instance.prompt();\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst result = await resultPromise;\n\t\texpect(result).to.equal(undefined);\n\t\texpect(isCancel(result)).to.equal(false);\n\t\texpect(instance.state).to.equal('submit');\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo', '\\n', cursor.show]);\n\t});\n\n\ttest('cancels on ctrl-c', async () => {\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\t\tconst resultPromise = instance.prompt();\n\t\tinput.emit('keypress', '\\x03', { name: 'c' });\n\t\tconst result = await resultPromise;\n\t\texpect(isCancel(result)).to.equal(true);\n\t\texpect(instance.state).to.equal('cancel');\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo', '\\n', cursor.show]);\n\t});\n\n\ttest('does not write initialValue to value', () => {\n\t\tconst eventSpy = vi.fn();\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tinitialValue: 'bananas',\n\t\t});\n\t\tinstance.on('value', eventSpy);\n\t\tinstance.prompt();\n\t\texpect(instance.value).to.equal(undefined);\n\t\texpect(eventSpy).not.toHaveBeenCalled();\n\t});\n\n\ttest('re-renders on resize', () => {\n\t\tconst renderFn = vi.fn().mockImplementation(() => 'foo');\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: renderFn,\n\t\t});\n\t\tinstance.prompt();\n\n\t\texpect(renderFn).toHaveBeenCalledTimes(1);\n\n\t\toutput.emit('resize');\n\n\t\texpect(renderFn).toHaveBeenCalledTimes(2);\n\t});\n\n\ttest('state is active after first render', async () => {\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\n\t\texpect(instance.state).to.equal('initial');\n\n\t\tinstance.prompt();\n\n\t\texpect(instance.state).to.equal('active');\n\t});\n\n\ttest('emits truthy confirm on y press', () => {\n\t\tconst eventFn = vi.fn();\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\n\t\tinstance.on('confirm', eventFn);\n\n\t\tinstance.prompt();\n\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\n\t\texpect(eventFn).toBeCalledWith(true);\n\t});\n\n\ttest('emits falsey confirm on n press', () => {\n\t\tconst eventFn = vi.fn();\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\n\t\tinstance.on('confirm', eventFn);\n\n\t\tinstance.prompt();\n\n\t\tinput.emit('keypress', 'n', { name: 'n' });\n\n\t\texpect(eventFn).toBeCalledWith(false);\n\t});\n\n\ttest('emits key event for unknown chars', () => {\n\t\tconst eventSpy = vi.fn();\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\n\t\tinstance.on('key', eventSpy);\n\n\t\tinstance.prompt();\n\n\t\tinput.emit('keypress', 'z', { name: 'z' });\n\n\t\texpect(eventSpy).toBeCalledWith('z', { name: 'z' });\n\t});\n\n\ttest('emits cursor events for movement keys', () => {\n\t\tconst keys = ['up', 'down', 'left', 'right'];\n\t\tconst eventSpy = vi.fn();\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\n\t\tinstance.on('cursor', eventSpy);\n\n\t\tinstance.prompt();\n\n\t\tfor (const key of keys) {\n\t\t\tinput.emit('keypress', key, { name: key });\n\t\t\texpect(eventSpy).toBeCalledWith(key);\n\t\t}\n\t});\n\n\ttest('emits cursor events for movement key aliases when not tracking', () => {\n\t\tconst keys = [\n\t\t\t['k', 'up'],\n\t\t\t['j', 'down'],\n\t\t\t['h', 'left'],\n\t\t\t['l', 'right'],\n\t\t];\n\t\tconst eventSpy = vi.fn();\n\t\tconst instance = new Prompt(\n\t\t\t{\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t},\n\t\t\tfalse\n\t\t);\n\n\t\tinstance.on('cursor', eventSpy);\n\n\t\tinstance.prompt();\n\n\t\tfor (const [alias, key] of keys) {\n\t\t\tinput.emit('keypress', alias, { name: alias });\n\t\t\texpect(eventSpy).toBeCalledWith(key);\n\t\t}\n\t});\n\n\ttest('aborts on abort signal', () => {\n\t\tconst abortController = new AbortController();\n\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tsignal: abortController.signal,\n\t\t});\n\n\t\tinstance.prompt();\n\n\t\texpect(instance.state).to.equal('active');\n\n\t\tabortController.abort();\n\n\t\texpect(instance.state).to.equal('cancel');\n\t});\n\n\ttest('returns immediately if signal is already aborted', () => {\n\t\tconst abortController = new AbortController();\n\t\tabortController.abort();\n\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tsignal: abortController.signal,\n\t\t});\n\t\tinstance.prompt();\n\n\t\texpect(instance.state).to.equal('cancel');\n\t});\n\n\ttest('accepts invalid initial value', () => {\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tinitialValue: 'invalid',\n\t\t\tvalidate: (value) => (value === 'valid' ? undefined : 'must be valid'),\n\t\t});\n\t\tinstance.prompt();\n\n\t\texpect(instance.state).to.equal('active');\n\t\texpect(instance.error).to.equal('');\n\t});\n\n\ttest('validates value on return', () => {\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tvalidate: (value) => (value === 'valid' ? undefined : 'must be valid'),\n\t\t});\n\t\tinstance.prompt();\n\n\t\tinstance.value = 'invalid';\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\texpect(instance.state).to.equal('error');\n\t\texpect(instance.error).to.equal('must be valid');\n\t});\n\n\ttest('validates value with Error object', () => {\n\t\tconst instance = new Prompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tvalidate: (value) => (value === 'valid' ? undefined : new Error('must be valid')),\n\t\t});\n\t\tinstance.prompt();\n\n\t\tinstance.value = 'invalid';\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\texpect(instance.state).to.equal('error');\n\t\texpect(instance.error).to.equal('must be valid');\n\t});\n\n\ttest('validates value with regex validation', () => {\n\t\tconst instance = new Prompt<string>({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tvalidate: (value) => (/^[A-Z]+$/.test(value ?? '') ? undefined : 'Invalid value'),\n\t\t});\n\t\tinstance.prompt();\n\n\t\tinstance.value = 'Invalid Value $$$';\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\texpect(instance.state).to.equal('error');\n\t\texpect(instance.error).to.equal('Invalid value');\n\t});\n\n\ttest('accepts valid value with regex validation', () => {\n\t\tconst instance = new Prompt<string>({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tvalidate: (value) => (/^[A-Z]+$/.test(value ?? '') ? undefined : 'Invalid value'),\n\t\t});\n\t\tinstance.prompt();\n\n\t\tinstance.value = 'VALID';\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\texpect(instance.state).to.equal('submit');\n\t\texpect(instance.error).to.equal('');\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/prompts/select.test.ts",
    "content": "import { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as SelectPrompt } from '../../src/prompts/select.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\ndescribe('SelectPrompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new SelectPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t});\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\tdescribe('cursor', () => {\n\t\ttest('cursor is index of selected item', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\texpect(instance.cursor).to.equal(1);\n\t\t});\n\n\t\ttest('cursor loops around', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }, { value: 'baz' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t\tinput.emit('keypress', 'up', { name: 'up' });\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t});\n\n\t\ttest('left behaves as up', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }, { value: 'baz' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'left', { name: 'left' });\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t});\n\n\t\ttest('right behaves as down', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t});\n\n\t\t\tinstance.prompt();\n\n\t\t\tinput.emit('keypress', 'left', { name: 'left' });\n\t\t\texpect(instance.cursor).to.equal(1);\n\t\t});\n\n\t\ttest('initial value is selected', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar' }],\n\t\t\t\tinitialValue: 'bar',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.cursor).to.equal(1);\n\t\t});\n\n\t\ttest('cursor skips disabled options (down)', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar', disabled: true }, { value: 'baz' }],\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t\tinput.emit('keypress', 'down', { name: 'down' });\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t});\n\n\t\ttest('cursor skips disabled options (up)', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tinitialValue: 'baz',\n\t\t\t\toptions: [{ value: 'foo' }, { value: 'bar', disabled: true }, { value: 'baz' }],\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.cursor).to.equal(2);\n\t\t\tinput.emit('keypress', 'up', { name: 'up' });\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t});\n\n\t\ttest('cursor skips initial disabled option', () => {\n\t\t\tconst instance = new SelectPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\toptions: [{ value: 'foo', disabled: true }, { value: 'bar' }, { value: 'baz' }],\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\texpect(instance.cursor).to.equal(1);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/prompts/text.test.ts",
    "content": "import { styleText } from 'node:util';\nimport { cursor } from 'sisteransi';\nimport { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { default as TextPrompt } from '../../src/prompts/text.js';\nimport { MockReadable } from '../mock-readable.js';\nimport { MockWritable } from '../mock-writable.js';\n\ndescribe('TextPrompt', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders render() result', () => {\n\t\tconst instance = new TextPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t});\n\t\t// leave the promise hanging since we don't want to submit in this test\n\t\tinstance.prompt();\n\t\texpect(output.buffer).to.deep.equal([cursor.hide, 'foo']);\n\t});\n\n\ttest('sets default value on finalize if no value', async () => {\n\t\tconst instance = new TextPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tdefaultValue: 'bleep bloop',\n\t\t});\n\t\tconst resultPromise = instance.prompt();\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst result = await resultPromise;\n\t\texpect(result).to.equal('bleep bloop');\n\t});\n\n\ttest('keeps value on finalize', async () => {\n\t\tconst instance = new TextPrompt({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trender: () => 'foo',\n\t\t\tdefaultValue: 'bleep bloop',\n\t\t});\n\t\tconst resultPromise = instance.prompt();\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst result = await resultPromise;\n\t\texpect(result).to.equal('x');\n\t});\n\n\tdescribe('cursor', () => {\n\t\ttest('can get cursor', () => {\n\t\t\tconst instance = new TextPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\n\t\t\texpect(instance.cursor).to.equal(0);\n\t\t});\n\t});\n\n\tdescribe('userInputWithCursor', () => {\n\t\ttest('returns value on submit', () => {\n\t\t\tconst instance = new TextPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t\texpect(instance.userInputWithCursor).to.equal('x');\n\t\t});\n\n\t\ttest('highlights cursor position', () => {\n\t\t\tconst instance = new TextPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tconst keys = 'foo';\n\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\tinput.emit('keypress', keys[i], { name: keys[i] });\n\t\t\t}\n\t\t\tinput.emit('keypress', undefined, { name: 'left' });\n\t\t\texpect(instance.userInputWithCursor).to.equal(`fo${styleText('inverse', 'o')}`);\n\t\t});\n\n\t\ttest('shows cursor at end if beyond value', () => {\n\t\t\tconst instance = new TextPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t});\n\t\t\tinstance.prompt();\n\t\t\tconst keys = 'foo';\n\t\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\t\tinput.emit('keypress', keys[i], { name: keys[i] });\n\t\t\t}\n\t\t\tinput.emit('keypress', undefined, { name: 'right' });\n\t\t\texpect(instance.userInputWithCursor).to.equal('foo█');\n\t\t});\n\n\t\ttest('does not use placeholder as value when pressing enter', async () => {\n\t\t\tconst instance = new TextPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tplaceholder: '  (hit Enter to use default)',\n\t\t\t\tdefaultValue: 'default-value',\n\t\t\t});\n\t\t\tconst resultPromise = instance.prompt();\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t\tconst result = await resultPromise;\n\t\t\texpect(result).to.equal('default-value');\n\t\t});\n\n\t\ttest('returns empty string when no value and no default', async () => {\n\t\t\tconst instance = new TextPrompt({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\trender: () => 'foo',\n\t\t\t\tplaceholder: '  (hit Enter to use default)',\n\t\t\t});\n\t\t\tconst resultPromise = instance.prompt();\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t\tconst result = await resultPromise;\n\t\t\texpect(result).to.equal('');\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/core/test/utils.test.ts",
    "content": "import type { Key } from 'node:readline';\nimport { cursor } from 'sisteransi';\nimport { afterEach, describe, expect, test, vi } from 'vitest';\nimport { block } from '../src/utils/index.js';\nimport { MockReadable } from './mock-readable.js';\nimport { MockWritable } from './mock-writable.js';\n\ndescribe('utils', () => {\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\tdescribe('block', () => {\n\t\ttest('clears output on keypress', () => {\n\t\t\tconst input = new MockReadable();\n\t\t\tconst output = new MockWritable();\n\t\t\tconst callback = block({ input, output });\n\n\t\t\tconst event: Key = {\n\t\t\t\tname: 'x',\n\t\t\t};\n\t\t\tconst eventData = Buffer.from('bloop');\n\t\t\tinput.emit('keypress', eventData, event);\n\t\t\tcallback();\n\t\t\texpect(output.buffer).to.deep.equal([cursor.hide, cursor.move(-1, 0), cursor.show]);\n\t\t});\n\n\t\ttest('clears output vertically when return pressed', () => {\n\t\t\tconst input = new MockReadable();\n\t\t\tconst output = new MockWritable();\n\t\t\tconst callback = block({ input, output });\n\n\t\t\tconst event: Key = {\n\t\t\t\tname: 'return',\n\t\t\t};\n\t\t\tconst eventData = Buffer.from('bloop');\n\t\t\tinput.emit('keypress', eventData, event);\n\t\t\tcallback();\n\t\t\texpect(output.buffer).to.deep.equal([cursor.hide, cursor.move(0, -1), cursor.show]);\n\t\t});\n\n\t\ttest('ignores additional keypresses after dispose', () => {\n\t\t\tconst input = new MockReadable();\n\t\t\tconst output = new MockWritable();\n\t\t\tconst callback = block({ input, output });\n\n\t\t\tconst event: Key = {\n\t\t\t\tname: 'x',\n\t\t\t};\n\t\t\tconst eventData = Buffer.from('bloop');\n\t\t\tinput.emit('keypress', eventData, event);\n\t\t\tcallback();\n\t\t\tinput.emit('keypress', eventData, event);\n\t\t\texpect(output.buffer).to.deep.equal([cursor.hide, cursor.move(-1, 0), cursor.show]);\n\t\t});\n\n\t\ttest('exits on ctrl-c', () => {\n\t\t\tconst input = new MockReadable();\n\t\t\tconst output = new MockWritable();\n\t\t\t// purposely don't keep the callback since we would exit the process\n\t\t\tblock({ input, output });\n\t\t\tconst spy = vi.spyOn(process, 'exit').mockImplementation((() => {\n\t\t\t\treturn;\n\t\t\t}) as () => never);\n\n\t\t\tconst event: Key = {\n\t\t\t\tname: 'c',\n\t\t\t};\n\t\t\tconst eventData = Buffer.from('\\x03');\n\t\t\tinput.emit('keypress', eventData, event);\n\t\t\texpect(spy).toHaveBeenCalled();\n\t\t\texpect(output.buffer).to.deep.equal([cursor.hide, cursor.show]);\n\t\t});\n\n\t\ttest('does not clear if overwrite=false', () => {\n\t\t\tconst input = new MockReadable();\n\t\t\tconst output = new MockWritable();\n\t\t\tconst callback = block({ input, output, overwrite: false });\n\n\t\t\tconst event: Key = {\n\t\t\t\tname: 'c',\n\t\t\t};\n\t\t\tconst eventData = Buffer.from('bloop');\n\t\t\tinput.emit('keypress', eventData, event);\n\t\t\tcallback();\n\t\t\texpect(output.buffer).to.deep.equal([cursor.hide, cursor.show]);\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/core/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/prompts/CHANGELOG.md",
    "content": "# @clack/prompts\n\n## 1.1.0\n\n### Minor Changes\n\n- e3333fb: Replaces `picocolors` with Node.js built-in `styleText`.\n\n### Patch Changes\n\n- c3666e2: destruct `limitOption` param for better code readability, tweak types definitions\n- ba3df8e: Fixes withGuide support in intro, outro, and cancel messages.\n- Updated dependencies [e3333fb]\n  - @clack/core@1.1.0\n\n## 1.0.1\n\n### Patch Changes\n\n- 6404dc1: Disallows selection of `disabled` options in autocomplete.\n- 86e36d8: Adds `withGuide` support to select prompt.\n- c697439: Fixes line wrapping behavior in autocomplete.\n- 0ded19c: Simplifies `withGuide` option checks.\n- 0e4ddc9: Fixes `withGuide` support in password and path prompts.\n- 76550d6: Adds `withGuide` support to selectKey prompt.\n- f9b9953: Adds `withGuide` support to password prompt.\n- 0e93ccb: Adds `vertical` arrangement option to `confirm` prompt.\n- 4e9ae13: Adds `withGuide` support to confirm prompt.\n- 0256238: Adds `withGuide` support to spinner prompt.\n- Updated dependencies [6404dc1]\n- Updated dependencies [2533180]\n  - @clack/core@1.0.1\n\n## 1.0.0\n\n### Major Changes\n\n- c713fd5: The package is now distributed as ESM-only. In `v0` releases, the package was dual-published as CJS and ESM.\n\n  For existing CJS projects using Node v20+, please see Node's guide on [Loading ECMAScript modules using `require()`](https://nodejs.org/docs/latest-v20.x/api/modules.html#loading-ecmascript-modules-using-require).\n\n### Minor Changes\n\n- 415410b: This adds a custom filter function to autocompleteMultiselect. It could be used, for example, to support fuzzy searching logic.\n- 7bc3301: Prompts now have a `userInput` stored separately from their `value`.\n- 8409f2c: feat: add styleFrame option for spinner\n- 2837845: Adds suggestion and path prompts\n- 99c3530: Adds `format` option to the note prompt to allow formatting of individual lines\n- 0aaee4c: Added new `taskLog` prompt for log output which is cleared on success\n- 729bbb6: Add support for customizable spinner cancel and error messages. Users can now customize these messages either per spinner instance or globally via the `updateSettings` function to support multilingual CLIs.\n\n  This update also improves the architecture by exposing the core settings to the prompts package, enabling more consistent default message handling across the codebase.\n\n  ```ts\n  // Per-instance customization\n  const spinner = prompts.spinner({\n    cancelMessage: \"Operación cancelada\", // \"Operation cancelled\" in Spanish\n    errorMessage: \"Se produjo un error\", // \"An error occurred\" in Spanish\n  });\n\n  // Global customization via updateSettings\n  prompts.updateSettings({\n    messages: {\n      cancel: \"Operación cancelada\", // \"Operation cancelled\" in Spanish\n      error: \"Se produjo un error\", // \"An error occurred\" in Spanish\n    },\n  });\n\n  // Settings can now be accessed directly\n  console.log(prompts.settings.messages.cancel); // \"Operación cancelada\"\n\n  // Direct options take priority over global settings\n  const spinner = prompts.spinner({\n    cancelMessage: \"Cancelled\", // This will be used instead of the global setting\n  });\n  ```\n\n- 44df9af: Adds a new `groupSpacing` option to grouped multi-select prompts. If set to an integer greater than 0, it will add that number of new lines between each group.\n- 55645c2: Support wrapping autocomplete and select prompts.\n- 9e5bc6c: Add support for signals in prompts, allowing them to be aborted.\n- f2c2b89: Adds `AutocompletePrompt` to core with comprehensive tests and implement both `autocomplete` and `autocomplete-multiselect` components in prompts package.\n- 38019c7: Updates the API for stopping spinners and progress bars to be clearer\n\n  Previously, both the spinner and progress bar components used a single `stop` method that accepted a code to indicate success, cancellation, or error. This update separates these into distinct methods: `stop()`, `cancel()`, and `error()`:\n\n  ```diff\n  const spinner = prompts.spinner();\n  spinner.start();\n\n  // Cancelling a spinner\n  - spinner.stop(undefined, 1);\n  + spinner.cancel();\n\n  // Stopping with an error\n  - spinner.stop(undefined, 2);\n  + spinner.error();\n  ```\n\n  As before, you can pass a message to each method to customize the output displayed:\n\n  ```js\n  spinner.cancel(\"Operation cancelled by user\");\n  progressBar.error(\"An error occurred during processing\");\n  ```\n\n- c45b9fb: Adds support for detecting spinner cancellation via CTRL+C. This allows for graceful handling of user interruptions during long-running operations.\n- f10071e: Using the `group` method, task logs can now have groups which themselves can have scrolling windows of logs.\n- df4eea1: Remove `suggestion` prompt and change `path` prompt to be an autocomplete prompt.\n- 76fd17f: Added new `box` prompt for rendering boxed text, similar a note.\n- 9a09318: Adds new `progress` prompt to display a progess-bar\n- 1604f97: Add `clearOnError` option to password prompt to automatically clear input when validation fails\n- 9bd8072: Add a `required` option to autocomplete multiselect.\n- 19558b9: Added support for custom frames in spinner prompt\n\n### Patch Changes\n\n- 46dc0a4: Fixes multiselect only shows hints on the first item in the options list. Now correctly shows hints for all selected options with hint property.\n- aea4573: Clamp scrolling windows to 5 rows.\n- bfe0dd3: Prevents placeholder from being used as input value in text prompts\n- 55eb280: Fix placeholder rendering when using autocomplete.\n- 4d1d83b: Fixes rendering of multi-line messages and options in select prompt.\n- 6176ced: Add withGuide support to note prompt\n- 7b009df: Fix spinner clearing too many lines upwards when non-wrapping.\n- 43aed55: Change styling of disabled multi-select options to have strikethrough.\n- 17342d2: Exposes a new `SpinnerResult` type to describe the return type of `spinner`\n- 282b39e: Wrap spinner output to allow for multi-line/wrapped messages.\n- 2feaebb: Fix duplicated logs when scrolling through options with multiline messages by calculating `rowPadding` dynamically based on actual rendered lines instead of using a hardcoded value.\n- 69681ea: Strip destructive ANSI codes from task log messages.\n- b0fa7d8: Add support for wrapped messages in multi line prompts\n- 9999adf: fix note component overflow bug\n- 6868c1c: Adds a new `selectableGroups` boolean to the group multi-select prompt. Using `selectableGroups: false` will disable the ability to select a top-level group, but still allow every child to be selected individually.\n- 7df841d: Removed all trailing space in prompt output and fixed various padding rendering bugs.\n- 2839c66: fix(note): hard wrap text to column limit\n- 7a556ad: Updates all prompts to accept a custom `output` and `input` stream\n- 17d3650: Use a default import for picocolors to avoid run time errors in some environments.\n- 7cc8a55: Messages passed to the `stop` method of a spinner no longer have dots stripped.\n- b103ad3: Allow disabled options in multi-select and select prompts.\n- 71b5029: Add missing nullish checks around values.\n- 1a45f93: Switched from wrap-ansi to fast-wrap-ansi\n- f952592: Fixes missing guide when rendering empty log lines.\n- 372b526: Add `clear` method to spinner for stopping and clearing.\n- d25f6d0: fix(note, box): handle CJK correctly\n- 94fee2a: Changes `placeholder` to be a visual hint rather than a tabbable value.\n- 7530af0: Fixes wrapping of cancelled and success messages of select prompt\n- 4c89dd7: chore: use more accurate type to replace any in group select\n- 0b852e1: Handle `stop` calls on spinners which have not yet been started.\n- 42adff8: fix: add missing guide line in autocomplete-multiselect\n- 8e2e30a: fix: fix autocomplete bar color when validate\n- 2048eb1: Fix spinner's dots behavior with custom frames\n- acc4c3a: Add a new `withGuide` option to all prompts to disable the default clack border\n- 9b92161: Show symbol when withGuide is true for log messages\n- 68dbf9b: select-key: Fixed wrapping and added new `caseSensitive` option\n- 09e596c: refactor(progress): remove unnecessary return statement in start function\n- 2310b43: Allow custom writables as output stream.\n- ae84dd0: Update key binding text to show tab/space when navigating, and tab otherwise.\n- Updated dependency on `@clack/core` to `1.0.0`\n\n## 0.10.0\n\n### Minor Changes\n\n- 613179d: Adds a new `indicator` option to `spinner`, which supports the original `\"dots\"` loading animation or a new `\"timer\"` loading animation.\n\n  ```ts\n  import * as p from \"@clack/prompts\";\n\n  const spin = p.spinner({ indicator: \"timer\" });\n  spin.start(\"Loading\");\n  await sleep(3000);\n  spin.stop(\"Loaded\");\n  ```\n\n- a38b2bc: Adds `stream` API which provides the same methods as `log`, but for iterable (even async) message streams. This is particularly useful for AI responses which are dynamically generated by LLMs.\n\n  ```ts\n  import * as p from \"@clack/prompts\";\n\n  await p.stream.step(\n    (async function* () {\n      yield* generateLLMResponse(question);\n    })()\n  );\n  ```\n\n## 0.9.1\n\n### Patch Changes\n\n- 8093f3c: Adds `Error` support to the `validate` function\n- 98925e3: Exports the `Option` type and improves JSDocannotations\n- 1904e57: Replace custom utility for stripping ANSI control sequences with Node's built-in [`stripVTControlCharacters`](https://nodejs.org/docs/latest/api/util.html#utilstripvtcontrolcharactersstr) utility.\n- Updated dependencies [8093f3c]\n- Updated dependencies [e5ba09a]\n- Updated dependencies [8cba8e3]\n  - @clack/core@0.4.1\n\n## 0.9.0\n\n### Minor Changes\n\n- a83d2f8: Adds a new `updateSettings()` function to support new global keybindings.\n\n  `updateSettings()` accepts an `aliases` object that maps custom keys to an action (`up | down | left | right | space | enter | cancel`).\n\n  ```ts\n  import { updateSettings } from \"@clack/prompts\";\n\n  // Support custom keybindings\n  updateSettings({\n    aliases: {\n      w: \"up\",\n      a: \"left\",\n      s: \"down\",\n      d: \"right\",\n    },\n  });\n  ```\n\n> [!WARNING]\n> In order to enforce consistent, user-friendly defaults across the ecosystem, `updateSettings` does not support disabling Clack's default keybindings.\n\n- 801246b: Adds a new `signal` option to support programmatic prompt cancellation with an [abort controller](https://kettanaito.com/blog/dont-sleep-on-abort-controller).\n\n  One example use case is automatically cancelling a prompt after a timeout.\n\n  ```ts\n  const shouldContinue = await confirm({\n    message: \"This message will self destruct in 5 seconds\",\n    signal: AbortSignal.timeout(5000),\n  });\n  ```\n\n  Another use case is racing a long running task with a manual prompt.\n\n  ```ts\n  const abortController = new AbortController();\n\n  const projectType = await Promise.race([\n    detectProjectType({\n      signal: abortController.signal,\n    }),\n    select({\n      message: \"Pick a project type.\",\n      options: [\n        { value: \"ts\", label: \"TypeScript\" },\n        { value: \"js\", label: \"JavaScript\" },\n        { value: \"coffee\", label: \"CoffeeScript\", hint: \"oh no\" },\n      ],\n      signal: abortController.signal,\n    }),\n  ]);\n\n  abortController.abort();\n  ```\n\n- a83d2f8: Updates default keybindings to support Vim motion shortcuts and map the `escape` key to cancel (`ctrl+c`).\n\n  | alias | action |\n  | ----- | ------ |\n  | `k`   | up     |\n  | `l`   | right  |\n  | `j`   | down   |\n  | `h`   | left   |\n  | `esc` | cancel |\n\n### Patch Changes\n\n- f9f139d: Adapts `spinner` output for static CI environments\n- Updated dependencies [a83d2f8]\n- Updated dependencies [801246b]\n- Updated dependencies [a83d2f8]\n- Updated dependencies [51e12bc]\n  - @clack/core@0.4.0\n\n## 0.8.2\n\n### Patch Changes\n\n- Updated dependencies [4845f4f]\n- Updated dependencies [d7b2fb9]\n  - @clack/core@0.3.5\n\n## 0.8.1\n\n### Patch Changes\n\n- 360afeb: feat: adaptative max items\n\n## 0.8.0\n\n### Minor Changes\n\n- 9acccde: Add tasks function for executing tasks in spinners\n\n### Patch Changes\n\n- b5c6b9b: Feat multiselect maxItems option\n- 50ed94a: fix: clear `spinner` hooks on `spinner.stop`\n- Updated dependencies [a04e418]\n- Updated dependencies [4f6fcf5]\n  - @clack/core@0.3.4\n\n## 0.7.0\n\n### Minor Changes\n\n- b27a701: add maxItems option to select prompt\n- 89371be: added a new method called `spinner.message(msg: string)`\n\n### Patch Changes\n\n- 52183c4: Fix `spinner` conflict with terminal on error between `spinner.start()` and `spinner.stop()`\n- ab51d29: Fixes cases where the note title length was miscalculated due to ansi characters\n- Updated dependencies [cd79076]\n  - @clack/core@0.3.3\n\n## 0.6.3\n\n### Patch Changes\n\n- c96eda5: Enable hard line-wrapping behavior for long words without spaces\n- Updated dependencies [c96eda5]\n  - @clack/core@0.3.2\n\n## 0.6.2\n\n### Patch Changes\n\n- 58a1df1: Fix line duplication bug by automatically wrapping prompts to `process.stdout.columns`\n- Updated dependencies [58a1df1]\n  - @clack/core@0.3.1\n\n## 0.6.1\n\n### Patch Changes\n\n- ca08fb6: Support complex value types for `select`, `multiselect` and `groupMultiselect`.\n\n## 0.6.0\n\n### Minor Changes\n\n- 8a4a12f: add `groupMultiselect` prompt\n- 165a1b3: Add `log` APIs. Supports `log.info`, `log.success`, `log.warn`, and `log.error`. For low-level control, `log.message` is also exposed.\n\n### Patch Changes\n\n- Updated dependencies [8a4a12f]\n- Updated dependencies [8a4a12f]\n  - @clack/core@0.3.0\n\n## 0.5.1\n\n### Patch Changes\n\n- cc11917: Update default `password` mask\n- Updated dependencies [ec812b6]\n  - @clack/core@0.2.1\n\n## 0.5.0\n\n### Minor Changes\n\n- d74dd05: Adds a `selectKey` prompt type\n- 54c1bc3: **Breaking Change** `multiselect` has renamed `initialValue` to `initialValues`\n\n### Patch Changes\n\n- Updated dependencies [d74dd05]\n- Updated dependencies [54c1bc3]\n  - @clack/core@0.2.0\n\n## 0.4.5\n\n### Patch Changes\n\n- 1251132: Multiselect: return `Value[]` instead of `Option[]`.\n- 8994382: Add a password prompt to `@clack/prompts`\n- Updated dependencies [1251132]\n- Updated dependencies [8994382]\n  - @clack/core@0.1.9\n\n## 0.4.4\n\n### Patch Changes\n\n- d96071c: Don't mutate `initialValue` in `multiselect`, fix parameter type for `validate()`.\n\n  Credits to @banjo for the bug report and initial PR!\n\n- Updated dependencies [d96071c]\n  - @clack/core@0.1.8\n\n## 0.4.3\n\n### Patch Changes\n\n- 83d890e: Fix text cancel display bug\n\n## 0.4.2\n\n### Patch Changes\n\n- Update README\n\n## 0.4.1\n\n### Patch Changes\n\n- 7fb5375: Adds a new `defaultValue` option to the text prompt, removes automatic usage of the placeholder value.\n- Updated dependencies [7fb5375]\n  - @clack/core@0.1.6\n\n## 0.4.0\n\n### Minor Changes\n\n- 61b88b6: Add `group` construct to group many prompts together\n\n### Patch Changes\n\n- de1314e: Support `required` option for multi-select\n- Updated dependencies [de1314e]\n  - @clack/core@0.1.5\n\n## 0.3.0\n\n### Minor Changes\n\n- 493c592: Improve types for select/multiselect prompts. Numbers and booleans are now supported as the `value` option.\n- 15558e3: Improved Windows/non-unicode support\n\n### Patch Changes\n\n- ca77da1: Fix multiselect initial value logic\n- Updated dependencies [ca77da1]\n- Updated dependencies [8aed606]\n  - @clack/core@0.1.4\n\n## 0.2.2\n\n### Patch Changes\n\n- 94b24d9: Fix CJS `ansi-regex` interop\n\n## 0.2.1\n\n### Patch Changes\n\n- a99c458: Support `initialValue` option for text prompt\n- Updated dependencies [a99c458]\n  - @clack/core@0.1.3\n\n## 0.2.0\n\n### Minor Changes\n\n- Improved type safety\n- b1341d6: Updated styles, new note component\n\n### Patch Changes\n\n- Updated dependencies [7dcad8f]\n- Updated dependencies [2242f13]\n- Updated dependencies [b1341d6]\n  - @clack/core@0.1.2\n\n## 0.1.1\n\n### Patch Changes\n\n- fa09bf5: Use circle for radio, square for checkbox\n- Updated dependencies [4be7dbf]\n- Updated dependencies [b480679]\n  - @clack/core@0.1.1\n\n## 0.1.0\n\n### Minor Changes\n\n- 7015ec9: Create new prompt: multi-select\n\n### Patch Changes\n\n- Updated dependencies [7015ec9]\n  - @clack/core@0.1.0\n\n## 0.0.10\n\n### Patch Changes\n\n- e0b49e5: Update spinner so it actually spins\n\n## 0.0.9\n\n### Patch Changes\n\n- Update README\n\n## 0.0.8\n\n### Patch Changes\n\n- Updated dependencies [9d371c3]\n  - @clack/core@0.0.12\n\n## 0.0.7\n\n### Patch Changes\n\n- Update README\n\n## 0.0.6\n\n### Patch Changes\n\n- d20ef2a: Update keywords, URLs\n- Updated dependencies [441d5b7]\n- Updated dependencies [d20ef2a]\n- Updated dependencies [fe13c2f]\n  - @clack/core@0.0.11\n\n## 0.0.5\n\n### Patch Changes\n\n- Update README\n\n## 0.0.4\n\n### Patch Changes\n\n- 80404ab: Update README\n\n## 0.0.3\n\n### Patch Changes\n\n- a0cb382: Add `main` entrypoint\n- Updated dependencies [a0cb382]\n  - @clack/core@0.0.10\n\n## 0.0.2\n\n### Patch Changes\n\n- Updated dependencies\n  - @clack/core@0.0.9\n\n## 0.0.1\n\n### Patch Changes\n\n- a4b5e13: Initial release\n- Updated dependencies [a4b5e13]\n  - @clack/core@0.0.8\n"
  },
  {
    "path": "packages/prompts/LICENSE",
    "content": "MIT License\n\nCopyright (c) Nate Moore\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "packages/prompts/README.md",
    "content": "# `@clack/prompts`\n\nEffortlessly build beautiful command-line apps 🪄 [Try the demo](https://stackblitz.com/edit/clack-prompts?file=index.js)\n\n![clack-prompt](https://github.com/bombshell-dev/clack/blob/main/.github/assets/clack-demo.gif)\n\n---\n\n`@clack/prompts` is an opinionated, pre-styled wrapper around [`@clack/core`](https://www.npmjs.com/package/@clack/core).\n\n- 🤏 80% smaller than other options\n- 💎 Beautiful, minimal UI\n- ✅ Simple API\n- 🧱 Comes with `text`, `confirm`, `select`, `multiselect`, and `spinner` components\n\n## Basics\n\n### Setup\n\nThe `intro` and `outro` functions will print a message to begin or end a prompt session, respectively.\n\n```js\nimport { intro, outro } from '@clack/prompts';\n\nintro(`create-my-app`);\n// Do stuff\noutro(`You're all set!`);\n```\n\n### Cancellation\n\nThe `isCancel` function is a guard that detects when a user cancels a question with `CTRL + C`. You should handle this situation for each prompt, optionally providing a nice cancellation message with the `cancel` utility.\n\n```js\nimport { isCancel, cancel, text } from '@clack/prompts';\n\nconst value = await text({\n  message: 'What is the meaning of life?',\n});\n\nif (isCancel(value)) {\n  cancel('Operation cancelled.');\n  process.exit(0);\n}\n```\n\n## Components\n\n### Text\n\nThe text component accepts a single line of text.\n\n```js\nimport { text } from '@clack/prompts';\n\nconst meaning = await text({\n  message: 'What is the meaning of life?',\n  placeholder: 'Not sure',\n  initialValue: '42',\n  validate(value) {\n    if (value.length === 0) return `Value is required!`;\n  },\n});\n```\n\n### Confirm\n\nThe confirm component accepts a yes or no answer. The result is a boolean value of `true` or `false`.\n\n```js\nimport { confirm } from '@clack/prompts';\n\nconst shouldContinue = await confirm({\n  message: 'Do you want to continue?',\n});\n```\n\n### Select\n\nThe select component allows a user to choose one value from a list of options. The result is the `value` prop of a given option.\n\n```js\nimport { select } from '@clack/prompts';\n\nconst projectType = await select({\n  message: 'Pick a project type.',\n  options: [\n    { value: 'ts', label: 'TypeScript' },\n    { value: 'js', label: 'JavaScript', disabled: true },\n    { value: 'coffee', label: 'CoffeeScript', hint: 'oh no' },\n  ],\n});\n```\n\n### Multi-Select\n\nThe `multiselect` component allows a user to choose many values from a list of options. The result is an array with all selected `value` props.\n\n```js\nimport { multiselect } from '@clack/prompts';\n\nconst additionalTools = await multiselect({\n  message: 'Select additional tools.',\n  options: [\n    { value: 'eslint', label: 'ESLint', hint: 'recommended' },\n    { value: 'prettier', label: 'Prettier', disabled: true },\n    { value: 'gh-action', label: 'GitHub Action' },\n  ],\n  required: false,\n});\n```\n\nIt is also possible to select multiple items arranged into hierarchy by using `groupMultiselect`:\n\n```js\nimport { groupMultiselect } from '@clack/prompts';\n\nconst basket = await groupMultiselect({\n  message: 'Select your favorite fruits and vegetables:',\n  options: {\n    fruits: [\n      { value: 'apple', label: 'apple' },\n      { value: 'banana', label: 'banana' },\n      { value: 'cherry', label: 'cherry' },\n    ],\n    vegetables: [\n      { value: 'carrot', label: 'carrot' },\n      { value: 'spinach', label: 'spinach' },\n      { value: 'potato', label: 'potato' },\n    ]\n  }\n});\n```\n\n### Spinner\n\nThe spinner component surfaces a pending action, such as a long-running download or dependency installation.\n\n```js\nimport { spinner } from '@clack/prompts';\n\nconst s = spinner();\ns.start('Installing via npm');\n// Do installation here\ns.stop('Installed via npm');\n```\n\n### Progress\n\nThe progress component extends the spinner component to add a progress bar to visualize the progression of an action.\n\n```js\nimport { progress } from '@clack/prompts';\n\nconst p = progress({ max: 10 });\np.start('Downloading archive');\n// Do download here\np.advance(3, 'Downloading (30%)');\n// ...\np.advance(8, 'Downloading (80%)');\n// ...\np.stop('Archive downloaded');\n```\n\n## Utilities\n\n### Grouping\n\nGrouping prompts together is a great way to keep your code organized. This accepts a JSON object with a name that can be used to reference the group later. The second argument is an optional but has a `onCancel` callback that will be called if the user cancels one of the prompts in the group.\n\n```js\nimport * as p from '@clack/prompts';\n\nconst group = await p.group(\n  {\n    name: () => p.text({ message: 'What is your name?' }),\n    age: () => p.text({ message: 'What is your age?' }),\n    color: ({ results }) =>\n      p.multiselect({\n        message: `What is your favorite color ${results.name}?`,\n        options: [\n          { value: 'red', label: 'Red' },\n          { value: 'green', label: 'Green' },\n          { value: 'blue', label: 'Blue' },\n        ],\n      }),\n  },\n  {\n    // On Cancel callback that wraps the group\n    // So if the user cancels one of the prompts in the group this function will be called\n    onCancel: ({ results }) => {\n      p.cancel('Operation cancelled.');\n      process.exit(0);\n    },\n  }\n);\n\nconsole.log(group.name, group.age, group.color);\n```\n\n### Tasks\n\nExecute multiple tasks in spinners.\n\n```js\nimport { tasks } from '@clack/prompts';\n\nawait tasks([\n  {\n    title: 'Installing via npm',\n    task: async (message) => {\n      // Do installation here\n      return 'Installed via npm';\n    },\n  },\n]);\n```\n\n### Logs\n\n```js\nimport { log } from '@clack/prompts';\n\nlog.info('Info!');\nlog.success('Success!');\nlog.step('Step!');\nlog.warn('Warn!');\nlog.error('Error!');\nlog.message('Hello, World', { symbol: color.cyan('~') });\n```\n\n\n### Stream\n\nWhen interacting with dynamic LLMs or other streaming message providers, use the `stream` APIs to log messages from an iterable, even an async one.\n\n```js\nimport { stream } from '@clack/prompts';\n\nstream.info((function *() { yield 'Info!'; })());\nstream.success((function *() { yield 'Success!'; })());\nstream.step((function *() { yield 'Step!'; })());\nstream.warn((function *() { yield 'Warn!'; })());\nstream.error((function *() { yield 'Error!'; })());\nstream.message((function *() { yield 'Hello'; yield \", World\" })(), { symbol: color.cyan('~') });\n```\n\n![clack-log-prompts](https://github.com/bombshell-dev/clack/blob/main/.github/assets/clack-logs.png)\n\n### Task Log\n\nWhen executing a sub-process or a similar sub-task, `taskLog` can be used to render the output continuously and clear it at the end if it was successful.\n\n```js\nimport { taskLog } from '@clack/prompts';\n\nconst log = taskLog({\n\ttitle: 'Running npm install'\n});\n\nfor await (const line of npmInstall()) {\n\tlog.message(line);\n}\n\nif (success) {\n\tlog.success('Done!');\n} else {\n\tlog.error('Failed!');\n}\n```\n"
  },
  {
    "path": "packages/prompts/__mocks__/fs.cjs",
    "content": "const { fs } = require('memfs');\nmodule.exports = fs;\n"
  },
  {
    "path": "packages/prompts/build.config.ts",
    "content": "import { defineBuildConfig } from 'unbuild';\n\nexport default defineBuildConfig({\n\tpreset: '../../build.preset',\n\tentries: ['src/index'],\n});\n"
  },
  {
    "path": "packages/prompts/package.json",
    "content": "{\n  \"name\": \"@clack/prompts\",\n  \"version\": \"1.1.0\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.mjs\",\n  \"module\": \"./dist/index.mjs\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./dist/index.d.mts\",\n      \"default\": \"./dist/index.mjs\"\n    },\n    \"./package.json\": \"./package.json\"\n  },\n  \"types\": \"./dist/index.d.mts\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/bombshell-dev/clack.git\",\n    \"directory\": \"packages/prompts\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/bombshell-dev/clack/issues\"\n  },\n  \"homepage\": \"https://github.com/bombshell-dev/clack/tree/main/packages/prompts#readme\",\n  \"files\": [\n    \"dist\",\n    \"CHANGELOG.md\"\n  ],\n  \"author\": {\n    \"name\": \"Nate Moore\",\n    \"email\": \"nate@natemoo.re\",\n    \"url\": \"https://twitter.com/n_moore\"\n  },\n  \"license\": \"MIT\",\n  \"keywords\": [\n    \"ask\",\n    \"clack\",\n    \"cli\",\n    \"command-line\",\n    \"command\",\n    \"input\",\n    \"interact\",\n    \"interface\",\n    \"menu\",\n    \"prompt\",\n    \"prompts\",\n    \"stdin\",\n    \"ui\"\n  ],\n  \"packageManager\": \"pnpm@9.14.2\",\n  \"scripts\": {\n    \"build\": \"unbuild\",\n    \"prepack\": \"pnpm build\",\n    \"test\": \"vitest run\"\n  },\n  \"dependencies\": {\n    \"@clack/core\": \"workspace:*\",\n    \"fast-string-width\": \"^1.1.0\",\n    \"fast-wrap-ansi\": \"^0.1.3\",\n    \"sisteransi\": \"^1.0.5\"\n  },\n  \"devDependencies\": {\n    \"is-unicode-supported\": \"^1.3.0\",\n    \"memfs\": \"^4.17.2\",\n    \"vitest\": \"^3.2.4\",\n    \"vitest-ansi-serializer\": \"^0.1.2\"\n  }\n}\n"
  },
  {
    "path": "packages/prompts/src/autocomplete.ts",
    "content": "import { styleText } from 'node:util';\nimport { AutocompletePrompt, settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\nimport type { Option } from './select.js';\n\nfunction getLabel<T>(option: Option<T>) {\n\treturn option.label ?? String(option.value ?? '');\n}\n\nfunction getFilteredOption<T>(searchText: string, option: Option<T>): boolean {\n\tif (!searchText) {\n\t\treturn true;\n\t}\n\tconst label = (option.label ?? String(option.value ?? '')).toLowerCase();\n\tconst hint = (option.hint ?? '').toLowerCase();\n\tconst value = String(option.value).toLowerCase();\n\tconst term = searchText.toLowerCase();\n\n\treturn label.includes(term) || hint.includes(term) || value.includes(term);\n}\n\nfunction getSelectedOptions<T>(values: T[], options: Option<T>[]): Option<T>[] {\n\tconst results: Option<T>[] = [];\n\n\tfor (const option of options) {\n\t\tif (values.includes(option.value)) {\n\t\t\tresults.push(option);\n\t\t}\n\t}\n\n\treturn results;\n}\n\ninterface AutocompleteSharedOptions<Value> extends CommonOptions {\n\t/**\n\t * The message to display to the user.\n\t */\n\tmessage: string;\n\t/**\n\t * Available options for the autocomplete prompt.\n\t */\n\toptions: Option<Value>[] | ((this: AutocompletePrompt<Option<Value>>) => Option<Value>[]);\n\t/**\n\t * Maximum number of items to display at once.\n\t */\n\tmaxItems?: number;\n\t/**\n\t * Placeholder text to display when no input is provided.\n\t */\n\tplaceholder?: string;\n\t/**\n\t * Validates the value\n\t */\n\tvalidate?: (value: Value | Value[] | undefined) => string | Error | undefined;\n\t/**\n\t * Custom filter function to match options against search input.\n\t * If not provided, a default filter that matches label, hint, and value is used.\n\t */\n\tfilter?: (search: string, option: Option<Value>) => boolean;\n}\n\nexport interface AutocompleteOptions<Value> extends AutocompleteSharedOptions<Value> {\n\t/**\n\t * The initial selected value.\n\t */\n\tinitialValue?: Value;\n\t/**\n\t * The initial user input\n\t */\n\tinitialUserInput?: string;\n}\n\nexport const autocomplete = <Value>(opts: AutocompleteOptions<Value>) => {\n\tconst prompt = new AutocompletePrompt({\n\t\toptions: opts.options,\n\t\tinitialValue: opts.initialValue ? [opts.initialValue] : undefined,\n\t\tinitialUserInput: opts.initialUserInput,\n\t\tplaceholder: opts.placeholder,\n\t\tfilter:\n\t\t\topts.filter ??\n\t\t\t((search: string, opt: Option<Value>) => {\n\t\t\t\treturn getFilteredOption(search, opt);\n\t\t\t}),\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tvalidate: opts.validate,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\t// Title and message display\n\t\t\tconst headings = hasGuide\n\t\t\t\t? [`${styleText('gray', S_BAR)}`, `${symbol(this.state)}  ${opts.message}`]\n\t\t\t\t: [`${symbol(this.state)}  ${opts.message}`];\n\t\t\tconst userInput = this.userInput;\n\t\t\tconst options = this.options;\n\t\t\tconst placeholder = opts.placeholder;\n\t\t\tconst showPlaceholder = userInput === '' && placeholder !== undefined;\n\t\t\tconst opt = (option: Option<Value>, state: 'inactive' | 'active' | 'disabled') => {\n\t\t\t\tconst label = getLabel(option);\n\t\t\t\tconst hint =\n\t\t\t\t\toption.hint && option.value === this.focusedValue\n\t\t\t\t\t\t? styleText('dim', ` (${option.hint})`)\n\t\t\t\t\t\t: '';\n\t\t\t\tswitch (state) {\n\t\t\t\t\tcase 'active':\n\t\t\t\t\t\treturn `${styleText('green', S_RADIO_ACTIVE)} ${label}${hint}`;\n\t\t\t\t\tcase 'inactive':\n\t\t\t\t\t\treturn `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', label)}`;\n\t\t\t\t\tcase 'disabled':\n\t\t\t\t\t\treturn `${styleText('gray', S_RADIO_INACTIVE)} ${styleText(['strikethrough', 'gray'], label)}`;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Handle different states\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\t// Show selected value\n\t\t\t\t\tconst selected = getSelectedOptions(this.selectedValues, options);\n\t\t\t\t\tconst label =\n\t\t\t\t\t\tselected.length > 0 ? `  ${styleText('dim', selected.map(getLabel).join(', '))}` : '';\n\t\t\t\t\tconst submitPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${headings.join('\\n')}\\n${submitPrefix}${label}`;\n\t\t\t\t}\n\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst userInputText = userInput\n\t\t\t\t\t\t? `  ${styleText(['strikethrough', 'dim'], userInput)}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\tconst cancelPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${headings.join('\\n')}\\n${cancelPrefix}${userInputText}`;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tconst barStyle = this.state === 'error' ? 'yellow' : 'cyan';\n\t\t\t\t\tconst guidePrefix = hasGuide ? `${styleText(barStyle, S_BAR)}  ` : '';\n\t\t\t\t\tconst guidePrefixEnd = hasGuide ? styleText(barStyle, S_BAR_END) : '';\n\t\t\t\t\t// Display cursor position - show plain text in navigation mode\n\t\t\t\t\tlet searchText = '';\n\t\t\t\t\tif (this.isNavigating || showPlaceholder) {\n\t\t\t\t\t\tconst searchTextValue = showPlaceholder ? placeholder : userInput;\n\t\t\t\t\t\tsearchText = searchTextValue !== '' ? ` ${styleText('dim', searchTextValue)}` : '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsearchText = ` ${this.userInputWithCursor}`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Show match count if filtered\n\t\t\t\t\tconst matches =\n\t\t\t\t\t\tthis.filteredOptions.length !== options.length\n\t\t\t\t\t\t\t? styleText(\n\t\t\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t\t\t` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? '' : 'es'})`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: '';\n\n\t\t\t\t\t// No matches message\n\t\t\t\t\tconst noResults =\n\t\t\t\t\t\tthis.filteredOptions.length === 0 && userInput\n\t\t\t\t\t\t\t? [`${guidePrefix}${styleText('yellow', 'No matches found')}`]\n\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\tconst validationError =\n\t\t\t\t\t\tthis.state === 'error' ? [`${guidePrefix}${styleText('yellow', this.error)}`] : [];\n\n\t\t\t\t\tif (hasGuide) {\n\t\t\t\t\t\theadings.push(`${guidePrefix.trimEnd()}`);\n\t\t\t\t\t}\n\t\t\t\t\theadings.push(\n\t\t\t\t\t\t`${guidePrefix}${styleText('dim', 'Search:')}${searchText}${matches}`,\n\t\t\t\t\t\t...noResults,\n\t\t\t\t\t\t...validationError\n\t\t\t\t\t);\n\n\t\t\t\t\t// Show instructions\n\t\t\t\t\tconst instructions = [\n\t\t\t\t\t\t`${styleText('dim', '↑/↓')} to select`,\n\t\t\t\t\t\t`${styleText('dim', 'Enter:')} confirm`,\n\t\t\t\t\t\t`${styleText('dim', 'Type:')} to search`,\n\t\t\t\t\t];\n\n\t\t\t\t\tconst footers = [`${guidePrefix}${instructions.join(' • ')}`, guidePrefixEnd];\n\n\t\t\t\t\t// Render options with selection\n\t\t\t\t\tconst displayOptions =\n\t\t\t\t\t\tthis.filteredOptions.length === 0\n\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t: limitOptions({\n\t\t\t\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\t\t\t\toptions: this.filteredOptions,\n\t\t\t\t\t\t\t\t\tcolumnPadding: hasGuide ? 3 : 0, // for `|  ` when guide is shown\n\t\t\t\t\t\t\t\t\trowPadding: headings.length + footers.length,\n\t\t\t\t\t\t\t\t\tstyle: (option, active) => {\n\t\t\t\t\t\t\t\t\t\treturn opt(\n\t\t\t\t\t\t\t\t\t\t\toption,\n\t\t\t\t\t\t\t\t\t\t\toption.disabled ? 'disabled' : active ? 'active' : 'inactive'\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t// Return the formatted prompt\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...headings,\n\t\t\t\t\t\t...displayOptions.map((option) => `${guidePrefix}${option}`),\n\t\t\t\t\t\t...footers,\n\t\t\t\t\t].join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the result or cancel symbol\n\treturn prompt.prompt() as Promise<Value | symbol>;\n};\n\n// Type definition for the autocompleteMultiselect component\nexport interface AutocompleteMultiSelectOptions<Value> extends AutocompleteSharedOptions<Value> {\n\t/**\n\t * The initial selected values\n\t */\n\tinitialValues?: Value[];\n\t/**\n\t * If true, at least one option must be selected\n\t */\n\trequired?: boolean;\n}\n\n/**\n * Integrated autocomplete multiselect - combines type-ahead filtering with multiselect in one UI\n */\nexport const autocompleteMultiselect = <Value>(opts: AutocompleteMultiSelectOptions<Value>) => {\n\tconst formatOption = (\n\t\toption: Option<Value>,\n\t\tactive: boolean,\n\t\tselectedValues: Value[],\n\t\tfocusedValue: Value | undefined\n\t) => {\n\t\tconst isSelected = selectedValues.includes(option.value);\n\t\tconst label = option.label ?? String(option.value ?? '');\n\t\tconst hint =\n\t\t\toption.hint && focusedValue !== undefined && option.value === focusedValue\n\t\t\t\t? styleText('dim', ` (${option.hint})`)\n\t\t\t\t: '';\n\t\tconst checkbox = isSelected\n\t\t\t? styleText('green', S_CHECKBOX_SELECTED)\n\t\t\t: styleText('dim', S_CHECKBOX_INACTIVE);\n\n\t\tif (option.disabled) {\n\t\t\treturn `${styleText('gray', S_CHECKBOX_INACTIVE)} ${styleText(['strikethrough', 'gray'], label)}`;\n\t\t}\n\t\tif (active) {\n\t\t\treturn `${checkbox} ${label}${hint}`;\n\t\t}\n\t\treturn `${checkbox} ${styleText('dim', label)}`;\n\t};\n\n\t// Create text prompt which we'll use as foundation\n\tconst prompt = new AutocompletePrompt<Option<Value>>({\n\t\toptions: opts.options,\n\t\tmultiple: true,\n\t\tplaceholder: opts.placeholder,\n\t\tfilter:\n\t\t\topts.filter ??\n\t\t\t((search, opt) => {\n\t\t\t\treturn getFilteredOption(search, opt);\n\t\t\t}),\n\t\tvalidate: () => {\n\t\t\tif (opts.required && prompt.selectedValues.length === 0) {\n\t\t\t\treturn 'Please select at least one item';\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t\tinitialValue: opts.initialValues,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\trender() {\n\t\t\t// Title and symbol\n\t\t\tconst title = `${styleText('gray', S_BAR)}\\n${symbol(this.state)}  ${opts.message}\\n`;\n\n\t\t\t// Selection counter\n\t\t\tconst userInput = this.userInput;\n\t\t\tconst placeholder = opts.placeholder;\n\t\t\tconst showPlaceholder = userInput === '' && placeholder !== undefined;\n\n\t\t\t// Search input display\n\t\t\tconst searchText =\n\t\t\t\tthis.isNavigating || showPlaceholder\n\t\t\t\t\t? styleText('dim', showPlaceholder ? placeholder : userInput) // Just show plain text when in navigation mode\n\t\t\t\t\t: this.userInputWithCursor;\n\n\t\t\tconst options = this.options;\n\n\t\t\tconst matches =\n\t\t\t\tthis.filteredOptions.length !== options.length\n\t\t\t\t\t? styleText(\n\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? '' : 'es'})`\n\t\t\t\t\t\t)\n\t\t\t\t\t: '';\n\n\t\t\t// Render prompt state\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\treturn `${title}${styleText('gray', S_BAR)}  ${styleText('dim', `${this.selectedValues.length} items selected`)}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\treturn `${title}${styleText('gray', S_BAR)}  ${styleText(['strikethrough', 'dim'], userInput)}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst barStyle = this.state === 'error' ? 'yellow' : 'cyan';\n\t\t\t\t\t// Instructions\n\t\t\t\t\tconst instructions = [\n\t\t\t\t\t\t`${styleText('dim', '↑/↓')} to navigate`,\n\t\t\t\t\t\t`${styleText('dim', this.isNavigating ? 'Space/Tab:' : 'Tab:')} select`,\n\t\t\t\t\t\t`${styleText('dim', 'Enter:')} confirm`,\n\t\t\t\t\t\t`${styleText('dim', 'Type:')} to search`,\n\t\t\t\t\t];\n\n\t\t\t\t\t// No results message\n\t\t\t\t\tconst noResults =\n\t\t\t\t\t\tthis.filteredOptions.length === 0 && userInput\n\t\t\t\t\t\t\t? [`${styleText(barStyle, S_BAR)}  ${styleText('yellow', 'No matches found')}`]\n\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\tconst errorMessage =\n\t\t\t\t\t\tthis.state === 'error'\n\t\t\t\t\t\t\t? [`${styleText(barStyle, S_BAR)}  ${styleText('yellow', this.error)}`]\n\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\t// Calculate header and footer line counts for rowPadding\n\t\t\t\t\tconst headerLines = [\n\t\t\t\t\t\t...`${title}${styleText(barStyle, S_BAR)}`.split('\\n'),\n\t\t\t\t\t\t`${styleText(barStyle, S_BAR)}  ${styleText('dim', 'Search:')} ${searchText}${matches}`,\n\t\t\t\t\t\t...noResults,\n\t\t\t\t\t\t...errorMessage,\n\t\t\t\t\t];\n\t\t\t\t\tconst footerLines = [\n\t\t\t\t\t\t`${styleText(barStyle, S_BAR)}  ${instructions.join(' • ')}`,\n\t\t\t\t\t\tstyleText(barStyle, S_BAR_END),\n\t\t\t\t\t];\n\n\t\t\t\t\t// Get limited options for display\n\t\t\t\t\tconst displayOptions = limitOptions({\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\toptions: this.filteredOptions,\n\t\t\t\t\t\tstyle: (option, active) =>\n\t\t\t\t\t\t\tformatOption(option, active, this.selectedValues, this.focusedValue),\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\trowPadding: headerLines.length + footerLines.length,\n\t\t\t\t\t});\n\n\t\t\t\t\t// Build the prompt display\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...headerLines,\n\t\t\t\t\t\t...displayOptions.map((option) => `${styleText(barStyle, S_BAR)}  ${option}`),\n\t\t\t\t\t\t...footerLines,\n\t\t\t\t\t].join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the result or cancel symbol\n\treturn prompt.prompt() as Promise<Value[] | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/src/box.ts",
    "content": "import type { Writable } from 'node:stream';\nimport { getColumns, settings } from '@clack/core';\nimport stringWidth from 'fast-string-width';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_BAR_END_RIGHT,\n\tS_BAR_H,\n\tS_BAR_START,\n\tS_BAR_START_RIGHT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n\tS_CORNER_TOP_LEFT,\n\tS_CORNER_TOP_RIGHT,\n} from './common.js';\n\nexport type BoxAlignment = 'left' | 'center' | 'right';\n\ntype BoxSymbols = [topLeft: string, topRight: string, bottomLeft: string, bottomRight: string];\n\nconst roundedSymbols: BoxSymbols = [\n\tS_CORNER_TOP_LEFT,\n\tS_CORNER_TOP_RIGHT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n];\nconst squareSymbols: BoxSymbols = [S_BAR_START, S_BAR_START_RIGHT, S_BAR_END, S_BAR_END_RIGHT];\n\nexport interface BoxOptions extends CommonOptions {\n\tcontentAlign?: BoxAlignment;\n\ttitleAlign?: BoxAlignment;\n\twidth?: number | 'auto';\n\ttitlePadding?: number;\n\tcontentPadding?: number;\n\trounded?: boolean;\n\tformatBorder?: (text: string) => string;\n}\n\nfunction getPaddingForLine(\n\tlineLength: number,\n\tinnerWidth: number,\n\tpadding: number,\n\tcontentAlign: BoxAlignment | undefined\n): [number, number] {\n\tlet leftPadding = padding;\n\tlet rightPadding = padding;\n\tif (contentAlign === 'center') {\n\t\tleftPadding = Math.floor((innerWidth - lineLength) / 2);\n\t} else if (contentAlign === 'right') {\n\t\tleftPadding = innerWidth - lineLength - padding;\n\t}\n\n\trightPadding = innerWidth - leftPadding - lineLength;\n\n\treturn [leftPadding, rightPadding];\n}\n\nconst defaultFormatBorder = (text: string) => text;\n\nexport const box = (message = '', title = '', opts?: BoxOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst columns = getColumns(output);\n\tconst borderWidth = 1;\n\tconst borderTotalWidth = borderWidth * 2;\n\tconst titlePadding = opts?.titlePadding ?? 1;\n\tconst contentPadding = opts?.contentPadding ?? 2;\n\tconst width = opts?.width === undefined || opts.width === 'auto' ? 1 : Math.min(1, opts.width);\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst linePrefix = !hasGuide ? '' : `${S_BAR} `;\n\tconst formatBorder = opts?.formatBorder ?? defaultFormatBorder;\n\tconst symbols = (opts?.rounded ? roundedSymbols : squareSymbols).map(formatBorder);\n\tconst hSymbol = formatBorder(S_BAR_H);\n\tconst vSymbol = formatBorder(S_BAR);\n\tconst linePrefixWidth = stringWidth(linePrefix);\n\tconst titleWidth = stringWidth(title);\n\tconst maxBoxWidth = columns - linePrefixWidth;\n\tlet boxWidth = Math.floor(columns * width) - linePrefixWidth;\n\tif (opts?.width === 'auto') {\n\t\tconst lines = message.split('\\n');\n\t\tlet longestLine = titleWidth + titlePadding * 2;\n\t\tfor (const line of lines) {\n\t\t\tconst lineWithPadding = stringWidth(line) + contentPadding * 2;\n\t\t\tif (lineWithPadding > longestLine) {\n\t\t\t\tlongestLine = lineWithPadding;\n\t\t\t}\n\t\t}\n\t\tconst longestLineWidth = longestLine + borderTotalWidth;\n\t\tif (longestLineWidth < boxWidth) {\n\t\t\tboxWidth = longestLineWidth;\n\t\t}\n\t}\n\tif (boxWidth % 2 !== 0) {\n\t\tif (boxWidth < maxBoxWidth) {\n\t\t\tboxWidth++;\n\t\t} else {\n\t\t\tboxWidth--;\n\t\t}\n\t}\n\tconst innerWidth = boxWidth - borderTotalWidth;\n\tconst maxTitleLength = innerWidth - titlePadding * 2;\n\tconst truncatedTitle =\n\t\ttitleWidth > maxTitleLength ? `${title.slice(0, maxTitleLength - 3)}...` : title;\n\tconst [titlePaddingLeft, titlePaddingRight] = getPaddingForLine(\n\t\tstringWidth(truncatedTitle),\n\t\tinnerWidth,\n\t\ttitlePadding,\n\t\topts?.titleAlign\n\t);\n\tconst wrappedMessage = wrapAnsi(message, innerWidth - contentPadding * 2, {\n\t\thard: true,\n\t\ttrim: false,\n\t});\n\toutput.write(\n\t\t`${linePrefix}${symbols[0]}${hSymbol.repeat(titlePaddingLeft)}${truncatedTitle}${hSymbol.repeat(titlePaddingRight)}${symbols[1]}\\n`\n\t);\n\tconst wrappedLines = wrappedMessage.split('\\n');\n\tfor (const line of wrappedLines) {\n\t\tconst [leftLinePadding, rightLinePadding] = getPaddingForLine(\n\t\t\tstringWidth(line),\n\t\t\tinnerWidth,\n\t\t\tcontentPadding,\n\t\t\topts?.contentAlign\n\t\t);\n\t\toutput.write(\n\t\t\t`${linePrefix}${vSymbol}${' '.repeat(leftLinePadding)}${line}${' '.repeat(rightLinePadding)}${vSymbol}\\n`\n\t\t);\n\t}\n\toutput.write(`${linePrefix}${symbols[2]}${hSymbol.repeat(innerWidth)}${symbols[3]}\\n`);\n};\n"
  },
  {
    "path": "packages/prompts/src/common.ts",
    "content": "import type { Readable, Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport type { State } from '@clack/core';\nimport isUnicodeSupported from 'is-unicode-supported';\n\nexport const unicode = isUnicodeSupported();\nexport const isCI = (): boolean => process.env.CI === 'true';\nexport const isTTY = (output: Writable): boolean => {\n\treturn (output as Writable & { isTTY?: boolean }).isTTY === true;\n};\nexport const unicodeOr = (c: string, fallback: string) => (unicode ? c : fallback);\nexport const S_STEP_ACTIVE = unicodeOr('◆', '*');\nexport const S_STEP_CANCEL = unicodeOr('■', 'x');\nexport const S_STEP_ERROR = unicodeOr('▲', 'x');\nexport const S_STEP_SUBMIT = unicodeOr('◇', 'o');\n\nexport const S_BAR_START = unicodeOr('┌', 'T');\nexport const S_BAR = unicodeOr('│', '|');\nexport const S_BAR_END = unicodeOr('└', '—');\nexport const S_BAR_START_RIGHT = unicodeOr('┐', 'T');\nexport const S_BAR_END_RIGHT = unicodeOr('┘', '—');\n\nexport const S_RADIO_ACTIVE = unicodeOr('●', '>');\nexport const S_RADIO_INACTIVE = unicodeOr('○', ' ');\nexport const S_CHECKBOX_ACTIVE = unicodeOr('◻', '[•]');\nexport const S_CHECKBOX_SELECTED = unicodeOr('◼', '[+]');\nexport const S_CHECKBOX_INACTIVE = unicodeOr('◻', '[ ]');\nexport const S_PASSWORD_MASK = unicodeOr('▪', '•');\n\nexport const S_BAR_H = unicodeOr('─', '-');\nexport const S_CORNER_TOP_RIGHT = unicodeOr('╮', '+');\nexport const S_CONNECT_LEFT = unicodeOr('├', '+');\nexport const S_CORNER_BOTTOM_RIGHT = unicodeOr('╯', '+');\nexport const S_CORNER_BOTTOM_LEFT = unicodeOr('╰', '+');\nexport const S_CORNER_TOP_LEFT = unicodeOr('╭', '+');\n\nexport const S_INFO = unicodeOr('●', '•');\nexport const S_SUCCESS = unicodeOr('◆', '*');\nexport const S_WARN = unicodeOr('▲', '!');\nexport const S_ERROR = unicodeOr('■', 'x');\n\nexport const symbol = (state: State) => {\n\tswitch (state) {\n\t\tcase 'initial':\n\t\tcase 'active':\n\t\t\treturn styleText('cyan', S_STEP_ACTIVE);\n\t\tcase 'cancel':\n\t\t\treturn styleText('red', S_STEP_CANCEL);\n\t\tcase 'error':\n\t\t\treturn styleText('yellow', S_STEP_ERROR);\n\t\tcase 'submit':\n\t\t\treturn styleText('green', S_STEP_SUBMIT);\n\t}\n};\n\nexport const symbolBar = (state: State) => {\n\tswitch (state) {\n\t\tcase 'initial':\n\t\tcase 'active':\n\t\t\treturn styleText('cyan', S_BAR);\n\t\tcase 'cancel':\n\t\t\treturn styleText('red', S_BAR);\n\t\tcase 'error':\n\t\t\treturn styleText('yellow', S_BAR);\n\t\tcase 'submit':\n\t\t\treturn styleText('green', S_BAR);\n\t}\n};\n\nexport interface CommonOptions {\n\tinput?: Readable;\n\toutput?: Writable;\n\tsignal?: AbortSignal;\n\twithGuide?: boolean;\n}\n"
  },
  {
    "path": "packages/prompts/src/confirm.ts",
    "content": "import { styleText } from 'node:util';\nimport { ConfirmPrompt, settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n} from './common.js';\n\nexport interface ConfirmOptions extends CommonOptions {\n\tmessage: string;\n\tactive?: string;\n\tinactive?: string;\n\tinitialValue?: boolean;\n\tvertical?: boolean;\n}\nexport const confirm = (opts: ConfirmOptions) => {\n\tconst active = opts.active ?? 'Yes';\n\tconst inactive = opts.inactive ?? 'No';\n\treturn new ConfirmPrompt({\n\t\tactive,\n\t\tinactive,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue ?? true,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)}  ${opts.message}\\n`;\n\t\t\tconst value = this.value ? active : inactive;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${styleText('dim', value)}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${styleText(['strikethrough', 'dim'], value)}${\n\t\t\t\t\t\thasGuide ? `\\n${styleText('gray', S_BAR)}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)}  ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${\n\t\t\t\t\t\tthis.value\n\t\t\t\t\t\t\t? `${styleText('green', S_RADIO_ACTIVE)} ${active}`\n\t\t\t\t\t\t\t: `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', active)}`\n\t\t\t\t\t}${opts.vertical ? (hasGuide ? `\\n${styleText('cyan', S_BAR)}  ` : '\\n') : ` ${styleText('dim', '/')} `}${\n\t\t\t\t\t\t!this.value\n\t\t\t\t\t\t\t? `${styleText('green', S_RADIO_ACTIVE)} ${inactive}`\n\t\t\t\t\t\t\t: `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', inactive)}`\n\t\t\t\t\t}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<boolean | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/src/date.ts",
    "content": "import { styleText } from 'node:util';\nimport type { DateFormat, State } from '@clack/core';\nimport { DatePrompt, settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\n\nexport type { DateFormat };\n\nexport interface DateOptions extends CommonOptions {\n\tmessage: string;\n\tformat?: DateFormat;\n\tlocale?: string;\n\tdefaultValue?: Date;\n\tinitialValue?: Date;\n\tminDate?: Date;\n\tmaxDate?: Date;\n\tvalidate?: (value: Date | undefined) => string | Error | undefined;\n}\n\nexport const date = (opts: DateOptions) => {\n\tconst validate = opts.validate;\n\treturn new DatePrompt({\n\t\t...opts,\n\t\tvalidate(value: Date | undefined) {\n\t\t\tif (value === undefined) {\n\t\t\t\tif (opts.defaultValue !== undefined) return undefined;\n\t\t\t\tif (validate) return validate(value);\n\t\t\t\treturn settings.date.messages.required;\n\t\t\t}\n\t\t\tconst iso = (d: Date) => d.toISOString().slice(0, 10);\n\t\t\tif (opts.minDate && iso(value) < iso(opts.minDate)) {\n\t\t\t\treturn settings.date.messages.afterMin(opts.minDate);\n\t\t\t}\n\t\t\tif (opts.maxDate && iso(value) > iso(opts.maxDate)) {\n\t\t\t\treturn settings.date.messages.beforeMax(opts.maxDate);\n\t\t\t}\n\t\t\tif (validate) return validate(value);\n\t\t\treturn undefined;\n\t\t},\n\t\trender() {\n\t\t\tconst hasGuide = (opts?.withGuide ?? settings.withGuide) !== false;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)}  `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\n\t\t\tconst state = this.state !== 'initial' ? this.state : 'active';\n\n\t\t\tconst userInput = renderDate(this, state);\n\t\t\tconst value = this.value instanceof Date ? this.formattedValue : '';\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorText = this.error ? `  ${styleText('yellow', this.error)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? `${styleText('yellow', S_BAR)}  ` : '';\n\t\t\t\t\tconst barEnd = hasGuide ? styleText('yellow', S_BAR_END) : '';\n\t\t\t\t\treturn `${title.trim()}\\n${bar}${userInput}\\n${barEnd}${errorText}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst valueText = value ? `  ${styleText('dim', value)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${bar}${valueText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst valueText = value ? `  ${styleText(['strikethrough', 'dim'], value)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${bar}${valueText}${value.trim() ? `\\n${bar}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst bar = hasGuide ? `${styleText('cyan', S_BAR)}  ` : '';\n\t\t\t\t\tconst barEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst inlineBar = hasGuide ? `${styleText('cyan', S_BAR)}  ` : '';\n\t\t\t\t\tconst inlineError = this.inlineError\n\t\t\t\t\t\t? `\\n${inlineBar}${styleText('yellow', this.inlineError)}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `${title}${bar}${userInput}${inlineError}\\n${barEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Date | symbol>;\n};\n\nfunction renderDate(prompt: Omit<InstanceType<typeof DatePrompt>, 'prompt'>, state: State): string {\n\tconst parts = prompt.segmentValues;\n\tconst cursor = prompt.segmentCursor;\n\n\tif (state === 'submit' || state === 'cancel') {\n\t\treturn prompt.formattedValue;\n\t}\n\n\tconst sep = styleText('gray', prompt.separator);\n\treturn prompt.segments\n\t\t.map((seg, i) => {\n\t\t\tconst isActive = i === cursor.segmentIndex && !['submit', 'cancel'].includes(state);\n\t\t\tconst label = DEFAULT_LABELS[seg.type];\n\t\t\treturn renderSegment(parts[seg.type], { isActive, label });\n\t\t})\n\t\t.join(sep);\n}\n\ninterface SegmentOptions {\n\tisActive: boolean;\n\tlabel: string;\n}\nfunction renderSegment(value: string, opts: SegmentOptions): string {\n\tconst isBlank = !value || value.replace(/_/g, '') === '';\n\tif (opts.isActive) return styleText('inverse', isBlank ? opts.label : value.replace(/_/g, ' '));\n\tif (isBlank) return styleText('dim', opts.label);\n\treturn value.replace(/_/g, styleText('dim', ' '));\n}\n\nconst DEFAULT_LABELS: Record<'year' | 'month' | 'day', string> = {\n\tyear: 'yyyy',\n\tmonth: 'mm',\n\tday: 'dd',\n};\n"
  },
  {
    "path": "packages/prompts/src/group-multi-select.ts",
    "content": "import { styleText } from 'node:util';\nimport { GroupMultiSelectPrompt } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_ACTIVE,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tsymbol,\n} from './common.js';\nimport type { Option } from './select.js';\n\nexport interface GroupMultiSelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Record<string, Option<Value>[]>;\n\tinitialValues?: Value[];\n\trequired?: boolean;\n\tcursorAt?: Value;\n\tselectableGroups?: boolean;\n\tgroupSpacing?: number;\n}\nexport const groupMultiselect = <Value>(opts: GroupMultiSelectOptions<Value>) => {\n\tconst { selectableGroups = true, groupSpacing = 0 } = opts;\n\tconst opt = (\n\t\toption: Option<Value> & { group: string | boolean },\n\t\tstate:\n\t\t\t| 'inactive'\n\t\t\t| 'active'\n\t\t\t| 'selected'\n\t\t\t| 'active-selected'\n\t\t\t| 'group-active'\n\t\t\t| 'group-active-selected'\n\t\t\t| 'submitted'\n\t\t\t| 'cancelled',\n\t\toptions: (Option<Value> & { group: string | boolean })[] = []\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tconst isItem = typeof option.group === 'string';\n\t\tconst next = isItem && (options[options.indexOf(option) + 1] ?? { group: true });\n\t\tconst isLast = isItem && next && next.group === true;\n\t\tconst prefix = isItem ? (selectableGroups ? `${isLast ? S_BAR_END : S_BAR} ` : '  ') : '';\n\t\tlet spacingPrefix = '';\n\t\tif (groupSpacing > 0 && !isItem) {\n\t\t\tconst spacingPrefixText = `\\n${styleText('cyan', S_BAR)}`;\n\t\t\tspacingPrefix = `${spacingPrefixText.repeat(groupSpacing - 1)}${spacingPrefixText}  `;\n\t\t}\n\n\t\tif (state === 'active') {\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${styleText('cyan', S_CHECKBOX_ACTIVE)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'group-active') {\n\t\t\treturn `${spacingPrefix}${prefix}${styleText('cyan', S_CHECKBOX_ACTIVE)} ${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'group-active-selected') {\n\t\t\treturn `${spacingPrefix}${prefix}${styleText('green', S_CHECKBOX_SELECTED)} ${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'selected') {\n\t\t\tconst selectedCheckbox =\n\t\t\t\tisItem || selectableGroups ? styleText('green', S_CHECKBOX_SELECTED) : '';\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${selectedCheckbox} ${styleText('dim', label)}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${styleText(['strikethrough', 'dim'], label)}`;\n\t\t}\n\t\tif (state === 'active-selected') {\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${styleText('green', S_CHECKBOX_SELECTED)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'submitted') {\n\t\t\treturn `${styleText('dim', label)}`;\n\t\t}\n\t\tconst unselectedCheckbox =\n\t\t\tisItem || selectableGroups ? styleText('dim', S_CHECKBOX_INACTIVE) : '';\n\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${unselectedCheckbox} ${styleText('dim', label)}`;\n\t};\n\tconst required = opts.required ?? true;\n\n\treturn new GroupMultiSelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValues: opts.initialValues,\n\t\trequired,\n\t\tcursorAt: opts.cursorAt,\n\t\tselectableGroups,\n\t\tvalidate(selected: Value[] | undefined) {\n\t\t\tif (required && (selected === undefined || selected.length === 0))\n\t\t\t\treturn `Please select at least one option.\\n${styleText(\n\t\t\t\t\t'reset',\n\t\t\t\t\tstyleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`Press ${styleText(['gray', 'bgWhite', 'inverse'], ' space ')} to select, ${styleText(\n\t\t\t\t\t\t\t'gray',\n\t\t\t\t\t\t\tstyleText(['bgWhite', 'inverse'], ' enter ')\n\t\t\t\t\t\t)} to submit`\n\t\t\t\t\t)\n\t\t\t\t)}`;\n\t\t},\n\t\trender() {\n\t\t\tconst title = `${styleText('gray', S_BAR)}\\n${symbol(this.state)}  ${opts.message}\\n`;\n\t\t\tconst value = this.value ?? [];\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst selectedOptions = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'submitted'));\n\t\t\t\t\tconst optionsText =\n\t\t\t\t\t\tselectedOptions.length === 0 ? '' : `  ${selectedOptions.join(styleText('dim', ', '))}`;\n\t\t\t\t\treturn `${title}${styleText('gray', S_BAR)}${optionsText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst label = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'cancelled'))\n\t\t\t\t\t\t.join(styleText('dim', ', '));\n\t\t\t\t\treturn `${title}${styleText('gray', S_BAR)}  ${\n\t\t\t\t\t\tlabel.trim() ? `${label}\\n${styleText('gray', S_BAR)}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst footer = this.error\n\t\t\t\t\t\t.split('\\n')\n\t\t\t\t\t\t.map((ln, i) =>\n\t\t\t\t\t\t\ti === 0 ? `${styleText('yellow', S_BAR_END)}  ${styleText('yellow', ln)}` : `   ${ln}`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\treturn `${title}${styleText('yellow', S_BAR)}  ${this.options\n\t\t\t\t\t\t.map((option, i, options) => {\n\t\t\t\t\t\t\tconst selected =\n\t\t\t\t\t\t\t\tvalue.includes(option.value) ||\n\t\t\t\t\t\t\t\t(option.group === true && this.isGroupSelected(`${option.value}`));\n\t\t\t\t\t\t\tconst active = i === this.cursor;\n\t\t\t\t\t\t\tconst groupActive =\n\t\t\t\t\t\t\t\t!active &&\n\t\t\t\t\t\t\t\ttypeof option.group === 'string' &&\n\t\t\t\t\t\t\t\tthis.options[this.cursor].value === option.group;\n\t\t\t\t\t\t\tif (groupActive) {\n\t\t\t\t\t\t\t\treturn opt(option, selected ? 'group-active-selected' : 'group-active', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (active && selected) {\n\t\t\t\t\t\t\t\treturn opt(option, 'active-selected', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (selected) {\n\t\t\t\t\t\t\t\treturn opt(option, 'selected', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn opt(option, active ? 'active' : 'inactive', options);\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(`\\n${styleText('yellow', S_BAR)}  `)}\\n${footer}\\n`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst optionsText = this.options\n\t\t\t\t\t\t.map((option, i, options) => {\n\t\t\t\t\t\t\tconst selected =\n\t\t\t\t\t\t\t\tvalue.includes(option.value) ||\n\t\t\t\t\t\t\t\t(option.group === true && this.isGroupSelected(`${option.value}`));\n\t\t\t\t\t\t\tconst active = i === this.cursor;\n\t\t\t\t\t\t\tconst groupActive =\n\t\t\t\t\t\t\t\t!active &&\n\t\t\t\t\t\t\t\ttypeof option.group === 'string' &&\n\t\t\t\t\t\t\t\tthis.options[this.cursor].value === option.group;\n\t\t\t\t\t\t\tlet optionText = '';\n\t\t\t\t\t\t\tif (groupActive) {\n\t\t\t\t\t\t\t\toptionText = opt(\n\t\t\t\t\t\t\t\t\toption,\n\t\t\t\t\t\t\t\t\tselected ? 'group-active-selected' : 'group-active',\n\t\t\t\t\t\t\t\t\toptions\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else if (active && selected) {\n\t\t\t\t\t\t\t\toptionText = opt(option, 'active-selected', options);\n\t\t\t\t\t\t\t} else if (selected) {\n\t\t\t\t\t\t\t\toptionText = opt(option, 'selected', options);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\toptionText = opt(option, active ? 'active' : 'inactive', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst prefix = i !== 0 && !optionText.startsWith('\\n') ? '  ' : '';\n\t\t\t\t\t\t\treturn `${prefix}${optionText}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(`\\n${styleText('cyan', S_BAR)}`);\n\t\t\t\t\tconst optionsPrefix = optionsText.startsWith('\\n') ? '' : '  ';\n\t\t\t\t\treturn `${title}${styleText('cyan', S_BAR)}${optionsPrefix}${optionsText}\\n${styleText('cyan', S_BAR_END)}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value[] | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/src/group.ts",
    "content": "import { isCancel } from '@clack/core';\n\ntype Prettify<T> = {\n\t[P in keyof T]: T[P];\n} & {};\n\nexport type PromptGroupAwaitedReturn<T> = {\n\t[P in keyof T]: Exclude<Awaited<T[P]>, symbol>;\n};\n\nexport interface PromptGroupOptions<T> {\n\t/**\n\t * Control how the group can be canceled\n\t * if one of the prompts is canceled.\n\t */\n\tonCancel?: (opts: { results: Prettify<Partial<PromptGroupAwaitedReturn<T>>> }) => void;\n}\n\nexport type PromptGroup<T> = {\n\t[P in keyof T]: (opts: {\n\t\tresults: Prettify<Partial<PromptGroupAwaitedReturn<Omit<T, P>>>>;\n\t}) => undefined | Promise<T[P] | undefined>;\n};\n\n/**\n * Define a group of prompts to be displayed\n * and return a results of objects within the group\n */\nexport const group = async <T>(\n\tprompts: PromptGroup<T>,\n\topts?: PromptGroupOptions<T>\n): Promise<Prettify<PromptGroupAwaitedReturn<T>>> => {\n\tconst results = {} as any;\n\tconst promptNames = Object.keys(prompts);\n\n\tfor (const name of promptNames) {\n\t\tconst prompt = prompts[name as keyof T];\n\t\tconst result = await prompt({ results })?.catch((e) => {\n\t\t\tthrow e;\n\t\t});\n\n\t\t// Pass the results to the onCancel function\n\t\t// so the user can decide what to do with the results\n\t\t// TODO: Switch to callback within core to avoid isCancel Fn\n\t\tif (typeof opts?.onCancel === 'function' && isCancel(result)) {\n\t\t\tresults[name] = 'canceled';\n\t\t\topts.onCancel({ results });\n\t\t\tcontinue;\n\t\t}\n\n\t\tresults[name] = result;\n\t}\n\n\treturn results;\n};\n"
  },
  {
    "path": "packages/prompts/src/index.ts",
    "content": "export { type ClackSettings, isCancel, settings, updateSettings } from '@clack/core';\n\nexport * from './autocomplete.js';\nexport * from './box.js';\nexport * from './common.js';\nexport * from './confirm.js';\nexport * from './date.js';\nexport * from './group.js';\nexport * from './group-multi-select.js';\nexport * from './limit-options.js';\nexport * from './log.js';\nexport * from './messages.js';\nexport * from './multi-select.js';\nexport * from './note.js';\nexport * from './password.js';\nexport * from './path.js';\nexport * from './progress-bar.js';\nexport * from './select.js';\nexport * from './select-key.js';\nexport * from './spinner.js';\nexport * from './stream.js';\nexport * from './task.js';\nexport * from './task-log.js';\nexport * from './text.js';\n"
  },
  {
    "path": "packages/prompts/src/limit-options.ts",
    "content": "import { styleText } from 'node:util';\nimport { getColumns, getRows } from '@clack/core';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport type { CommonOptions } from './common.js';\n\nexport interface LimitOptionsParams<TOption> extends CommonOptions {\n\toptions: TOption[];\n\tcursor: number;\n\tstyle: (option: TOption, active: boolean) => string;\n\tmaxItems?: number;\n\tcolumnPadding?: number;\n\trowPadding?: number;\n}\n\nconst trimLines = (\n\tgroups: Array<string[]>,\n\tinitialLineCount: number,\n\tstartIndex: number,\n\tendIndex: number,\n\tmaxLines: number\n) => {\n\tlet lineCount = initialLineCount;\n\tlet removals = 0;\n\tfor (let i = startIndex; i < endIndex; i++) {\n\t\tconst group = groups[i];\n\t\tlineCount = lineCount - group.length;\n\t\tremovals++;\n\t\tif (lineCount <= maxLines) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn { lineCount, removals };\n};\n\nexport const limitOptions = <TOption>({\n\tcursor,\n\toptions,\n\tstyle,\n\toutput = process.stdout,\n\tmaxItems = Number.POSITIVE_INFINITY,\n\tcolumnPadding = 0,\n\trowPadding = 4,\n}: LimitOptionsParams<TOption>): string[] => {\n\tconst columns = getColumns(output);\n\tconst maxWidth = columns - columnPadding;\n\tconst rows = getRows(output);\n\tconst overflowFormat = styleText('dim', '...');\n\n\tconst outputMaxItems = Math.max(rows - rowPadding, 0);\n\t// We clamp to minimum 5 because anything less doesn't make sense UX wise\n\tconst computedMaxItems = Math.max(Math.min(maxItems, outputMaxItems), 5);\n\tlet slidingWindowLocation = 0;\n\n\tif (cursor >= computedMaxItems - 3) {\n\t\tslidingWindowLocation = Math.max(\n\t\t\tMath.min(cursor - computedMaxItems + 3, options.length - computedMaxItems),\n\t\t\t0\n\t\t);\n\t}\n\n\tlet shouldRenderTopEllipsis = computedMaxItems < options.length && slidingWindowLocation > 0;\n\tlet shouldRenderBottomEllipsis =\n\t\tcomputedMaxItems < options.length && slidingWindowLocation + computedMaxItems < options.length;\n\n\tconst slidingWindowLocationEnd = Math.min(\n\t\tslidingWindowLocation + computedMaxItems,\n\t\toptions.length\n\t);\n\tconst lineGroups: Array<string[]> = [];\n\tlet lineCount = 0;\n\tif (shouldRenderTopEllipsis) {\n\t\tlineCount++;\n\t}\n\tif (shouldRenderBottomEllipsis) {\n\t\tlineCount++;\n\t}\n\n\tconst slidingWindowLocationWithEllipsis =\n\t\tslidingWindowLocation + (shouldRenderTopEllipsis ? 1 : 0);\n\tconst slidingWindowLocationEndWithEllipsis =\n\t\tslidingWindowLocationEnd - (shouldRenderBottomEllipsis ? 1 : 0);\n\n\tfor (let i = slidingWindowLocationWithEllipsis; i < slidingWindowLocationEndWithEllipsis; i++) {\n\t\tconst wrappedLines = wrapAnsi(style(options[i], i === cursor), maxWidth, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t}).split('\\n');\n\t\tlineGroups.push(wrappedLines);\n\t\tlineCount += wrappedLines.length;\n\t}\n\n\tif (lineCount > outputMaxItems) {\n\t\tlet precedingRemovals = 0;\n\t\tlet followingRemovals = 0;\n\t\tlet newLineCount = lineCount;\n\t\tconst cursorGroupIndex = cursor - slidingWindowLocationWithEllipsis;\n\t\tconst trimLinesLocal = (startIndex: number, endIndex: number) =>\n\t\t\ttrimLines(lineGroups, newLineCount, startIndex, endIndex, outputMaxItems);\n\n\t\tif (shouldRenderTopEllipsis) {\n\t\t\t({ lineCount: newLineCount, removals: precedingRemovals } = trimLinesLocal(\n\t\t\t\t0,\n\t\t\t\tcursorGroupIndex\n\t\t\t));\n\t\t\tif (newLineCount > outputMaxItems) {\n\t\t\t\t({ lineCount: newLineCount, removals: followingRemovals } = trimLinesLocal(\n\t\t\t\t\tcursorGroupIndex + 1,\n\t\t\t\t\tlineGroups.length\n\t\t\t\t));\n\t\t\t}\n\t\t} else {\n\t\t\t({ lineCount: newLineCount, removals: followingRemovals } = trimLinesLocal(\n\t\t\t\tcursorGroupIndex + 1,\n\t\t\t\tlineGroups.length\n\t\t\t));\n\t\t\tif (newLineCount > outputMaxItems) {\n\t\t\t\t({ lineCount: newLineCount, removals: precedingRemovals } = trimLinesLocal(\n\t\t\t\t\t0,\n\t\t\t\t\tcursorGroupIndex\n\t\t\t\t));\n\t\t\t}\n\t\t}\n\n\t\tif (precedingRemovals > 0) {\n\t\t\tshouldRenderTopEllipsis = true;\n\t\t\tlineGroups.splice(0, precedingRemovals);\n\t\t}\n\t\tif (followingRemovals > 0) {\n\t\t\tshouldRenderBottomEllipsis = true;\n\t\t\tlineGroups.splice(lineGroups.length - followingRemovals, followingRemovals);\n\t\t}\n\t}\n\n\tconst result: string[] = [];\n\tif (shouldRenderTopEllipsis) {\n\t\tresult.push(overflowFormat);\n\t}\n\tfor (const lineGroup of lineGroups) {\n\t\tfor (const line of lineGroup) {\n\t\t\tresult.push(line);\n\t\t}\n\t}\n\tif (shouldRenderBottomEllipsis) {\n\t\tresult.push(overflowFormat);\n\t}\n\n\treturn result;\n};\n"
  },
  {
    "path": "packages/prompts/src/log.ts",
    "content": "import { styleText } from 'node:util';\nimport { settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_ERROR,\n\tS_INFO,\n\tS_STEP_SUBMIT,\n\tS_SUCCESS,\n\tS_WARN,\n} from './common.js';\n\nexport interface LogMessageOptions extends CommonOptions {\n\tsymbol?: string;\n\tspacing?: number;\n\tsecondarySymbol?: string;\n}\n\nexport const log = {\n\tmessage: (\n\t\tmessage: string | string[] = [],\n\t\t{\n\t\t\tsymbol = styleText('gray', S_BAR),\n\t\t\tsecondarySymbol = styleText('gray', S_BAR),\n\t\t\toutput = process.stdout,\n\t\t\tspacing = 1,\n\t\t\twithGuide,\n\t\t}: LogMessageOptions = {}\n\t) => {\n\t\tconst parts: string[] = [];\n\t\tconst hasGuide = withGuide ?? settings.withGuide;\n\t\tconst spacingString = !hasGuide ? '' : secondarySymbol;\n\t\tconst prefix = !hasGuide ? '' : `${symbol}  `;\n\t\tconst secondaryPrefix = !hasGuide ? '' : `${secondarySymbol}  `;\n\n\t\tfor (let i = 0; i < spacing; i++) {\n\t\t\tparts.push(spacingString);\n\t\t}\n\n\t\tconst messageParts = Array.isArray(message) ? message : message.split('\\n');\n\t\tif (messageParts.length > 0) {\n\t\t\tconst [firstLine, ...lines] = messageParts;\n\t\t\tif (firstLine.length > 0) {\n\t\t\t\tparts.push(`${prefix}${firstLine}`);\n\t\t\t} else {\n\t\t\t\tparts.push(hasGuide ? symbol : '');\n\t\t\t}\n\t\t\tfor (const ln of lines) {\n\t\t\t\tif (ln.length > 0) {\n\t\t\t\t\tparts.push(`${secondaryPrefix}${ln}`);\n\t\t\t\t} else {\n\t\t\t\t\tparts.push(hasGuide ? secondarySymbol : '');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\toutput.write(`${parts.join('\\n')}\\n`);\n\t},\n\tinfo: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('blue', S_INFO) });\n\t},\n\tsuccess: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('green', S_SUCCESS) });\n\t},\n\tstep: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('green', S_STEP_SUBMIT) });\n\t},\n\twarn: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('yellow', S_WARN) });\n\t},\n\t/** alias for `log.warn()`. */\n\twarning: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.warn(message, opts);\n\t},\n\terror: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('red', S_ERROR) });\n\t},\n};\n"
  },
  {
    "path": "packages/prompts/src/messages.ts",
    "content": "import type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, S_BAR_START } from './common.js';\n\nexport const cancel = (message = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR_END)}  ` : '';\n\toutput.write(`${prefix}${styleText('red', message)}\\n\\n`);\n};\n\nexport const intro = (title = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR_START)}  ` : '';\n\toutput.write(`${prefix}${title}\\n`);\n};\n\nexport const outro = (message = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR)}\\n${styleText('gray', S_BAR_END)}  ` : '';\n\toutput.write(`${prefix}${message}\\n\\n`);\n};\n"
  },
  {
    "path": "packages/prompts/src/multi-select.ts",
    "content": "import { styleText } from 'node:util';\nimport { MultiSelectPrompt, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_ACTIVE,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tsymbol,\n\tsymbolBar,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\nimport type { Option } from './select.js';\n\nexport interface MultiSelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValues?: Value[];\n\tmaxItems?: number;\n\trequired?: boolean;\n\tcursorAt?: Value;\n}\nconst computeLabel = (label: string, format: (text: string) => string) => {\n\treturn label\n\t\t.split('\\n')\n\t\t.map((line) => format(line))\n\t\t.join('\\n');\n};\n\nexport const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate:\n\t\t\t| 'inactive'\n\t\t\t| 'active'\n\t\t\t| 'selected'\n\t\t\t| 'active-selected'\n\t\t\t| 'submitted'\n\t\t\t| 'cancelled'\n\t\t\t| 'disabled'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tif (state === 'disabled') {\n\t\t\treturn `${styleText('gray', S_CHECKBOX_INACTIVE)} ${computeLabel(label, (str) => styleText(['strikethrough', 'gray'], str))}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint ?? 'disabled'})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'active') {\n\t\t\treturn `${styleText('cyan', S_CHECKBOX_ACTIVE)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'selected') {\n\t\t\treturn `${styleText('green', S_CHECKBOX_SELECTED)} ${computeLabel(label, (text) => styleText('dim', text))}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${computeLabel(label, (text) => styleText(['strikethrough', 'dim'], text))}`;\n\t\t}\n\t\tif (state === 'active-selected') {\n\t\t\treturn `${styleText('green', S_CHECKBOX_SELECTED)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'submitted') {\n\t\t\treturn `${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t}\n\t\treturn `${styleText('dim', S_CHECKBOX_INACTIVE)} ${computeLabel(label, (text) => styleText('dim', text))}`;\n\t};\n\tconst required = opts.required ?? true;\n\n\treturn new MultiSelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValues: opts.initialValues,\n\t\trequired,\n\t\tcursorAt: opts.cursorAt,\n\t\tvalidate(selected: Value[] | undefined) {\n\t\t\tif (required && (selected === undefined || selected.length === 0))\n\t\t\t\treturn `Please select at least one option.\\n${styleText(\n\t\t\t\t\t'reset',\n\t\t\t\t\tstyleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`Press ${styleText(['gray', 'bgWhite', 'inverse'], ' space ')} to select, ${styleText(\n\t\t\t\t\t\t\t'gray',\n\t\t\t\t\t\t\tstyleText('bgWhite', styleText('inverse', ' enter '))\n\t\t\t\t\t\t)} to submit`\n\t\t\t\t\t)\n\t\t\t\t)}`;\n\t\t},\n\t\trender() {\n\t\t\tconst wrappedMessage = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\t`${symbolBar(this.state)}  `,\n\t\t\t\t`${symbol(this.state)}  `\n\t\t\t);\n\t\t\tconst title = `${styleText('gray', S_BAR)}\\n${wrappedMessage}\\n`;\n\t\t\tconst value = this.value ?? [];\n\n\t\t\tconst styleOption = (option: Option<Value>, active: boolean) => {\n\t\t\t\tif (option.disabled) {\n\t\t\t\t\treturn opt(option, 'disabled');\n\t\t\t\t}\n\t\t\t\tconst selected = value.includes(option.value);\n\t\t\t\tif (active && selected) {\n\t\t\t\t\treturn opt(option, 'active-selected');\n\t\t\t\t}\n\t\t\t\tif (selected) {\n\t\t\t\t\treturn opt(option, 'selected');\n\t\t\t\t}\n\t\t\t\treturn opt(option, active ? 'active' : 'inactive');\n\t\t\t};\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitText =\n\t\t\t\t\t\tthis.options\n\t\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t\t.map((option) => opt(option, 'submitted'))\n\t\t\t\t\t\t\t.join(styleText('dim', ', ')) || styleText('dim', 'none');\n\t\t\t\t\tconst wrappedSubmitText = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\tsubmitText,\n\t\t\t\t\t\t`${styleText('gray', S_BAR)}  `\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedSubmitText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst label = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'cancelled'))\n\t\t\t\t\t\t.join(styleText('dim', ', '));\n\t\t\t\t\tif (label.trim() === '') {\n\t\t\t\t\t\treturn `${title}${styleText('gray', S_BAR)}`;\n\t\t\t\t\t}\n\t\t\t\t\tconst wrappedLabel = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\t`${styleText('gray', S_BAR)}  `\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLabel}\\n${styleText('gray', S_BAR)}`;\n\t\t\t\t}\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst prefix = `${styleText('yellow', S_BAR)}  `;\n\t\t\t\t\tconst footer = this.error\n\t\t\t\t\t\t.split('\\n')\n\t\t\t\t\t\t.map((ln, i) =>\n\t\t\t\t\t\t\ti === 0 ? `${styleText('yellow', S_BAR_END)}  ${styleText('yellow', ln)}` : `   ${ln}`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (error message + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = footer.split('\\n').length + 1; // footer + trailing newline\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: styleOption,\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${footer}\\n`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst prefix = `${styleText('cyan', S_BAR)}  `;\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (S_BAR_END + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = 2; // S_BAR_END + trailing newline\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: styleOption,\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${styleText('cyan', S_BAR_END)}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value[] | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/src/note.ts",
    "content": "import process from 'node:process';\nimport type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { getColumns, settings } from '@clack/core';\nimport stringWidth from 'fast-string-width';\nimport { type Options as WrapAnsiOptions, wrapAnsi } from 'fast-wrap-ansi';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_H,\n\tS_CONNECT_LEFT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n\tS_CORNER_TOP_RIGHT,\n\tS_STEP_SUBMIT,\n} from './common.js';\n\ntype FormatFn = (line: string) => string;\nexport interface NoteOptions extends CommonOptions {\n\tformat?: FormatFn;\n}\n\nconst defaultNoteFormatter = (line: string): string => styleText('dim', line);\n\nconst wrapWithFormat = (message: string, width: number, format: FormatFn): string => {\n\tconst opts: WrapAnsiOptions = {\n\t\thard: true,\n\t\ttrim: false,\n\t};\n\tconst wrapMsg = wrapAnsi(message, width, opts).split('\\n');\n\tconst maxWidthNormal = wrapMsg.reduce((sum, ln) => Math.max(stringWidth(ln), sum), 0);\n\tconst maxWidthFormat = wrapMsg.map(format).reduce((sum, ln) => Math.max(stringWidth(ln), sum), 0);\n\tconst wrapWidth = width - (maxWidthFormat - maxWidthNormal);\n\treturn wrapAnsi(message, wrapWidth, opts);\n};\n\nexport const note = (message = '', title = '', opts?: NoteOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst format = opts?.format ?? defaultNoteFormatter;\n\tconst wrapMsg = wrapWithFormat(message, getColumns(output) - 6, format);\n\tconst lines = ['', ...wrapMsg.split('\\n').map(format), ''];\n\tconst titleLen = stringWidth(title);\n\tconst len =\n\t\tMath.max(\n\t\t\tlines.reduce((sum, ln) => {\n\t\t\t\tconst width = stringWidth(ln);\n\t\t\t\treturn width > sum ? width : sum;\n\t\t\t}, 0),\n\t\t\ttitleLen\n\t\t) + 2;\n\tconst msg = lines\n\t\t.map(\n\t\t\t(ln) =>\n\t\t\t\t`${styleText('gray', S_BAR)}  ${ln}${' '.repeat(len - stringWidth(ln))}${styleText('gray', S_BAR)}`\n\t\t)\n\t\t.join('\\n');\n\tconst leadingBorder = hasGuide ? `${styleText('gray', S_BAR)}\\n` : '';\n\tconst bottomLeft = hasGuide ? S_CONNECT_LEFT : S_CORNER_BOTTOM_LEFT;\n\toutput.write(\n\t\t`${leadingBorder}${styleText('green', S_STEP_SUBMIT)}  ${styleText('reset', title)} ${styleText(\n\t\t\t'gray',\n\t\t\tS_BAR_H.repeat(Math.max(len - titleLen - 1, 1)) + S_CORNER_TOP_RIGHT\n\t\t)}\\n${msg}\\n${styleText('gray', bottomLeft + S_BAR_H.repeat(len + 2) + S_CORNER_BOTTOM_RIGHT)}\\n`\n\t);\n};\n"
  },
  {
    "path": "packages/prompts/src/password.ts",
    "content": "import { styleText } from 'node:util';\nimport { PasswordPrompt, settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, S_PASSWORD_MASK, symbol } from './common.js';\n\nexport interface PasswordOptions extends CommonOptions {\n\tmessage: string;\n\tmask?: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n\tclearOnError?: boolean;\n}\nexport const password = (opts: PasswordOptions) => {\n\treturn new PasswordPrompt({\n\t\tvalidate: opts.validate,\n\t\tmask: opts.mask ?? S_PASSWORD_MASK,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)}  ${opts.message}\\n`;\n\t\t\tconst userInput = this.userInputWithCursor;\n\t\t\tconst masked = this.masked;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorPrefix = hasGuide ? `${styleText('yellow', S_BAR)}  ` : '';\n\t\t\t\t\tconst errorPrefixEnd = hasGuide ? `${styleText('yellow', S_BAR_END)}  ` : '';\n\t\t\t\t\tconst maskedText = masked ?? '';\n\t\t\t\t\tif (opts.clearOnError) {\n\t\t\t\t\t\tthis.clear();\n\t\t\t\t\t}\n\t\t\t\t\treturn `${title.trim()}\\n${errorPrefix}${maskedText}\\n${errorPrefixEnd}${styleText('yellow', this.error)}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\tconst maskedText = masked ? styleText('dim', masked) : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${maskedText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\tconst maskedText = masked ? styleText(['strikethrough', 'dim'], masked) : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${maskedText}${\n\t\t\t\t\t\tmasked && hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)}  ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${userInput}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/src/path.ts",
    "content": "import { existsSync, lstatSync, readdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { autocomplete } from './autocomplete.js';\nimport type { CommonOptions } from './common.js';\n\nexport interface PathOptions extends CommonOptions {\n\troot?: string;\n\tdirectory?: boolean;\n\tinitialValue?: string;\n\tmessage: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n}\n\nexport const path = (opts: PathOptions) => {\n\tconst validate = opts.validate;\n\n\treturn autocomplete({\n\t\t...opts,\n\t\tinitialUserInput: opts.initialValue ?? opts.root ?? process.cwd(),\n\t\tmaxItems: 5,\n\t\tvalidate(value) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\t// Shouldn't ever happen since we don't enable `multiple: true`\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (!value) {\n\t\t\t\treturn 'Please select a path';\n\t\t\t}\n\t\t\tif (validate) {\n\t\t\t\treturn validate(value);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t\toptions() {\n\t\t\tconst userInput = this.userInput;\n\t\t\tif (userInput === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tlet searchPath: string;\n\n\t\t\t\tif (!existsSync(userInput)) {\n\t\t\t\t\tsearchPath = dirname(userInput);\n\t\t\t\t} else {\n\t\t\t\t\tconst stat = lstatSync(userInput);\n\t\t\t\t\tif (stat.isDirectory() && (!opts.directory || userInput.endsWith('/'))) {\n\t\t\t\t\t\tsearchPath = userInput;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsearchPath = dirname(userInput);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Strip trailing slash so startsWith matches the directory itself among its siblings\n\t\t\t\tconst prefix =\n\t\t\t\t\tuserInput.length > 1 && userInput.endsWith('/') ? userInput.slice(0, -1) : userInput;\n\n\t\t\t\tconst items = readdirSync(searchPath)\n\t\t\t\t\t.map((item) => {\n\t\t\t\t\t\tconst path = join(searchPath, item);\n\t\t\t\t\t\tconst stats = lstatSync(path);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: item,\n\t\t\t\t\t\t\tpath,\n\t\t\t\t\t\t\tisDirectory: stats.isDirectory(),\n\t\t\t\t\t\t};\n\t\t\t\t\t})\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t({ path, isDirectory }) => path.startsWith(prefix) && (isDirectory || !opts.directory)\n\t\t\t\t\t);\n\n\t\t\t\treturn items.map((item) => ({\n\t\t\t\t\tvalue: item.path,\n\t\t\t\t}));\n\t\t\t} catch (_e) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t},\n\t});\n};\n"
  },
  {
    "path": "packages/prompts/src/progress-bar.ts",
    "content": "import { styleText } from 'node:util';\nimport type { State } from '@clack/core';\nimport { unicodeOr } from './common.js';\nimport { type SpinnerOptions, type SpinnerResult, spinner } from './spinner.js';\n\nconst S_PROGRESS_CHAR: Record<NonNullable<ProgressOptions['style']>, string> = {\n\tlight: unicodeOr('─', '-'),\n\theavy: unicodeOr('━', '='),\n\tblock: unicodeOr('█', '#'),\n};\n\nexport interface ProgressOptions extends SpinnerOptions {\n\tstyle?: 'light' | 'heavy' | 'block';\n\tmax?: number;\n\tsize?: number;\n}\n\nexport interface ProgressResult extends SpinnerResult {\n\tadvance(step?: number, msg?: string): void;\n}\n\nexport function progress({\n\tstyle = 'heavy',\n\tmax: userMax = 100,\n\tsize: userSize = 40,\n\t...spinnerOptions\n}: ProgressOptions = {}): ProgressResult {\n\tconst spin = spinner(spinnerOptions);\n\tlet value = 0;\n\tlet previousMessage = '';\n\n\tconst max = Math.max(1, userMax);\n\tconst size = Math.max(1, userSize);\n\n\tconst activeStyle = (state: State) => {\n\t\tswitch (state) {\n\t\t\tcase 'initial':\n\t\t\tcase 'active':\n\t\t\t\treturn (text: string) => styleText('magenta', text);\n\t\t\tcase 'error':\n\t\t\tcase 'cancel':\n\t\t\t\treturn (text: string) => styleText('red', text);\n\t\t\tcase 'submit':\n\t\t\t\treturn (text: string) => styleText('green', text);\n\t\t\tdefault:\n\t\t\t\treturn (text: string) => styleText('magenta', text);\n\t\t}\n\t};\n\tconst drawProgress = (state: State, msg: string) => {\n\t\tconst active = Math.floor((value / max) * size);\n\t\treturn `${activeStyle(state)(S_PROGRESS_CHAR[style].repeat(active))}${styleText('dim', S_PROGRESS_CHAR[style].repeat(size - active))} ${msg}`;\n\t};\n\n\tconst start = (msg = '') => {\n\t\tpreviousMessage = msg;\n\t\tspin.start(drawProgress('initial', msg));\n\t};\n\tconst advance = (step = 1, msg?: string): void => {\n\t\tvalue = Math.min(max, step + value);\n\t\tspin.message(drawProgress('active', msg ?? previousMessage));\n\t\tpreviousMessage = msg ?? previousMessage;\n\t};\n\treturn {\n\t\tstart,\n\t\tstop: spin.stop,\n\t\tcancel: spin.cancel,\n\t\terror: spin.error,\n\t\tclear: spin.clear,\n\t\tadvance,\n\t\tisCancelled: spin.isCancelled,\n\t\tmessage: (msg: string) => advance(0, msg),\n\t};\n}\n"
  },
  {
    "path": "packages/prompts/src/select-key.ts",
    "content": "import { styleText } from 'node:util';\nimport { SelectKeyPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\nimport type { Option } from './select.js';\n\nexport interface SelectKeyOptions<Value extends string> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValue?: Value;\n\tcaseSensitive?: boolean;\n}\n\nexport const selectKey = <Value extends string>(opts: SelectKeyOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate: 'inactive' | 'active' | 'selected' | 'cancelled' = 'inactive'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tif (state === 'selected') {\n\t\t\treturn `${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${styleText(['strikethrough', 'dim'], label)}`;\n\t\t}\n\t\tif (state === 'active') {\n\t\t\treturn `${styleText(['bgCyan', 'gray'], ` ${option.value} `)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\treturn `${styleText(['gray', 'bgWhite', 'inverse'], ` ${option.value} `)} ${label}${\n\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t}`;\n\t};\n\n\treturn new SelectKeyPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue,\n\t\tcaseSensitive: opts.caseSensitive,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)}  ${opts.message}\\n`;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\tconst selectedOption =\n\t\t\t\t\t\tthis.options.find((opt) => opt.value === this.value) ?? opts.options[0];\n\t\t\t\t\tconst wrapped = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(selectedOption, 'selected'),\n\t\t\t\t\t\tsubmitPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrapped}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\tconst wrapped = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[0], 'cancelled'),\n\t\t\t\t\t\tcancelPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrapped}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)}  ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst wrapped = this.options\n\t\t\t\t\t\t.map((option, i) =>\n\t\t\t\t\t\t\twrapTextWithPrefix(\n\t\t\t\t\t\t\t\topts.output,\n\t\t\t\t\t\t\t\topt(option, i === this.cursor ? 'active' : 'inactive'),\n\t\t\t\t\t\t\t\tdefaultPrefix\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\treturn `${title}${wrapped}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/src/select.ts",
    "content": "import { styleText } from 'node:util';\nimport { SelectPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n\tsymbolBar,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\n\ntype Primitive = Readonly<string | boolean | number>;\n\nexport type Option<Value> = Value extends Primitive\n\t? {\n\t\t\t/**\n\t\t\t * Internal data for this option.\n\t\t\t */\n\t\t\tvalue: Value;\n\t\t\t/**\n\t\t\t * The optional, user-facing text for this option.\n\t\t\t *\n\t\t\t * By default, the `value` is converted to a string.\n\t\t\t */\n\t\t\tlabel?: string;\n\t\t\t/**\n\t\t\t * An optional hint to display to the user when\n\t\t\t * this option might be selected.\n\t\t\t *\n\t\t\t * By default, no `hint` is displayed.\n\t\t\t */\n\t\t\thint?: string;\n\t\t\t/**\n\t\t\t * Whether this option is disabled.\n\t\t\t * Disabled options are visible but cannot be selected.\n\t\t\t *\n\t\t\t * By default, options are not disabled.\n\t\t\t */\n\t\t\tdisabled?: boolean;\n\t\t}\n\t: {\n\t\t\t/**\n\t\t\t * Internal data for this option.\n\t\t\t */\n\t\t\tvalue: Value;\n\t\t\t/**\n\t\t\t * Required. The user-facing text for this option.\n\t\t\t */\n\t\t\tlabel: string;\n\t\t\t/**\n\t\t\t * An optional hint to display to the user when\n\t\t\t * this option might be selected.\n\t\t\t *\n\t\t\t * By default, no `hint` is displayed.\n\t\t\t */\n\t\t\thint?: string;\n\t\t\t/**\n\t\t\t * Whether this option is disabled.\n\t\t\t * Disabled options are visible but cannot be selected.\n\t\t\t *\n\t\t\t * By default, options are not disabled.\n\t\t\t */\n\t\t\tdisabled?: boolean;\n\t\t};\n\nexport interface SelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValue?: Value;\n\tmaxItems?: number;\n}\n\nconst computeLabel = (label: string, format: (text: string) => string) => {\n\tif (!label.includes('\\n')) {\n\t\treturn format(label);\n\t}\n\treturn label\n\t\t.split('\\n')\n\t\t.map((line) => format(line))\n\t\t.join('\\n');\n};\n\nexport const select = <Value>(opts: SelectOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate: 'inactive' | 'active' | 'selected' | 'cancelled' | 'disabled'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tswitch (state) {\n\t\t\tcase 'disabled':\n\t\t\t\treturn `${styleText('gray', S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText('gray', text))}${\n\t\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint ?? 'disabled'})`)}` : ''\n\t\t\t\t}`;\n\t\t\tcase 'selected':\n\t\t\t\treturn `${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t\tcase 'active':\n\t\t\t\treturn `${styleText('green', S_RADIO_ACTIVE)} ${label}${\n\t\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t\t}`;\n\t\t\tcase 'cancelled':\n\t\t\t\treturn `${computeLabel(label, (str) => styleText(['strikethrough', 'dim'], str))}`;\n\t\t\tdefault:\n\t\t\t\treturn `${styleText('dim', S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t}\n\t};\n\n\treturn new SelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${symbol(this.state)}  `;\n\t\t\tconst titlePrefixBar = `${symbolBar(this.state)}  `;\n\t\t\tconst messageLines = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\ttitlePrefixBar,\n\t\t\t\ttitlePrefix\n\t\t\t);\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${messageLines}\\n`;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\tconst wrappedLines = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[this.cursor], 'selected'),\n\t\t\t\t\t\tsubmitPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLines}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)}  ` : '';\n\t\t\t\t\tconst wrappedLines = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[this.cursor], 'cancelled'),\n\t\t\t\t\t\tcancelPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLines}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst prefix = hasGuide ? `${styleText('cyan', S_BAR)}  ` : '';\n\t\t\t\t\tconst prefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (S_BAR_END + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = hasGuide ? 2 : 1; // S_BAR_END + trailing newline (or just trailing newline)\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: (item, active) =>\n\t\t\t\t\t\t\topt(item, item.disabled ? 'disabled' : active ? 'active' : 'inactive'),\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${prefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/src/spinner.ts",
    "content": "import { styleText } from 'node:util';\nimport { block, getColumns, settings } from '@clack/core';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor, erase } from 'sisteransi';\nimport {\n\ttype CommonOptions,\n\tisCI as isCIFn,\n\tS_BAR,\n\tS_STEP_CANCEL,\n\tS_STEP_ERROR,\n\tS_STEP_SUBMIT,\n\tunicode,\n} from './common.js';\n\nexport interface SpinnerOptions extends CommonOptions {\n\tindicator?: 'dots' | 'timer';\n\tonCancel?: () => void;\n\tcancelMessage?: string;\n\terrorMessage?: string;\n\tframes?: string[];\n\tdelay?: number;\n\tstyleFrame?: (frame: string) => string;\n}\n\nexport interface SpinnerResult {\n\tstart(msg?: string): void;\n\tstop(msg?: string): void;\n\tcancel(msg?: string): void;\n\terror(msg?: string): void;\n\tmessage(msg?: string): void;\n\tclear(): void;\n\treadonly isCancelled: boolean;\n}\n\nconst defaultStyleFn: SpinnerOptions['styleFrame'] = (frame) => styleText('magenta', frame);\n\nexport const spinner = ({\n\tindicator = 'dots',\n\tonCancel,\n\toutput = process.stdout,\n\tcancelMessage,\n\terrorMessage,\n\tframes = unicode ? ['◒', '◐', '◓', '◑'] : ['•', 'o', 'O', '0'],\n\tdelay = unicode ? 80 : 120,\n\tsignal,\n\t...opts\n}: SpinnerOptions = {}): SpinnerResult => {\n\tconst isCI = isCIFn();\n\n\tlet unblock: () => void;\n\tlet loop: NodeJS.Timeout;\n\tlet isSpinnerActive = false;\n\tlet isCancelled = false;\n\tlet _message = '';\n\tlet _prevMessage: string | undefined;\n\tlet _origin: number = performance.now();\n\tconst columns = getColumns(output);\n\tconst styleFn = opts?.styleFrame ?? defaultStyleFn;\n\n\tconst handleExit = (code: number) => {\n\t\tconst msg =\n\t\t\tcode > 1\n\t\t\t\t? (errorMessage ?? settings.messages.error)\n\t\t\t\t: (cancelMessage ?? settings.messages.cancel);\n\t\tisCancelled = code === 1;\n\t\tif (isSpinnerActive) {\n\t\t\t_stop(msg, code);\n\t\t\tif (isCancelled && typeof onCancel === 'function') {\n\t\t\t\tonCancel();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst errorEventHandler = () => handleExit(2);\n\tconst signalEventHandler = () => handleExit(1);\n\n\tconst registerHooks = () => {\n\t\t// Reference: https://nodejs.org/api/process.html#event-uncaughtexception\n\t\tprocess.on('uncaughtExceptionMonitor', errorEventHandler);\n\t\t// Reference: https://nodejs.org/api/process.html#event-unhandledrejection\n\t\tprocess.on('unhandledRejection', errorEventHandler);\n\t\t// Reference Signal Events: https://nodejs.org/api/process.html#signal-events\n\t\tprocess.on('SIGINT', signalEventHandler);\n\t\tprocess.on('SIGTERM', signalEventHandler);\n\t\tprocess.on('exit', handleExit);\n\n\t\tif (signal) {\n\t\t\tsignal.addEventListener('abort', signalEventHandler);\n\t\t}\n\t};\n\n\tconst clearHooks = () => {\n\t\tprocess.removeListener('uncaughtExceptionMonitor', errorEventHandler);\n\t\tprocess.removeListener('unhandledRejection', errorEventHandler);\n\t\tprocess.removeListener('SIGINT', signalEventHandler);\n\t\tprocess.removeListener('SIGTERM', signalEventHandler);\n\t\tprocess.removeListener('exit', handleExit);\n\n\t\tif (signal) {\n\t\t\tsignal.removeEventListener('abort', signalEventHandler);\n\t\t}\n\t};\n\n\tconst clearPrevMessage = () => {\n\t\tif (_prevMessage === undefined) return;\n\t\tif (isCI) output.write('\\n');\n\t\tconst wrapped = wrapAnsi(_prevMessage, columns, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t});\n\t\tconst prevLines = wrapped.split('\\n');\n\t\tif (prevLines.length > 1) {\n\t\t\toutput.write(cursor.up(prevLines.length - 1));\n\t\t}\n\t\toutput.write(cursor.to(0));\n\t\toutput.write(erase.down());\n\t};\n\n\tconst removeTrailingDots = (msg: string): string => {\n\t\treturn msg.replace(/\\.+$/, '');\n\t};\n\n\tconst formatTimer = (origin: number): string => {\n\t\tconst duration = (performance.now() - origin) / 1000;\n\t\tconst min = Math.floor(duration / 60);\n\t\tconst secs = Math.floor(duration % 60);\n\t\treturn min > 0 ? `[${min}m ${secs}s]` : `[${secs}s]`;\n\t};\n\n\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\n\tconst start = (msg = ''): void => {\n\t\tisSpinnerActive = true;\n\t\tunblock = block({ output });\n\t\t_message = removeTrailingDots(msg);\n\t\t_origin = performance.now();\n\t\tif (hasGuide) {\n\t\t\toutput.write(`${styleText('gray', S_BAR)}\\n`);\n\t\t}\n\t\tlet frameIndex = 0;\n\t\tlet indicatorTimer = 0;\n\t\tregisterHooks();\n\t\tloop = setInterval(() => {\n\t\t\tif (isCI && _message === _prevMessage) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclearPrevMessage();\n\t\t\t_prevMessage = _message;\n\t\t\tconst frame = styleFn(frames[frameIndex]);\n\t\t\tlet outputMessage: string;\n\n\t\t\tif (isCI) {\n\t\t\t\toutputMessage = `${frame}  ${_message}...`;\n\t\t\t} else if (indicator === 'timer') {\n\t\t\t\toutputMessage = `${frame}  ${_message} ${formatTimer(_origin)}`;\n\t\t\t} else {\n\t\t\t\tconst loadingDots = '.'.repeat(Math.floor(indicatorTimer)).slice(0, 3);\n\t\t\t\toutputMessage = `${frame}  ${_message}${loadingDots}`;\n\t\t\t}\n\n\t\t\tconst wrapped = wrapAnsi(outputMessage, columns, {\n\t\t\t\thard: true,\n\t\t\t\ttrim: false,\n\t\t\t});\n\t\t\toutput.write(wrapped);\n\n\t\t\tframeIndex = frameIndex + 1 < frames.length ? frameIndex + 1 : 0;\n\t\t\t// indicator increase by 1 every 8 frames\n\t\t\tindicatorTimer = indicatorTimer < 4 ? indicatorTimer + 0.125 : 0;\n\t\t}, delay);\n\t};\n\n\tconst _stop = (msg = '', code = 0, silent: boolean = false): void => {\n\t\tif (!isSpinnerActive) return;\n\t\tisSpinnerActive = false;\n\t\tclearInterval(loop);\n\t\tclearPrevMessage();\n\t\tconst step =\n\t\t\tcode === 0\n\t\t\t\t? styleText('green', S_STEP_SUBMIT)\n\t\t\t\t: code === 1\n\t\t\t\t\t? styleText('red', S_STEP_CANCEL)\n\t\t\t\t\t: styleText('red', S_STEP_ERROR);\n\t\t_message = msg ?? _message;\n\t\tif (!silent) {\n\t\t\tif (indicator === 'timer') {\n\t\t\t\toutput.write(`${step}  ${_message} ${formatTimer(_origin)}\\n`);\n\t\t\t} else {\n\t\t\t\toutput.write(`${step}  ${_message}\\n`);\n\t\t\t}\n\t\t}\n\t\tclearHooks();\n\t\tunblock();\n\t};\n\n\tconst stop = (msg = ''): void => _stop(msg, 0);\n\tconst cancel = (msg = ''): void => _stop(msg, 1);\n\tconst error = (msg = ''): void => _stop(msg, 2);\n\t// TODO (43081j): this will leave the initial S_BAR since we purposely\n\t// don't erase that in `clearPrevMessage`. In future, we may want to treat\n\t// `clear` as a special case and remove the bar too.\n\tconst clear = (): void => _stop('', 0, true);\n\n\tconst message = (msg = ''): void => {\n\t\t_message = removeTrailingDots(msg ?? _message);\n\t};\n\n\treturn {\n\t\tstart,\n\t\tstop,\n\t\tmessage,\n\t\tcancel,\n\t\terror,\n\t\tclear,\n\t\tget isCancelled() {\n\t\t\treturn isCancelled;\n\t\t},\n\t};\n};\n"
  },
  {
    "path": "packages/prompts/src/stream.ts",
    "content": "import { stripVTControlCharacters as strip, styleText } from 'node:util';\nimport { S_BAR, S_ERROR, S_INFO, S_STEP_SUBMIT, S_SUCCESS, S_WARN } from './common.js';\nimport type { LogMessageOptions } from './log.js';\n\nconst prefix = `${styleText('gray', S_BAR)}  `;\n\n// TODO (43081j): this currently doesn't support custom `output` writables\n// because we rely on `columns` existing (i.e. `process.stdout.columns).\n//\n// If we want to support `output` being passed in, we will need to use\n// a condition like `if (output insance Writable)` to check if it has columns\nexport const stream = {\n\tmessage: async (\n\t\titerable: Iterable<string> | AsyncIterable<string>,\n\t\t{ symbol = styleText('gray', S_BAR) }: LogMessageOptions = {}\n\t) => {\n\t\tprocess.stdout.write(`${styleText('gray', S_BAR)}\\n${symbol}  `);\n\t\tlet lineWidth = 3;\n\t\tfor await (let chunk of iterable) {\n\t\t\tchunk = chunk.replace(/\\n/g, `\\n${prefix}`);\n\t\t\tif (chunk.includes('\\n')) {\n\t\t\t\tlineWidth = 3 + strip(chunk.slice(chunk.lastIndexOf('\\n'))).length;\n\t\t\t}\n\t\t\tconst chunkLen = strip(chunk).length;\n\t\t\tif (lineWidth + chunkLen < process.stdout.columns) {\n\t\t\t\tlineWidth += chunkLen;\n\t\t\t\tprocess.stdout.write(chunk);\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(`\\n${prefix}${chunk.trimStart()}`);\n\t\t\t\tlineWidth = 3 + strip(chunk.trimStart()).length;\n\t\t\t}\n\t\t}\n\t\tprocess.stdout.write('\\n');\n\t},\n\tinfo: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('blue', S_INFO) });\n\t},\n\tsuccess: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('green', S_SUCCESS) });\n\t},\n\tstep: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('green', S_STEP_SUBMIT) });\n\t},\n\twarn: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('yellow', S_WARN) });\n\t},\n\t/** alias for `log.warn()`. */\n\twarning: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.warn(iterable);\n\t},\n\terror: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('red', S_ERROR) });\n\t},\n};\n"
  },
  {
    "path": "packages/prompts/src/task-log.ts",
    "content": "import type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { getColumns } from '@clack/core';\nimport { erase } from 'sisteransi';\nimport {\n\ttype CommonOptions,\n\tisCI as isCIFn,\n\tisTTY as isTTYFn,\n\tS_BAR,\n\tS_STEP_SUBMIT,\n} from './common.js';\nimport { log } from './log.js';\n\nexport interface TaskLogOptions extends CommonOptions {\n\ttitle: string;\n\tlimit?: number;\n\tspacing?: number;\n\tretainLog?: boolean;\n}\n\nexport interface TaskLogMessageOptions {\n\traw?: boolean;\n}\n\nexport interface TaskLogCompletionOptions {\n\tshowLog?: boolean;\n}\n\ninterface BufferEntry {\n\theader?: string;\n\tvalue: string;\n\tfull: string;\n\tresult?: {\n\t\tstatus: 'success' | 'error';\n\t\tmessage: string;\n\t};\n}\n\nconst stripDestructiveANSI = (input: string): string => {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional\n\treturn input.replace(/\\x1b\\[(?:\\d+;)*\\d*[ABCDEFGHfJKSTsu]|\\x1b\\[(s|u)/g, '');\n};\n\n/**\n * Renders a log which clears on success and remains on failure\n */\nexport const taskLog = (opts: TaskLogOptions) => {\n\tconst output: Writable = opts.output ?? process.stdout;\n\tconst columns = getColumns(output);\n\tconst secondarySymbol = styleText('gray', S_BAR);\n\tconst spacing = opts.spacing ?? 1;\n\tconst barSize = 3;\n\tconst retainLog = opts.retainLog === true;\n\tconst isTTY = !isCIFn() && isTTYFn(output);\n\n\toutput.write(`${secondarySymbol}\\n`);\n\toutput.write(`${styleText('green', S_STEP_SUBMIT)}  ${opts.title}\\n`);\n\tfor (let i = 0; i < spacing; i++) {\n\t\toutput.write(`${secondarySymbol}\\n`);\n\t}\n\n\tconst buffers: BufferEntry[] = [\n\t\t{\n\t\t\tvalue: '',\n\t\t\tfull: '',\n\t\t},\n\t];\n\tlet lastMessageWasRaw = false;\n\n\tconst clear = (clearTitle: boolean): void => {\n\t\tif (buffers.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet lines = 0;\n\n\t\tif (clearTitle) {\n\t\t\tlines += spacing + 2;\n\t\t}\n\n\t\tfor (const buffer of buffers) {\n\t\t\tconst { value, result } = buffer;\n\t\t\tlet text = result?.message ?? value;\n\n\t\t\tif (text.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (result === undefined && buffer.header !== undefined && buffer.header !== '') {\n\t\t\t\ttext += `\\n${buffer.header}`;\n\t\t\t}\n\n\t\t\tconst bufferHeight = text.split('\\n').reduce((count, line) => {\n\t\t\t\tif (line === '') {\n\t\t\t\t\treturn count + 1;\n\t\t\t\t}\n\t\t\t\treturn count + Math.ceil((line.length + barSize) / columns);\n\t\t\t}, 0);\n\n\t\t\tlines += bufferHeight;\n\t\t}\n\n\t\tif (lines > 0) {\n\t\t\tlines += 1;\n\t\t\toutput.write(erase.lines(lines));\n\t\t}\n\t};\n\tconst printBuffer = (buffer: BufferEntry, messageSpacing?: number, full?: boolean): void => {\n\t\tconst messages = full ? `${buffer.full}\\n${buffer.value}` : buffer.value;\n\t\tif (buffer.header !== undefined && buffer.header !== '') {\n\t\t\tlog.message(\n\t\t\t\tbuffer.header.split('\\n').map((line) => styleText('bold', line)),\n\t\t\t\t{\n\t\t\t\t\toutput,\n\t\t\t\t\tsecondarySymbol,\n\t\t\t\t\tsymbol: secondarySymbol,\n\t\t\t\t\tspacing: 0,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t\tlog.message(\n\t\t\tmessages.split('\\n').map((line) => styleText('dim', line)),\n\t\t\t{\n\t\t\t\toutput,\n\t\t\t\tsecondarySymbol,\n\t\t\t\tsymbol: secondarySymbol,\n\t\t\t\tspacing: messageSpacing ?? spacing,\n\t\t\t}\n\t\t);\n\t};\n\tconst renderBuffer = (): void => {\n\t\tfor (const buffer of buffers) {\n\t\t\tconst { header, value, full } = buffer;\n\t\t\tif ((header === undefined || header.length === 0) && value.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tprintBuffer(buffer, undefined, retainLog === true && full.length > 0);\n\t\t}\n\t};\n\tconst message = (buffer: BufferEntry, msg: string, mopts?: TaskLogMessageOptions) => {\n\t\tclear(false);\n\t\tif ((mopts?.raw !== true || !lastMessageWasRaw) && buffer.value !== '') {\n\t\t\tbuffer.value += '\\n';\n\t\t}\n\t\tbuffer.value += stripDestructiveANSI(msg);\n\t\tlastMessageWasRaw = mopts?.raw === true;\n\t\tif (opts.limit !== undefined) {\n\t\t\tconst lines = buffer.value.split('\\n');\n\t\t\tconst linesToRemove = lines.length - opts.limit;\n\t\t\tif (linesToRemove > 0) {\n\t\t\t\tconst removedLines = lines.splice(0, linesToRemove);\n\t\t\t\tif (retainLog) {\n\t\t\t\t\tbuffer.full += (buffer.full === '' ? '' : '\\n') + removedLines.join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuffer.value = lines.join('\\n');\n\t\t}\n\t\tif (isTTY) {\n\t\t\tprintBuffers();\n\t\t}\n\t};\n\tconst printBuffers = (): void => {\n\t\tfor (const buffer of buffers) {\n\t\t\tif (buffer.result) {\n\t\t\t\tif (buffer.result.status === 'error') {\n\t\t\t\t\tlog.error(buffer.result.message, { output, secondarySymbol, spacing: 0 });\n\t\t\t\t} else {\n\t\t\t\t\tlog.success(buffer.result.message, { output, secondarySymbol, spacing: 0 });\n\t\t\t\t}\n\t\t\t} else if (buffer.value !== '') {\n\t\t\t\tprintBuffer(buffer, 0);\n\t\t\t}\n\t\t}\n\t};\n\tconst completeBuffer = (buffer: BufferEntry, result: BufferEntry['result']): void => {\n\t\tclear(false);\n\n\t\tbuffer.result = result;\n\n\t\tif (isTTY) {\n\t\t\tprintBuffers();\n\t\t}\n\t};\n\n\treturn {\n\t\tmessage(msg: string, mopts?: TaskLogMessageOptions) {\n\t\t\tmessage(buffers[0], msg, mopts);\n\t\t},\n\t\tgroup(name: string) {\n\t\t\tconst buffer: BufferEntry = {\n\t\t\t\theader: name,\n\t\t\t\tvalue: '',\n\t\t\t\tfull: '',\n\t\t\t};\n\t\t\tbuffers.push(buffer);\n\t\t\treturn {\n\t\t\t\tmessage(msg: string, mopts?: TaskLogMessageOptions) {\n\t\t\t\t\tmessage(buffer, msg, mopts);\n\t\t\t\t},\n\t\t\t\terror(message: string) {\n\t\t\t\t\tcompleteBuffer(buffer, {\n\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tsuccess(message: string) {\n\t\t\t\t\tcompleteBuffer(buffer, {\n\t\t\t\t\t\tstatus: 'success',\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\terror(message: string, opts?: TaskLogCompletionOptions): void {\n\t\t\tclear(true);\n\t\t\tlog.error(message, { output, secondarySymbol, spacing: 1 });\n\t\t\tif (opts?.showLog !== false) {\n\t\t\t\trenderBuffer();\n\t\t\t}\n\t\t\t// clear buffer since error is an end state\n\t\t\tbuffers.splice(1, buffers.length - 1);\n\t\t\tbuffers[0].value = '';\n\t\t\tbuffers[0].full = '';\n\t\t},\n\t\tsuccess(message: string, opts?: TaskLogCompletionOptions): void {\n\t\t\tclear(true);\n\t\t\tlog.success(message, { output, secondarySymbol, spacing: 1 });\n\t\t\tif (opts?.showLog === true) {\n\t\t\t\trenderBuffer();\n\t\t\t}\n\t\t\t// clear buffer since success is an end state\n\t\t\tbuffers.splice(1, buffers.length - 1);\n\t\t\tbuffers[0].value = '';\n\t\t\tbuffers[0].full = '';\n\t\t},\n\t};\n};\n"
  },
  {
    "path": "packages/prompts/src/task.ts",
    "content": "import type { CommonOptions } from './common.js';\nimport { spinner } from './spinner.js';\n\nexport type Task = {\n\t/**\n\t * Task title\n\t */\n\ttitle: string;\n\t/**\n\t * Task function\n\t */\n\ttask: (message: (string: string) => void) => string | Promise<string> | void | Promise<void>;\n\n\t/**\n\t * If enabled === false the task will be skipped\n\t */\n\tenabled?: boolean;\n};\n\n/**\n * Define a group of tasks to be executed\n */\nexport const tasks = async (tasks: Task[], opts?: CommonOptions) => {\n\tfor (const task of tasks) {\n\t\tif (task.enabled === false) continue;\n\n\t\tconst s = spinner(opts);\n\t\ts.start(task.title);\n\t\tconst result = await task.task(s.message);\n\t\ts.stop(result || task.title);\n\t}\n};\n"
  },
  {
    "path": "packages/prompts/src/text.ts",
    "content": "import { styleText } from 'node:util';\nimport { settings, TextPrompt } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\n\nexport interface TextOptions extends CommonOptions {\n\tmessage: string;\n\tplaceholder?: string;\n\tdefaultValue?: string;\n\tinitialValue?: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n}\n\nexport const text = (opts: TextOptions) => {\n\treturn new TextPrompt({\n\t\tvalidate: opts.validate,\n\t\tplaceholder: opts.placeholder,\n\t\tdefaultValue: opts.defaultValue,\n\t\tinitialValue: opts.initialValue,\n\t\toutput: opts.output,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\trender() {\n\t\t\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)}  `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\t\t\tconst placeholder = opts.placeholder\n\t\t\t\t? styleText('inverse', opts.placeholder[0]) + styleText('dim', opts.placeholder.slice(1))\n\t\t\t\t: styleText(['inverse', 'hidden'], '_');\n\t\t\tconst userInput = !this.userInput ? placeholder : this.userInputWithCursor;\n\t\t\tconst value = this.value ?? '';\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorText = this.error ? `  ${styleText('yellow', this.error)}` : '';\n\t\t\t\t\tconst errorPrefix = hasGuide ? `${styleText('yellow', S_BAR)}  ` : '';\n\t\t\t\t\tconst errorPrefixEnd = hasGuide ? styleText('yellow', S_BAR_END) : '';\n\t\t\t\t\treturn `${title.trim()}\\n${errorPrefix}${userInput}\\n${errorPrefixEnd}${errorText}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst valueText = value ? `  ${styleText('dim', value)}` : '';\n\t\t\t\t\tconst submitPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${valueText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst valueText = value ? `  ${styleText(['strikethrough', 'dim'], value)}` : '';\n\t\t\t\t\tconst cancelPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${valueText}${value.trim() ? `\\n${cancelPrefix}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)}  ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${userInput}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/autocomplete.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`autocomplete > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > cannot select disabled options when only one left 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m k█\u001b[2m (1 match)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > displays disabled options correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mApple\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Banana\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Cherry\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Grape\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=7>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Orange\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mApple\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > limits displayed options when maxItems is set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select an option\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > placeholder is shown if set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[2mType to search...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m g█\u001b[2m (2 matches)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Grape\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mGrape\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > renders bottom ellipsis when items do not fit 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Line 0\n\u001b[36m│\u001b[39m  Line 1\n\u001b[36m│\u001b[39m  Line 2\n\u001b[36m│\u001b[39m  Line 3\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select an option\n\u001b[90m│\u001b[39m  \u001b[2mLine 0\nLine 1\nLine 2\nLine 3\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > renders initial UI with message and instructions 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mApple\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > renders placeholder if set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[2mType to search...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mApple\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > renders top ellipsis when scrolled down and its do not fit 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 2\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<erase.down>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  Select an option\n\u001b[90m│\u001b[39m  \u001b[2mOption 2\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > shows hint when option has hint and is focused 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mKiwi\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mApple\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Banana\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mKiwi\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Cherry\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mKiwi\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Grape\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mKiwi\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=7>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Orange\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mKiwi\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=8>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Kiwi\u001b[2m (New Zealand)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mKiwi\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > shows no matches message when search has no results 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m z█\u001b[2m (0 matches)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[33mNo matches found\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > shows selected value in submit state 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mApple\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Banana\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mBanana\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > shows strikethrough in cancel state 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete > supports initialValue 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mApple\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Cherry\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mCherry\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete with custom filter > falls back to default filter when not provided 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m a█\u001b[2m (2 matches)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mApple\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocomplete with custom filter > uses custom filter function when provided 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m a█\u001b[2m (1 match)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2mApple\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocompleteMultiselect > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocompleteMultiselect > can use navigation keys to select options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select fruits\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[2m\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mApple\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Banana\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mSpace/Tab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Banana\",\n  \"<cursor.down count=5>\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Cherry\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mSpace/Tab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=6>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Cherry\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select fruits\n\u001b[90m│\u001b[39m  \u001b[2m2 items selected\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocompleteMultiselect > cannot select disabled options when only one left 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m k█\u001b[2m (1 match)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2m0 items selected\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocompleteMultiselect > displays disabled options correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[2m\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mApple\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Banana\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mSpace/Tab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Cherry\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mSpace/Tab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Grape\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mSpace/Tab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=7>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Orange\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mSpace/Tab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mKiwi\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mSpace/Tab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Apple\",\n  \"<cursor.down count=7>\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2m1 items selected\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocompleteMultiselect > renders error when empty selection & required is true 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  Select a fruit\n\u001b[33m│\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[33m│\u001b[39m  \u001b[33mPlease select at least one item\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[33m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[33m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[33m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[33m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[33m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[33m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select a fruit\n\u001b[90m│\u001b[39m  \u001b[2m1 items selected\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`autocompleteMultiselect > supports custom filter function 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select fruits\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mBanana\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mCherry\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mGrape\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOrange\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m a█\u001b[2m (1 match)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m Apple\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to navigate • \u001b[2mTab:\u001b[22m select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Apple\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select fruits\n\u001b[90m│\u001b[39m  \u001b[2m1 items selected\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/box.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`box (isCI = false) > cannot have width larger than 100% 1`] = `\n[\n  \"│ ┌─title──────────────────────────────────────────────────────────────────────┐\n\",\n  \"│ │  message                                                                   │\n\",\n  \"│ └────────────────────────────────────────────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders as specified width 1`] = `\n[\n  \"│ ┌─title──────────────────────────────┐\n\",\n  \"│ │  short                             │\n\",\n  \"│ │  somewhat questionably long line   │\n\",\n  \"│ └────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders as wide as longest line with width: auto 1`] = `\n[\n  \"│ ┌─title──────────────────────────────┐\n\",\n  \"│ │  short                             │\n\",\n  \"│ │  somewhat questionably long line   │\n\",\n  \"│ └────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders auto width with content longer than title 1`] = `\n[\n  \"│ ┌─title──────────────────────────┐\n\",\n  \"│ │  messagemessagemessagemessage  │\n\",\n  \"│ └────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders auto width with title longer than content 1`] = `\n[\n  \"│ ┌─titletitletitletitle─┐\n\",\n  \"│ │  message             │\n\",\n  \"│ └──────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders center aligned content 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders center aligned title 1`] = `\n[\n  \"│ ┌───title────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders left aligned content 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders left aligned title 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders message 1`] = `\n[\n  \"│ ┌────────────────────────────────────────────────────────────────────────────┐\n\",\n  \"│ │  message                                                                   │\n\",\n  \"│ └────────────────────────────────────────────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders message with title 1`] = `\n[\n  \"│ ┌─some title─────────────────────────────────────────────────────────────────┐\n\",\n  \"│ │  message                                                                   │\n\",\n  \"│ └────────────────────────────────────────────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders right aligned content 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │   message  │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders right aligned title 1`] = `\n[\n  \"│ ┌──────title─┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders rounded corners when rounded is true 1`] = `\n[\n  \"│ ╭─title──────╮\n\",\n  \"│ │  message   │\n\",\n  \"│ ╰────────────╯\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders specified contentPadding 1`] = `\n[\n  \"│ ┌─title──────────────┐\n\",\n  \"│ │      message       │\n\",\n  \"│ └────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders specified titlePadding 1`] = `\n[\n  \"│ ┌──────title───────┐\n\",\n  \"│ │  message         │\n\",\n  \"│ └──────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders truncated long titles 1`] = `\n[\n  \"│ ┌─foofoof...─┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders wide characters with auto width 1`] = `\n[\n  \"│ ┌─这是标题─────────────────┐\n\",\n  \"│ │  이게 첫 번째 줄이에요   │\n\",\n  \"│ │  これは次の行です        │\n\",\n  \"│ └──────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders wide characters with specified width 1`] = `\n[\n  \"│ ┌─这是标题───┐\n\",\n  \"│ │  이게 첫   │\n\",\n  \"│ │  번째      │\n\",\n  \"│ │  줄이에요  │\n\",\n  \"│ │  これは次  │\n\",\n  \"│ │  の行です  │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders with formatBorder formatting 1`] = `\n[\n  \"│ \u001b[31m┌\u001b[39m\u001b[31m─\u001b[39mtitle\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m┐\u001b[39m\n\",\n  \"│ \u001b[31m│\u001b[39m  message   \u001b[31m│\u001b[39m\n\",\n  \"│ \u001b[31m└\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m┘\u001b[39m\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders without guide when global withGuide is false 1`] = `\n[\n  \"┌─title──────┐\n\",\n  \"│  message   │\n\",\n  \"└────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > renders without guide when withGuide is false 1`] = `\n[\n  \"┌─title──────┐\n\",\n  \"│  message   │\n\",\n  \"└────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = false) > wraps content to fit within specified width 1`] = `\n[\n  \"│ ┌─title──────────────────────────────┐\n\",\n  \"│ │  foo barfoo barfoo barfoo barfoo   │\n\",\n  \"│ │  barfoo barfoo barfoo barfoo       │\n\",\n  \"│ │  barfoo barfoo barfoo barfoo       │\n\",\n  \"│ │  barfoo barfoo barfoo barfoo       │\n\",\n  \"│ │  barfoo barfoo barfoo bar          │\n\",\n  \"│ └────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > cannot have width larger than 100% 1`] = `\n[\n  \"│ ┌─title──────────────────────────────────────────────────────────────────────┐\n\",\n  \"│ │  message                                                                   │\n\",\n  \"│ └────────────────────────────────────────────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders as specified width 1`] = `\n[\n  \"│ ┌─title──────────────────────────────┐\n\",\n  \"│ │  short                             │\n\",\n  \"│ │  somewhat questionably long line   │\n\",\n  \"│ └────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders as wide as longest line with width: auto 1`] = `\n[\n  \"│ ┌─title──────────────────────────────┐\n\",\n  \"│ │  short                             │\n\",\n  \"│ │  somewhat questionably long line   │\n\",\n  \"│ └────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders auto width with content longer than title 1`] = `\n[\n  \"│ ┌─title──────────────────────────┐\n\",\n  \"│ │  messagemessagemessagemessage  │\n\",\n  \"│ └────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders auto width with title longer than content 1`] = `\n[\n  \"│ ┌─titletitletitletitle─┐\n\",\n  \"│ │  message             │\n\",\n  \"│ └──────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders center aligned content 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders center aligned title 1`] = `\n[\n  \"│ ┌───title────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders left aligned content 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders left aligned title 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders message 1`] = `\n[\n  \"│ ┌────────────────────────────────────────────────────────────────────────────┐\n\",\n  \"│ │  message                                                                   │\n\",\n  \"│ └────────────────────────────────────────────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders message with title 1`] = `\n[\n  \"│ ┌─some title─────────────────────────────────────────────────────────────────┐\n\",\n  \"│ │  message                                                                   │\n\",\n  \"│ └────────────────────────────────────────────────────────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders right aligned content 1`] = `\n[\n  \"│ ┌─title──────┐\n\",\n  \"│ │   message  │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders right aligned title 1`] = `\n[\n  \"│ ┌──────title─┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders rounded corners when rounded is true 1`] = `\n[\n  \"│ ╭─title──────╮\n\",\n  \"│ │  message   │\n\",\n  \"│ ╰────────────╯\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders specified contentPadding 1`] = `\n[\n  \"│ ┌─title──────────────┐\n\",\n  \"│ │      message       │\n\",\n  \"│ └────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders specified titlePadding 1`] = `\n[\n  \"│ ┌──────title───────┐\n\",\n  \"│ │  message         │\n\",\n  \"│ └──────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders truncated long titles 1`] = `\n[\n  \"│ ┌─foofoof...─┐\n\",\n  \"│ │  message   │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders wide characters with auto width 1`] = `\n[\n  \"│ ┌─这是标题─────────────────┐\n\",\n  \"│ │  이게 첫 번째 줄이에요   │\n\",\n  \"│ │  これは次の行です        │\n\",\n  \"│ └──────────────────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders wide characters with specified width 1`] = `\n[\n  \"│ ┌─这是标题───┐\n\",\n  \"│ │  이게 첫   │\n\",\n  \"│ │  번째      │\n\",\n  \"│ │  줄이에요  │\n\",\n  \"│ │  これは次  │\n\",\n  \"│ │  の行です  │\n\",\n  \"│ └────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders with formatBorder formatting 1`] = `\n[\n  \"│ \u001b[31m┌\u001b[39m\u001b[31m─\u001b[39mtitle\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m┐\u001b[39m\n\",\n  \"│ \u001b[31m│\u001b[39m  message   \u001b[31m│\u001b[39m\n\",\n  \"│ \u001b[31m└\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m─\u001b[39m\u001b[31m┘\u001b[39m\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders without guide when global withGuide is false 1`] = `\n[\n  \"┌─title──────┐\n\",\n  \"│  message   │\n\",\n  \"└────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > renders without guide when withGuide is false 1`] = `\n[\n  \"┌─title──────┐\n\",\n  \"│  message   │\n\",\n  \"└────────────┘\n\",\n]\n`;\n\nexports[`box (isCI = true) > wraps content to fit within specified width 1`] = `\n[\n  \"│ ┌─title──────────────────────────────┐\n\",\n  \"│ │  foo barfoo barfoo barfoo barfoo   │\n\",\n  \"│ │  barfoo barfoo barfoo barfoo       │\n\",\n  \"│ │  barfoo barfoo barfoo barfoo       │\n\",\n  \"│ │  barfoo barfoo barfoo barfoo       │\n\",\n  \"│ │  barfoo barfoo barfoo bar          │\n\",\n  \"│ └────────────────────────────────────┘\n\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/confirm.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`confirm (isCI = false) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  yes?\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mNo\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > can set initialValue 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mYes\u001b[22m \u001b[2m/\u001b[22m \u001b[32m●\u001b[39m No\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mNo\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > left arrow moves to previous choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mYes\u001b[22m \u001b[2m/\u001b[22m \u001b[32m●\u001b[39m No\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > renders custom active choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m bleep \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mbleep\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > renders custom inactive choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mbleep\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > renders message with choices 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > renders options in vertical alignment 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > right arrow moves to next choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mYes\u001b[22m \u001b[2m/\u001b[22m \u001b[32m●\u001b[39m No\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mNo\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = false) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  yes?\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mNo\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > can set initialValue 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mYes\u001b[22m \u001b[2m/\u001b[22m \u001b[32m●\u001b[39m No\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mNo\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > left arrow moves to previous choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mYes\u001b[22m \u001b[2m/\u001b[22m \u001b[32m●\u001b[39m No\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > renders custom active choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m bleep \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mbleep\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > renders custom inactive choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mbleep\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > renders message with choices 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > renders options in vertical alignment 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > right arrow moves to next choice 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mYes\u001b[22m \u001b[2m/\u001b[22m \u001b[32m●\u001b[39m No\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mNo\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`confirm (isCI = true) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m Yes \u001b[2m/\u001b[22m \u001b[2m○\u001b[22m \u001b[2mNo\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mYes\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/date.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`date (isCI = false) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7mmm\u001b[27m\u001b[90m/\u001b[39m\u001b[2mdd\u001b[22m\u001b[90m/\u001b[39m\u001b[2myyyy\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = false) > defaultValue used when empty submit 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m12\u001b[27m\u001b[90m/\u001b[39m25\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m12/25/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = false) > renders initial value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = false) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = false) > renders submitted value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m06\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m06/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = false) > supports MDY format 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = false) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  Pick a date\n\u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = true) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7mmm\u001b[27m\u001b[90m/\u001b[39m\u001b[2mdd\u001b[22m\u001b[90m/\u001b[39m\u001b[2myyyy\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = true) > defaultValue used when empty submit 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m12\u001b[27m\u001b[90m/\u001b[39m25\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m12/25/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = true) > renders initial value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = true) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = true) > renders submitted value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m06\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m06/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = true) > supports MDY format 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Pick a date\n\u001b[36m│\u001b[39m  \u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n\u001b[90m│\u001b[39m  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`date (isCI = true) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  Pick a date\n\u001b[7m01\u001b[27m\u001b[90m/\u001b[39m15\u001b[90m/\u001b[39m2025\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Pick a date\n  \u001b[2m01/15/2025\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/group-multi-select.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`groupMultiselect (isCI = false) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > can deselect an option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > can select a group 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[32m◼\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > can select a group by selecting all members 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > can select multiple options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > can submit empty selection when require = false 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > cursorAt sets initial selection 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value1\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > groupSpacing > negative spacing is ignored 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > groupSpacing > renders spaced groups 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value0\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > initial values can be set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[32m◼\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > renders error when nothing selected 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[33m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[33m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[33m└\u001b[39m  \u001b[33mPlease select at least one option.\u001b[39m\n   \u001b[0m\u001b[2mPress \u001b[90m\u001b[47m\u001b[7m space \u001b[27m\u001b[49m\u001b[39m to select, \u001b[90m\u001b[47m\u001b[7m enter \u001b[27m\u001b[49m\u001b[39m to submit\u001b[22m\u001b[0m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > renders message with options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=5>\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > selectableGroups = false > cannot select groups 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > selectableGroups = false > selecting all members of group does not select group 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m group1value1\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = false) > values can be non-primitive 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mvalue0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mvalue1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mvalue1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mvalue0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select a fruit\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > can deselect an option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > can select a group 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[32m◼\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > can select a group by selecting all members 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > can select multiple options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > can submit empty selection when require = false 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > cursorAt sets initial selection 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value1\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > groupSpacing > negative spacing is ignored 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > groupSpacing > renders spaced groups 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[32m◼\u001b[39m group1value0\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > initial values can be set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[32m◼\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > renders error when nothing selected 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[33m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[33m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[33m└\u001b[39m  \u001b[33mPlease select at least one option.\u001b[39m\n   \u001b[0m\u001b[2mPress \u001b[90m\u001b[47m\u001b[7m space \u001b[27m\u001b[49m\u001b[39m to select, \u001b[90m\u001b[47m\u001b[7m enter \u001b[27m\u001b[49m\u001b[39m to submit\u001b[22m\u001b[0m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > renders message with options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup2value0\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=5>\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > selectableGroups = false > cannot select groups 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > selectableGroups = false > selecting all members of group does not select group 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[36m◻\u001b[39m group1value0\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1value1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m group1value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m \u001b[2mgroup1value0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[36m◻\u001b[39m group1value1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m  \u001b[22m\u001b[32m◼\u001b[39m group1value1\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mgroup1value0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mgroup1value1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`groupMultiselect (isCI = true) > values can be non-primitive 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[36m◻\u001b[39m group1\n\u001b[36m│\u001b[39m  │ \u001b[36m◻\u001b[39m \u001b[2mvalue0\u001b[22m\n\u001b[36m│\u001b[39m  └ \u001b[36m◻\u001b[39m \u001b[2mvalue1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m\u001b[22m\u001b[2m◻\u001b[22m \u001b[2mgroup1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[36m◻\u001b[39m value0\n\u001b[36m│\u001b[39m  \u001b[2m└ \u001b[22m\u001b[2m◻\u001b[22m \u001b[2mvalue1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m│ \u001b[22m\u001b[32m◼\u001b[39m value0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mvalue0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/log.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`log (isCI = false) > error > renders error message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  error message\n\",\n]\n`;\n\nexports[`log (isCI = false) > info > renders info message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[34m●\u001b[39m  info message\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders empty lines correctly 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  foo\n\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  bar\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders empty lines with guide disabled 1`] = `\n[\n  \"\nfoo\n\nbar\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders empty message correctly 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders empty message with guide disabled 1`] = `\n[\n  \"\n\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  message\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders message from array 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  line 1\n\u001b[90m│\u001b[39m  line 2\n\u001b[90m│\u001b[39m  line 3\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders message with custom spacing 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  spaced message\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders message with custom symbols and spacing 1`] = `\n[\n  \"\u001b[33m--\u001b[39m\n\u001b[31m>>\u001b[39m  custom\n\u001b[33m--\u001b[39m  symbols\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders message with guide disabled 1`] = `\n[\n  \"\nstandalone message\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders multiline message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  line 1\n\u001b[90m│\u001b[39m  line 2\n\u001b[90m│\u001b[39m  line 3\n\",\n]\n`;\n\nexports[`log (isCI = false) > message > renders multiline message with guide disabled 1`] = `\n[\n  \"\nline 1\nline 2\nline 3\n\",\n]\n`;\n\nexports[`log (isCI = false) > step > renders step message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  step message\n\",\n]\n`;\n\nexports[`log (isCI = false) > success > renders success message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  success message\n\",\n]\n`;\n\nexports[`log (isCI = false) > warn > renders warn message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[33m▲\u001b[39m  warn message\n\",\n]\n`;\n\nexports[`log (isCI = true) > error > renders error message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  error message\n\",\n]\n`;\n\nexports[`log (isCI = true) > info > renders info message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[34m●\u001b[39m  info message\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders empty lines correctly 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  foo\n\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  bar\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders empty lines with guide disabled 1`] = `\n[\n  \"\nfoo\n\nbar\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders empty message correctly 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders empty message with guide disabled 1`] = `\n[\n  \"\n\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  message\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders message from array 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  line 1\n\u001b[90m│\u001b[39m  line 2\n\u001b[90m│\u001b[39m  line 3\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders message with custom spacing 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  spaced message\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders message with custom symbols and spacing 1`] = `\n[\n  \"\u001b[33m--\u001b[39m\n\u001b[31m>>\u001b[39m  custom\n\u001b[33m--\u001b[39m  symbols\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders message with guide disabled 1`] = `\n[\n  \"\nstandalone message\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders multiline message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  line 1\n\u001b[90m│\u001b[39m  line 2\n\u001b[90m│\u001b[39m  line 3\n\",\n]\n`;\n\nexports[`log (isCI = true) > message > renders multiline message with guide disabled 1`] = `\n[\n  \"\nline 1\nline 2\nline 3\n\",\n]\n`;\n\nexports[`log (isCI = true) > step > renders step message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  step message\n\",\n]\n`;\n\nexports[`log (isCI = true) > success > renders success message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  success message\n\",\n]\n`;\n\nexports[`log (isCI = true) > warn > renders warn message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[33m▲\u001b[39m  warn message\n\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/multi-select.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`multiselect (isCI = false) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > can render option hints 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > can set cursorAt to preselect an option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > can set custom labels 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Option 0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > can set initial values 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > can submit without selection when required = false 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mnone\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > maxItems renders a sliding window 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt3\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt4\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt5\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt6\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=5>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt6\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt6\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > renders disabled options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mopt0\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mopt2\u001b[39m\u001b[29m \u001b[2m(Hint 2)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > renders multiple cancelled values 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mopt0\u001b[22m\u001b[29m\u001b[2m, \u001b[22m\u001b[9m\u001b[2mopt1\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > renders multiple selected options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > renders validation errors 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[33m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[33m└\u001b[39m  \u001b[33mPlease select at least one option.\u001b[39m\n   \u001b[0m\u001b[2mPress \u001b[90m\u001b[47m\u001b[7m space \u001b[27m\u001b[49m\u001b[39m to select, \u001b[90m\u001b[47m\u001b[7m enter \u001b[27m\u001b[49m\u001b[39m to submit\u001b[22m\u001b[0m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > shows hints for all selected options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m \u001b[2m(Hint 1)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt0\u001b[22m \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1 \u001b[2m(Hint 1)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m \u001b[2m(Hint 1)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2 \u001b[2m(Hint 2)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > sliding window loops downwards 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt3\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt4\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt5\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt6\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt7\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt8\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt8\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt9\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt8\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt9\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt10\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt11\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt9\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt10\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt11\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt10\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt11\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=7>\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > sliding window loops upwards 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt8\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt9\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt10\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt11\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=7>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt11\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt11\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > wraps cancelled state with long options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOption 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Option 0 Option 0 Option \",\n  \"<cursor.down count=9>\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > wraps long messages 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo foo foo foo foo foo foo\n\u001b[32m│\u001b[39m   foo foo foo foo foo foo \n\u001b[32m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = false) > wraps success state with long options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOption 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Option 0 Option 0 Option \",\n  \"<cursor.down count=9>\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > can render option hints 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > can set cursorAt to preselect an option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > can set custom labels 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Option 0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > can set initial values 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > can submit without selection when required = false 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mnone\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > maxItems renders a sliding window 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt3\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt4\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt5\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt6\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=5>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt6\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt6\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > renders disabled options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mopt0\u001b[39m\u001b[29m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[90m◻\u001b[39m \u001b[9m\u001b[90mopt2\u001b[39m\u001b[29m \u001b[2m(Hint 2)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > renders multiple cancelled values 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mopt0\u001b[22m\u001b[29m\u001b[2m, \u001b[22m\u001b[9m\u001b[2mopt1\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > renders multiple selected options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=4>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > renders validation errors 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[33m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[33m└\u001b[39m  \u001b[33mPlease select at least one option.\u001b[39m\n   \u001b[0m\u001b[2mPress \u001b[90m\u001b[47m\u001b[7m space \u001b[27m\u001b[49m\u001b[39m to select, \u001b[90m\u001b[47m\u001b[7m enter \u001b[27m\u001b[49m\u001b[39m to submit\u001b[22m\u001b[0m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > shows hints for all selected options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m \u001b[2m(Hint 1)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt0\u001b[22m \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt1 \u001b[2m(Hint 1)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m \u001b[2mopt1\u001b[22m \u001b[2m(Hint 1)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2 \u001b[2m(Hint 2)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\u001b[2m, \u001b[22m\u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > sliding window loops downwards 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt1\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt2\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt3\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt4\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt5\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt6\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt7\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt8\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt6\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt8\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt9\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt8\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt9\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt10\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt11\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt9\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt10\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt11\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt10\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt11\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=7>\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > sliding window loops upwards 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt7\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt8\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt9\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt10\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt11\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=7>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt11\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt11\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > wraps cancelled state with long options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOption 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Option 0 Option 0 Option \",\n  \"<cursor.down count=9>\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > wraps long messages 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=4>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m opt0\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo foo foo foo foo foo foo\n\u001b[32m│\u001b[39m   foo foo foo foo foo foo \n\u001b[32m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`multiselect (isCI = true) > wraps success state with long options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[36m◻\u001b[39m Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0 Option 0 Option \n\u001b[36m│\u001b[39m  0 Option 0\n\u001b[36m│\u001b[39m  \u001b[2m◻\u001b[22m \u001b[2mOption 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1 Option 1 Option \u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m1 Option 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m◼\u001b[39m Option 0 Option 0 Option \",\n  \"<cursor.down count=9>\",\n  \"<cursor.backward count=999><cursor.up count=11>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0 Option 0 Option 0 \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/note.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`note (isCI = false) > don't overflow 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───────────────────────────────────────────────────────────────╮\u001b[39m\n\u001b[90m│\u001b[39m                                                                       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string \u001b[22m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string \u001b[22m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string \u001b[22m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string\u001b[22m               \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m                                                                       \u001b[90m│\u001b[39m\n\u001b[90m├───────────────────────────────────────────────────────────────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > don't overflow with formatter 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m─────────────────────────────────────────────────────────────────╮\u001b[39m\n\u001b[90m│\u001b[39m                                                                         \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string \u001b[31m *\u001b[39m                                                \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string \u001b[31m *\u001b[39m                                                \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string \u001b[31m *\u001b[39m                                                \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string\u001b[31m *\u001b[39m                                                 \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m                                                                         \u001b[90m│\u001b[39m\n\u001b[90m├─────────────────────────────────────────────────────────────────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > formatter which adds colors works 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m──╮\u001b[39m\n\u001b[90m│\u001b[39m          \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31mline 0\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31mline 1\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31mline 2\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m          \u001b[90m│\u001b[39m\n\u001b[90m├──────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > formatter which adds length works 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m──────╮\u001b[39m\n\u001b[90m│\u001b[39m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  * line 0 *  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  * line 1 *  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  * line 2 *  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m              \u001b[90m│\u001b[39m\n\u001b[90m├──────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > handle wide characters 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0m这是标题\u001b[0m \u001b[90m─╮\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m이게\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m 첫 \u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m번째\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m \u001b[22m         \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m줄이\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m에요\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mこれ\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mは次\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mの行\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mです\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m├────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > handle wide characters with formatter 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0m这是标题\u001b[0m \u001b[90m─╮\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m\u001b[31m *\u001b[39m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m이\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m게\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m \u001b[31m *\u001b[39m     \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m첫\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m \u001b[31m *\u001b[39m     \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m번\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m째\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m \u001b[31m *\u001b[39m     \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m줄\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m이\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m에\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m요\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m\u001b[31m *\u001b[39m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mこ\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mれ\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mは\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m次\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mの\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m行\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mで\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mす\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m├────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > renders as wide as longest line 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───────────────────────────╮\u001b[39m\n\u001b[90m│\u001b[39m                                   \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mshort\u001b[22m                            \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat questionably long line\u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m                                   \u001b[90m│\u001b[39m\n\u001b[90m├───────────────────────────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > renders message with title 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───╮\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mmessage\u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m├───────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = false) > without guide 1`] = `\n[\n  \"\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───╮\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mmessage\u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m╰───────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > don't overflow 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───────────────────────────────────────────────────────────────╮\u001b[39m\n\u001b[90m│\u001b[39m                                                                       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string \u001b[22m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string \u001b[22m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string \u001b[22m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string test string \u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mtest string test string test string test string test string test \u001b[22m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mstring test string test string test string test string\u001b[22m               \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m                                                                       \u001b[90m│\u001b[39m\n\u001b[90m├───────────────────────────────────────────────────────────────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > don't overflow with formatter 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m─────────────────────────────────────────────────────────────────╮\u001b[39m\n\u001b[90m│\u001b[39m                                                                         \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string \u001b[31m *\u001b[39m                                                \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string \u001b[31m *\u001b[39m                                                \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string \u001b[31m *\u001b[39m                                                \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mtest string test string test string test string test string test \u001b[31m *\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string test string test string test string test \u001b[31m *\u001b[39m       \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mstring test string\u001b[31m *\u001b[39m                                                 \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m                                                                         \u001b[90m│\u001b[39m\n\u001b[90m├─────────────────────────────────────────────────────────────────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > formatter which adds colors works 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m──╮\u001b[39m\n\u001b[90m│\u001b[39m          \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31mline 0\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31mline 1\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31mline 2\u001b[39m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m          \u001b[90m│\u001b[39m\n\u001b[90m├──────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > formatter which adds length works 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m──────╮\u001b[39m\n\u001b[90m│\u001b[39m              \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  * line 0 *  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  * line 1 *  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  * line 2 *  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m              \u001b[90m│\u001b[39m\n\u001b[90m├──────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > handle wide characters 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0m这是标题\u001b[0m \u001b[90m─╮\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m이게\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m 첫 \u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m번째\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m \u001b[22m         \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m줄이\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2m에요\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mこれ\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mは次\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mの行\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mです\u001b[22m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m├────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > handle wide characters with formatter 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0m这是标题\u001b[0m \u001b[90m─╮\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m\u001b[31m *\u001b[39m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m이\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m게\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m \u001b[31m *\u001b[39m     \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m첫\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m \u001b[31m *\u001b[39m     \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m번\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m째\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m \u001b[31m *\u001b[39m     \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m줄\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m이\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m에\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m요\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m\u001b[31m *\u001b[39m      \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mこ\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mれ\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mは\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m次\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mの\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36m行\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mで\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[31m* \u001b[36mす\u001b[31m *\u001b[39m    \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m            \u001b[90m│\u001b[39m\n\u001b[90m├────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > renders as wide as longest line 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───────────────────────────╮\u001b[39m\n\u001b[90m│\u001b[39m                                   \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mshort\u001b[22m                            \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat questionably long line\u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m                                   \u001b[90m│\u001b[39m\n\u001b[90m├───────────────────────────────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > renders message with title 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───╮\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mmessage\u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m├───────────╯\u001b[39m\n\",\n]\n`;\n\nexports[`note (isCI = true) > without guide 1`] = `\n[\n  \"\u001b[32m◇\u001b[39m  \u001b[0mtitle\u001b[0m \u001b[90m───╮\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mmessage\u001b[22m  \u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m           \u001b[90m│\u001b[39m\n\u001b[90m╰───────────╯\u001b[39m\n\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/password.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`password (isCI = false) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > clears input on error when clearOnError is true 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  ▪\n\u001b[33m└\u001b[39m  \u001b[33mError\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m▪▪\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > renders and clears validation errors 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  ▪\n\u001b[33m└\u001b[39m  \u001b[33mPassword must be at least 2 characters\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  ▪▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m▪▪\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > renders cancelled value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2m▪\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > renders custom mask 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  *\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  **\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m**\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > renders masked value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m▪▪\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = false) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > clears input on error when clearOnError is true 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  ▪\n\u001b[33m└\u001b[39m  \u001b[33mError\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m▪▪\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > renders and clears validation errors 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  ▪\n\u001b[33m└\u001b[39m  \u001b[33mPassword must be at least 2 characters\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  ▪▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m▪▪\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > renders cancelled value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2m▪\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > renders custom mask 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  *\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  **\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m**\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > renders masked value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  ▪▪\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m▪▪\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`password (isCI = true) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/path.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`text (isCI = false) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2m/tmp/\u001b[22m\u001b[29m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > cannot submit unknown value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/_█\n\u001b[36m│\u001b[39m  \u001b[33mNo matches found\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/_█\n\u001b[33m│\u001b[39m  \u001b[33mNo matches found\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[33mPlease select a path\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[33m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > initialValue sets the value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/bar█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > renders cancelled value if one set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/x█\n\u001b[36m│\u001b[39m  \u001b[33mNo matches found\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/xy█\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2m/tmp/xy\u001b[22m\u001b[29m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > renders submitted value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/ba█\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > validation errors render and clear (using Error) 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[33m│\u001b[39m  \u001b[33mshould be /tmp/bar\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[33m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[33m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/bar\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > validation errors render and clear 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[33m│\u001b[39m  \u001b[33mshould be /tmp/bar\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[33m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[33m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/bar\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2m/tmp/\u001b[22m\u001b[29m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > cannot submit unknown value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/_█\n\u001b[36m│\u001b[39m  \u001b[33mNo matches found\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/_█\n\u001b[33m│\u001b[39m  \u001b[33mNo matches found\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[33mPlease select a path\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[33m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > initialValue sets the value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/bar█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > renders cancelled value if one set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/x█\n\u001b[36m│\u001b[39m  \u001b[33mNo matches found\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/xy█\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2m/tmp/xy\u001b[22m\u001b[29m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > renders submitted value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=3>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/ba█\",\n  \"<cursor.down count=3>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > validation errors render and clear (using Error) 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[33m│\u001b[39m  \u001b[33mshould be /tmp/bar\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[33m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[33m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/bar\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > validation errors render and clear 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/root.zip\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/r█\n\u001b[33m│\u001b[39m  \u001b[33mshould be /tmp/bar\u001b[39m\n\u001b[33m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[33m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[33m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/█\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/bar\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/foo\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2m/tmp/hello\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/root.zip\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=3>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2mSearch:\u001b[22m /tmp/b█\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m /tmp/bar\n\u001b[36m│\u001b[39m  \u001b[2m↑/↓\u001b[22m to select • \u001b[2mEnter:\u001b[22m confirm • \u001b[2mType:\u001b[22m to search\n\u001b[36m└\u001b[39m\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2m/tmp/bar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/progress-bar.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`prompts - progress (isCI = false) > message > sets message for next frame 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m foo\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > process exit handling > prioritizes cancel option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Progress cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > process exit handling > prioritizes error option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Progress error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > process exit handling > uses custom cancel message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Custom cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > process exit handling > uses custom error message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Custom error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > process exit handling > uses default cancel message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Canceled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > process exit handling > uses global custom cancel message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Global cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > process exit handling > uses global custom error message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Global error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > start > renders frames at interval 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◓\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◑\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > start > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m foo\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > start > renders timer when indicator is \"timer\" 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m  [0s]\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > stop > renders cancel symbol when calling cancel() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > stop > renders error symbol when calling error() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > stop > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > stop > renders message when cancelling 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  cancelled :-(\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > stop > renders message when erroring 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  FATAL ERROR!\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > stop > renders message without removing dots 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo.\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > stop > renders submit symbol and stops progress 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > style > renders block progressbar 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m██████████\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m\u001b[39m\u001b[2m██████████\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◓\u001b[39m  \u001b[35m█████\u001b[39m\u001b[2m█████\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◑\u001b[39m  \u001b[35m█████\u001b[39m\u001b[2m█████\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > style > renders heavy progressbar 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◓\u001b[39m  \u001b[35m━━━━━\u001b[39m\u001b[2m━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◑\u001b[39m  \u001b[35m━━━━━\u001b[39m\u001b[2m━━━━━\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = false) > style > renders light progressbar 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m──────────\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m\u001b[39m\u001b[2m──────────\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◓\u001b[39m  \u001b[35m─────\u001b[39m\u001b[2m─────\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◑\u001b[39m  \u001b[35m─────\u001b[39m\u001b[2m─────\u001b[22m \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > message > sets message for next frame 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m foo...\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > process exit handling > prioritizes cancel option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Progress cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > process exit handling > prioritizes error option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Progress error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > process exit handling > uses custom cancel message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Custom cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > process exit handling > uses custom error message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Custom error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > process exit handling > uses default cancel message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Canceled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > process exit handling > uses global custom cancel message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Global cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > process exit handling > uses global custom error message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Global error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > start > renders frames at interval 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > start > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m foo...\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > start > renders timer when indicator is \"timer\" 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > stop > renders cancel symbol when calling cancel() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > stop > renders error symbol when calling error() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > stop > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > stop > renders message when cancelling 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  cancelled :-(\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > stop > renders message when erroring 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  FATAL ERROR!\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > stop > renders message without removing dots 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo.\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > stop > renders submit symbol and stops progress 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > style > renders block progressbar 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m██████████\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m█████\u001b[39m\u001b[2m█████\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > style > renders heavy progressbar 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m━━━━━━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m━━━━━\u001b[39m\u001b[2m━━━━━\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`prompts - progress (isCI = true) > style > renders light progressbar 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \u001b[35m\u001b[39m\u001b[2m──────────\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \u001b[35m─────\u001b[39m\u001b[2m─────\u001b[22m ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/select-key.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`text (isCI = false) > can cancel by pressing escape 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mOption A\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > caseSensitive: true makes input case-sensitive 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option a\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m A \u001b[27m\u001b[49m\u001b[39m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = false) > caseSensitive: true makes options case-sensitive 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m A \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mOption A\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = false) > input is case-insensitive by default 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = false) > long cancelled labels are wrapped correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option:\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m This is a somewhat long\n\u001b[36m│\u001b[39m   label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label \n\u001b[36m│\u001b[39m  This is a somewhat long \n\u001b[36m│\u001b[39m  label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Short label\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=16>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  Select an option:\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > long option labels are wrapped correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option:\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m This is a somewhat long\n\u001b[36m│\u001b[39m   label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label \n\u001b[36m│\u001b[39m  This is a somewhat long \n\u001b[36m│\u001b[39m  label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Short label\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=16>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select an option:\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = false) > long submitted labels are wrapped correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option:\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m This is a somewhat long\n\u001b[36m│\u001b[39m   label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label \n\u001b[36m│\u001b[39m  This is a somewhat long \n\u001b[36m│\u001b[39m  label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Short label\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=16>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select an option:\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = false) > options are case-insensitive by default 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m A \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = false) > renders message with options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > selects option by keypress 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption B\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = false) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > can cancel by pressing escape 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mOption A\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > caseSensitive: true makes input case-sensitive 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option a\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m A \u001b[27m\u001b[49m\u001b[39m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > caseSensitive: true makes options case-sensitive 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m A \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mOption A\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > input is case-insensitive by default 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > long cancelled labels are wrapped correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option:\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m This is a somewhat long\n\u001b[36m│\u001b[39m   label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label \n\u001b[36m│\u001b[39m  This is a somewhat long \n\u001b[36m│\u001b[39m  label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Short label\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=16>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  Select an option:\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > long option labels are wrapped correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option:\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m This is a somewhat long\n\u001b[36m│\u001b[39m   label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label \n\u001b[36m│\u001b[39m  This is a somewhat long \n\u001b[36m│\u001b[39m  label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Short label\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=16>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select an option:\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > long submitted labels are wrapped correctly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Select an option:\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m This is a somewhat long\n\u001b[36m│\u001b[39m   label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label \n\u001b[36m│\u001b[39m  This is a somewhat long \n\u001b[36m│\u001b[39m  label This is a somewhat \n\u001b[36m│\u001b[39m  long label This is a \n\u001b[36m│\u001b[39m  somewhat long label This is\n\u001b[36m│\u001b[39m   a somewhat long label This\n\u001b[36m│\u001b[39m   is a somewhat long label\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Short label\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=16>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Select an option:\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mThis is a somewhat long \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlabel This is a somewhat \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mlong label This is a \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2msomewhat long label This is\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m a somewhat long label This\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m is a somewhat long label\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > options are case-insensitive by default 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m A \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > renders message with options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption A\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > selects option by keypress 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[36m│\u001b[39m  \u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption B\u001b[22m\",\n  \"\n\",\n]\n`;\n\nexports[`text (isCI = true) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[46m\u001b[90m a \u001b[39m\u001b[49m Option A\n\u001b[90m\u001b[47m\u001b[7m b \u001b[27m\u001b[49m\u001b[39m Option B\n\n\",\n  \"<cursor.show>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mOption A\u001b[22m\",\n  \"\n\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/select.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`select (isCI = false) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mopt0\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > correctly limits options when message wraps to multiple lines 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  This is a very \n\u001b[36m│\u001b[39m  long message that\n\u001b[36m│\u001b[39m   will wrap to \n\u001b[36m│\u001b[39m  multiple lines\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 2\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 3\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 4\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  This is a very \n\u001b[32m│\u001b[39m  long message that\n\u001b[32m│\u001b[39m   will wrap to \n\u001b[32m│\u001b[39m  multiple lines\n\u001b[90m│\u001b[39m  \u001b[2mOption 4\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > correctly limits options with explicit multiline message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Choose an option:\n\u001b[36m│\u001b[39m  Line 2 of the message\n\u001b[36m│\u001b[39m  Line 3 of the message\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 2\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 3\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Choose an option:\n\u001b[32m│\u001b[39m  Line 2 of the message\n\u001b[32m│\u001b[39m  Line 3 of the message\n\u001b[90m│\u001b[39m  \u001b[2mOption 3\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > down arrow selects next option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m opt0\n\u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > handles mixed size re-renders 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Whatever\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=12>\",\n  \"<erase.down>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Whatever\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 3\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Whatever\n\u001b[90m│\u001b[39m  \u001b[2mOption 3\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > renders disabled options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[90mOption 0\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[90mOption 2\u001b[39m \u001b[2m(Hint 2)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > renders multi-line option labels 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  with multiple lines\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2mwith multiple lines\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > renders option hints 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > renders option labels 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > renders options and message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > up arrow selects previous option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m opt0\n\u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > wraps long cancelled message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > wraps long messages 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo foo foo foo foo foo foo\n\u001b[32m│\u001b[39m   foo foo foo foo foo foo \n\u001b[32m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = false) > wraps long results 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mopt0\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > correctly limits options when message wraps to multiple lines 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  This is a very \n\u001b[36m│\u001b[39m  long message that\n\u001b[36m│\u001b[39m   will wrap to \n\u001b[36m│\u001b[39m  multiple lines\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 2\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 3\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=6>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 4\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 5\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  This is a very \n\u001b[32m│\u001b[39m  long message that\n\u001b[32m│\u001b[39m   will wrap to \n\u001b[32m│\u001b[39m  multiple lines\n\u001b[90m│\u001b[39m  \u001b[2mOption 4\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > correctly limits options with explicit multiline message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Choose an option:\n\u001b[36m│\u001b[39m  Line 2 of the message\n\u001b[36m│\u001b[39m  Line 3 of the message\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=5>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 2\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 3\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=4>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 3\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 4\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=10>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Choose an option:\n\u001b[32m│\u001b[39m  Line 2 of the message\n\u001b[32m│\u001b[39m  Line 3 of the message\n\u001b[90m│\u001b[39m  \u001b[2mOption 3\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > down arrow selects next option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m opt0\n\u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > handles mixed size re-renders 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Whatever\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  Long Option\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=12>\",\n  \"<erase.down>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  Whatever\n\u001b[36m│\u001b[39m  \u001b[2m...\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 2\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 3\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=8>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  Whatever\n\u001b[90m│\u001b[39m  \u001b[2mOption 3\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > renders disabled options 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[90mOption 0\u001b[39m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m│\u001b[39m  \u001b[90m○\u001b[39m \u001b[90mOption 2\u001b[39m \u001b[2m(Hint 2)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > renders multi-line option labels 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  with multiple lines\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2mwith multiple lines\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=6>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 1\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > renders option hints 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0 \u001b[2m(Hint 0)\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > renders option labels 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m Option 0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mOption 0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > renders options and message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > up arrow selects previous option 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt0\u001b[22m\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt1\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=2>\",\n  \"<erase.down>\",\n  \"\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=5>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[32m●\u001b[39m opt0\n\u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > wraps long cancelled message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > wraps long messages 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m opt0\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mopt1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=7>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo foo foo foo foo foo foo\n\u001b[32m│\u001b[39m   foo foo foo foo foo foo \n\u001b[32m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[90m│\u001b[39m  \u001b[2mopt0\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`select (isCI = true) > wraps long results 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[32m●\u001b[39m foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo foo foo \n\u001b[36m│\u001b[39m  foo foo foo foo foo foo foo\n\u001b[36m│\u001b[39m   foo foo foo foo\n\u001b[36m│\u001b[39m  \u001b[2m○\u001b[22m \u001b[2mOption 1\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=9>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo foo foo foo\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m foo foo foo foo foo foo \u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mfoo foo foo foo\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/spinner.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`spinner (isCI = false) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Canceled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > clear > stops and clears the spinner from the output 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  Loading\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[35m◒\u001b[39m  foo\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > indicator customization > custom delay 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◓\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◑\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > indicator customization > custom frame style 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m◐\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m◓\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m◑\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > indicator customization > custom frames 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m🐴\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m🦋\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m🐙\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m🐶\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > indicator customization > custom frames with lots of frame have consistent ellipsis display 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m0\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m1\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m2\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m3\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m4\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m5\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m6\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m7\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m8\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m9\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m0\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m1\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m2\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m3\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m4\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m5\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m6\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m7\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m8\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m9\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m0\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m1\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m2\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m3\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m4\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m5\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m6\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m7\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m8\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m9\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m0\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m1\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m2\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m3\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m4\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m5\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m6\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m7\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m8\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m9\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m0\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m1\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m2\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m3\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m4\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m5\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m6\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m7\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m8\u001b[39m  .\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m9\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m0\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m1\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m2\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m3\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m4\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m5\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m6\u001b[39m  ..\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m7\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m8\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m9\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m0\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m1\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m2\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m3\u001b[39m  ...\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > message > sets message for next frame 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  foo\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > process exit handling > prioritizes cancel option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Spinner cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > process exit handling > prioritizes error option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Spinner error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > process exit handling > uses custom cancel message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Custom cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > process exit handling > uses custom error message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Custom error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > process exit handling > uses default cancel message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Canceled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > process exit handling > uses global custom cancel message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Global cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > process exit handling > uses global custom error message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Global error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > start > handles multi-line messages 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  foo\nbar\nbaz\",\n  \"<cursor.up count=2>\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > start > handles wrapping 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxx\",\n  \"<cursor.up count=1>\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  stopped\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > start > renders frames at interval 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◓\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◑\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > start > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  foo\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > start > renders timer when indicator is \"timer\" 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m   [0s]\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m   [0s]\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > stop > renders cancel symbol when calling cancel() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > stop > renders error symbol when calling error() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > stop > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > stop > renders message when cancelling 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  too dizzy — spinning cancelled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > stop > renders message when erroring 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  error: spun too fast!\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > stop > renders message without removing dots 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo.\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > stop > renders submit symbol and stops spinner 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  \",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = false) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[35m◒\u001b[39m  foo\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Canceled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > clear > stops and clears the spinner from the output 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  Loading...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[35m◒\u001b[39m  foo...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > indicator customization > custom delay 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > indicator customization > custom frame style 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > indicator customization > custom frames 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m🐴\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > indicator customization > custom frames with lots of frame have consistent ellipsis display 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m0\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > message > sets message for next frame 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[35m◐\u001b[39m  foo...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > process exit handling > prioritizes cancel option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Spinner cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > process exit handling > prioritizes error option over global setting 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Spinner error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > process exit handling > uses custom cancel message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Custom cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > process exit handling > uses custom error message when provided directly 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Custom error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > process exit handling > uses default cancel message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Canceled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > process exit handling > uses global custom cancel message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m■\u001b[39m  Global cancel message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > process exit handling > uses global custom error message from settings 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[31m▲\u001b[39m  Global error message\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > start > handles multi-line messages 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  foo\nbar\nbaz...\",\n  \"\n\",\n  \"<cursor.up count=2>\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > start > handles wrapping 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nxxxxxxxxxxxxx...\",\n  \"\n\",\n  \"<cursor.up count=1>\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  stopped\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > start > renders frames at interval 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > start > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  foo...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > start > renders timer when indicator is \"timer\" 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m   [0s]\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > stop > renders cancel symbol when calling cancel() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > stop > renders error symbol when calling error() 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > stop > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > stop > renders message when cancelling 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  too dizzy — spinning cancelled\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > stop > renders message when erroring 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m▲\u001b[39m  error: spun too fast!\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > stop > renders message without removing dots 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo.\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > stop > renders submit symbol and stops spinner 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[35m◒\u001b[39m  ...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`spinner (isCI = true) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[35m◒\u001b[39m  foo...\",\n  \"\n\",\n  \"<cursor.left count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  \n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/task-log.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`taskLog (isCI = false) > error > clears output if showLog = false 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  some error!\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > error > renders output with message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  some error!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > applies limit per group 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 4\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 4\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 4\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > can render multiple groups of different sizes 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 4\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > can render multiple groups of equal size 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 4\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 4\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 4\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > handles empty groups 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◆\u001b[39m  Group success!\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > renders error state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[31m■\u001b[39m  Group error!\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > renders group error state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[31m■\u001b[39m  Group error!\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > renders group success state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[32m◆\u001b[39m  Group success!\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > renders success state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[32m◆\u001b[39m  Group success!\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > group > showLog shows all groups in order 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 4\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[32m◆\u001b[39m  Group 0 success!\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 4\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[32m◆\u001b[39m  Group 0 success!\n\",\n  \"\u001b[31m■\u001b[39m  Group 1 error!\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  overall error\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 4\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > can write line by line 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > can write multiple lines 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > destructive ansi codes are stripped 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2 bad ansi!\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2 bad ansi!\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > enforces limit if set 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > prints empty lines 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2m\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > raw = true appends message text until newline 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0still line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0still line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > raw = true works when mixed with non-raw messages 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0still line 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0still line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > message > raw = true works when started with non-raw messages 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1still line 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > error > outputs limited log with limit by default 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > error > retainLog = false outputs full log without limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > error > retainLog = false outputs limited log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > error > retainLog = true outputs full log 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > error > retainLog = true outputs full log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > success > outputs limited log with limit by default 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > success > retainLog = false outputs full log without limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > success > retainLog = false outputs limited log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > success > retainLog = true outputs full log 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > retainLog > success > retainLog = true outputs full log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > success > clears output and renders message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  success!\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > success > renders output if showLog = true 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  success!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = false) > writes message header 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > error > clears output if showLog = false 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  some error!\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > error > renders output with message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  some error!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > applies limit per group 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > can render multiple groups of different sizes 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > can render multiple groups of equal size 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > handles empty groups 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > renders error state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > renders group error state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > renders group success state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > renders success state 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > group > showLog shows all groups in order 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  Some log\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  overall error\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 0\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 0 line 2\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m  \u001b[1mGroup 1\u001b[22m\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 3\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mGroup 1 line 4\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > can write line by line 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > can write multiple lines 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > destructive ansi codes are stripped 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > enforces limit if set 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > prints empty lines 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > raw = true appends message text until newline 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > raw = true works when mixed with non-raw messages 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > message > raw = true works when started with non-raw messages 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > error > outputs limited log with limit by default 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > error > retainLog = false outputs full log without limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > error > retainLog = false outputs limited log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > error > retainLog = true outputs full log 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > error > retainLog = true outputs full log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[31m■\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > success > outputs limited log with limit by default 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > success > retainLog = false outputs full log without limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > success > retainLog = false outputs limited log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > success > retainLog = true outputs full log 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > retainLog > success > retainLog = true outputs full log with limit 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  woo!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 2\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 3\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > success > clears output and renders message 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  success!\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > success > renders output if showLog = true 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"<erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.up count=1><erase.line><cursor.left count=1>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[32m◆\u001b[39m  success!\n\",\n  \"\u001b[90m│\u001b[39m\n\u001b[90m│\u001b[39m  \u001b[2mline 0\u001b[22m\n\u001b[90m│\u001b[39m  \u001b[2mline 1\u001b[22m\n\",\n]\n`;\n\nexports[`taskLog (isCI = true) > writes message header 1`] = `\n[\n  \"\u001b[90m│\u001b[39m\n\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\u001b[90m│\u001b[39m\n\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/__snapshots__/text.test.ts.snap",
    "content": "// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html\n\nexports[`text (isCI = false) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > defaultValue sets the value but does not render 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mbar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > empty string when no value and no default 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m \u001b[27m\u001b[2m (hit Enter to use default)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > placeholder is not used as value when pressing enter 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m \u001b[27m\u001b[2m (hit Enter to use default)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mdefault-value\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > renders cancelled value if one set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  xy█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mxy\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > renders placeholder if set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7mb\u001b[27m\u001b[2mar\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > renders submitted value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  xy█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mxy\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > validation errors render and clear (using Error) 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  x█\n\u001b[33m└\u001b[39m  \u001b[33mshould be xy\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  xy█\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mxy\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > validation errors render and clear 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  x█\n\u001b[33m└\u001b[39m  \u001b[33mshould be xy\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  xy█\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mxy\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = false) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > can be aborted by a signal 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > can cancel 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > defaultValue sets the value but does not render 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mbar\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > empty string when no value and no default 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m \u001b[27m\u001b[2m (hit Enter to use default)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > global withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > placeholder is not used as value when pressing enter 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m \u001b[27m\u001b[2m (hit Enter to use default)\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mdefault-value\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > renders cancelled value if one set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  xy█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[31m■\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[9m\u001b[2mxy\u001b[22m\u001b[29m\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > renders message 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > renders placeholder if set 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7mb\u001b[27m\u001b[2mar\u001b[22m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > renders submitted value 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  xy█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mxy\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > validation errors render and clear (using Error) 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  x█\n\u001b[33m└\u001b[39m  \u001b[33mshould be xy\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  xy█\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mxy\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > validation errors render and clear 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[90m│\u001b[39m\n\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  \u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=2>\",\n  \"<erase.line><cursor.left count=1>\",\n  \"\u001b[36m│\u001b[39m  x█\",\n  \"<cursor.down count=2>\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[33m▲\u001b[39m  foo\n\u001b[33m│\u001b[39m  x█\n\u001b[33m└\u001b[39m  \u001b[33mshould be xy\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[36m│\u001b[39m  xy█\n\u001b[36m└\u001b[39m\n\",\n  \"<cursor.backward count=999><cursor.up count=4>\",\n  \"<cursor.down count=1>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\u001b[90m│\u001b[39m  \u001b[2mxy\u001b[22m\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n\nexports[`text (isCI = true) > withGuide: false removes guide 1`] = `\n[\n  \"<cursor.hide>\",\n  \"\u001b[36m◆\u001b[39m  foo\n\u001b[7m\u001b[8m_\u001b[28m\u001b[27m\n\n\",\n  \"<cursor.backward count=999><cursor.up count=3>\",\n  \"<erase.down>\",\n  \"\u001b[32m◇\u001b[39m  foo\n\",\n  \"\n\",\n  \"<cursor.show>\",\n]\n`;\n"
  },
  {
    "path": "packages/prompts/test/autocomplete.test.ts",
    "content": "import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';\nimport { autocomplete, autocompleteMultiselect } from '../src/autocomplete.js';\nimport { isCancel } from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe('autocomplete', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\tconst testOptions = [\n\t\t{ value: 'apple', label: 'Apple' },\n\t\t{ value: 'banana', label: 'Banana' },\n\t\t{ value: 'cherry', label: 'Cherry' },\n\t\t{ value: 'grape', label: 'Grape' },\n\t\t{ value: 'orange', label: 'Orange' },\n\t];\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders initial UI with message and instructions', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tawait result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('limits displayed options when maxItems is set', async () => {\n\t\tconst options = [];\n\t\tfor (let i = 0; i < 10; i++) {\n\t\t\toptions.push({ value: `option ${i}`, label: `Option ${i}` });\n\t\t}\n\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select an option',\n\t\t\toptions,\n\t\t\tmaxItems: 6,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tawait result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('shows no matches message when search has no results', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Type something that won't match\n\t\tinput.emit('keypress', 'z', { name: 'z' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tawait result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('shows hint when option has hint and is focused', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: [...testOptions, { value: 'kiwi', label: 'Kiwi', hint: 'New Zealand' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Navigate to the option with hint\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tawait result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('shows selected value in submit state', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Select an option and submit\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toBe('banana');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('shows strikethrough in cancel state', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Cancel with Ctrl+C\n\t\tinput.emit('keypress', '\\x03', { name: 'c', ctrl: true });\n\n\t\tconst value = await result;\n\t\texpect(typeof value === 'symbol').toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders placeholder if set', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\tplaceholder: 'Type to search...',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst value = await result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('apple');\n\t});\n\n\ttest('Tab with placeholder fills input and Enter submits matching option', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\tplaceholder: 'apple',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '\\t', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst value = await result;\n\t\texpect(value).toBe('apple');\n\t});\n\n\ttest('Tab with non-matching placeholder does not fill input', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\tplaceholder: 'Type to search...',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '\\t', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst value = await result;\n\t\t// Tab did not fill input with placeholder (no option matches), so Enter submits first option\n\t\texpect(value).toBe('apple');\n\t});\n\n\ttest('supports initialValue', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\tinitialValue: 'cherry',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('cherry');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'foo',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders bottom ellipsis when items do not fit', async () => {\n\t\toutput.rows = 5;\n\n\t\tconst options = [\n\t\t\t{\n\t\t\t\tvalue: Array.from({ length: 4 })\n\t\t\t\t\t.map((_val, index) => `Line ${index}`)\n\t\t\t\t\t.join('\\n'),\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue: 'Option 2',\n\t\t\t},\n\t\t];\n\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select an option',\n\t\t\toptions,\n\t\t\tmaxItems: 5,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tawait result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders top ellipsis when scrolled down and its do not fit', async () => {\n\t\toutput.rows = 5;\n\n\t\tconst options = [\n\t\t\t{\n\t\t\t\tvalue: 'option1',\n\t\t\t\tlabel: Array.from({ length: 4 })\n\t\t\t\t\t.map((_val, index) => `Line ${index}`)\n\t\t\t\t\t.join('\\n'),\n\t\t\t},\n\t\t\t{\n\t\t\t\tvalue: 'option2',\n\t\t\t\tlabel: 'Option 2',\n\t\t\t},\n\t\t];\n\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select an option',\n\t\t\toptions,\n\t\t\tinitialValue: 'option2',\n\t\t\tmaxItems: 5,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tawait result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('placeholder is shown if set', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\tplaceholder: 'Type to search...',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'g', { name: 'g' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst value = await result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('grape');\n\t});\n\n\ttest('displays disabled options correctly', async () => {\n\t\tconst optionsWithDisabled = [...testOptions, { value: 'kiwi', label: 'Kiwi', disabled: true }];\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: optionsWithDisabled,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tfor (let i = 0; i < 5; i++) {\n\t\t\tinput.emit('keypress', '', { name: 'down' });\n\t\t}\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toBe('apple');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('cannot select disabled options when only one left', async () => {\n\t\tconst optionsWithDisabled = [...testOptions, { value: 'kiwi', label: 'Kiwi', disabled: true }];\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: optionsWithDisabled,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'k', { name: 'k' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toBe(undefined);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n\ndescribe('autocompleteMultiselect', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\tconst testOptions = [\n\t\t{ value: 'apple', label: 'Apple' },\n\t\t{ value: 'banana', label: 'Banana' },\n\t\t{ value: 'cherry', label: 'Cherry' },\n\t\t{ value: 'grape', label: 'Grape' },\n\t\t{ value: 'orange', label: 'Orange' },\n\t];\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders error when empty selection & required is true', async () => {\n\t\tconst result = autocompleteMultiselect({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\trequired: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tinput.emit('keypress', '', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tawait result;\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = autocompleteMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can use navigation keys to select options', async () => {\n\t\tconst result = autocompleteMultiselect({\n\t\t\tmessage: 'Select fruits',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toEqual(['banana', 'cherry']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('supports custom filter function', async () => {\n\t\tconst result = autocompleteMultiselect({\n\t\t\tmessage: 'Select fruits',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\t// Custom filter that only matches exact prefix\n\t\t\tfilter: (search, option) => {\n\t\t\t\tconst label = option.label ?? String(option.value ?? '');\n\t\t\t\treturn label.toLowerCase().startsWith(search.toLowerCase());\n\t\t\t},\n\t\t});\n\n\t\t// Type 'a' - should match 'Apple' only (not 'Banana' which contains 'a')\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\tinput.emit('keypress', '', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toEqual(['apple']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('displays disabled options correctly', async () => {\n\t\tconst optionsWithDisabled = [...testOptions, { value: 'kiwi', label: 'Kiwi', disabled: true }];\n\t\tconst result = autocompleteMultiselect({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: optionsWithDisabled,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tfor (let i = 0; i < testOptions.length; i++) {\n\t\t\tinput.emit('keypress', '', { name: 'down' });\n\t\t}\n\t\tinput.emit('keypress', '', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toEqual(['apple']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('cannot select disabled options when only one left', async () => {\n\t\tconst optionsWithDisabled = [...testOptions, { value: 'kiwi', label: 'Kiwi', disabled: true }];\n\t\tconst result = autocompleteMultiselect({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: optionsWithDisabled,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'k', { name: 'k' });\n\t\tinput.emit('keypress', '', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toEqual([]);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('Tab with placeholder fills input; Enter submits current selection', async () => {\n\t\tconst result = autocompleteMultiselect({\n\t\t\tmessage: 'Select fruits',\n\t\t\tplaceholder: 'apple',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '\\t', { name: 'tab' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tconst value = await result;\n\t\texpect(value).toEqual([]);\n\t});\n});\n\ndescribe('autocomplete with custom filter', () => {\n\tlet input: MockReadable;\n\tlet output: MockWritable;\n\tconst testOptions = [\n\t\t{ value: 'apple', label: 'Apple' },\n\t\t{ value: 'banana', label: 'Banana' },\n\t\t{ value: 'cherry', label: 'Cherry' },\n\t];\n\n\tbeforeEach(() => {\n\t\tinput = new MockReadable();\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('uses custom filter function when provided', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t\t// Custom filter that only matches exact prefix\n\t\t\tfilter: (search, option) => {\n\t\t\t\tconst label = option.label ?? String(option.value ?? '');\n\t\t\t\treturn label.toLowerCase().startsWith(search.toLowerCase());\n\t\t\t},\n\t\t});\n\n\t\t// Type 'a' - should match 'Apple' only (not 'Banana' which contains 'a')\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\texpect(value).toBe('apple');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('falls back to default filter when not provided', async () => {\n\t\tconst result = autocomplete({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: testOptions,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Type 'a' - default filter should match both 'Apple' and 'Banana'\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\t\t// First match should be selected\n\t\texpect(value).toBe('apple');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/box.test.ts",
    "content": "import { styleText } from 'node:util';\nimport { updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('box (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('renders message', () => {\n\t\tprompts.box('message', undefined, {\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders message with title', () => {\n\t\tprompts.box('message', 'some title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders as wide as longest line with width: auto', () => {\n\t\tprompts.box('short\\nsomewhat questionably long line', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders as specified width', () => {\n\t\tprompts.box('short\\nsomewhat questionably long line', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 0.5,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('wraps content to fit within specified width', () => {\n\t\tprompts.box('foo bar'.repeat(20), 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 0.5,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders specified titlePadding', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\ttitlePadding: 6,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders specified contentPadding', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tcontentPadding: 6,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders without guide when withGuide is false', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twithGuide: false,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders without guide when global withGuide is false', () => {\n\t\tupdateSettings({ withGuide: false });\n\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders truncated long titles', () => {\n\t\tprompts.box('message', 'foo'.repeat(20), {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 0.2,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('cannot have width larger than 100%', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 1.1,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders rounded corners when rounded is true', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\trounded: true,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders auto width with content longer than title', () => {\n\t\tprompts.box('message'.repeat(4), 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders auto width with title longer than content', () => {\n\t\tprompts.box('message', 'title'.repeat(4), {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders left aligned title', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\ttitleAlign: 'left',\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders right aligned title', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\ttitleAlign: 'right',\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders center aligned title', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\ttitleAlign: 'center',\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders left aligned content', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tcontentAlign: 'left',\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders right aligned content', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tcontentAlign: 'right',\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders center aligned content', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tcontentAlign: 'center',\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders with formatBorder formatting', () => {\n\t\tprompts.box('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 'auto',\n\t\t\tformatBorder: (text: string) => styleText('red', text),\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders wide characters with auto width', () => {\n\t\tconst messages = ['이게 첫 번째 줄이에요', 'これは次の行です'];\n\t\tprompts.box(messages.join('\\n'), '这是标题', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 'auto',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders wide characters with specified width', () => {\n\t\tconst messages = ['이게 첫 번째 줄이에요', 'これは次の行です'];\n\t\tprompts.box(messages.join('\\n'), '这是标题', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twidth: 0.2,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/confirm.test.ts",
    "content": "import { updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('confirm (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('renders message with choices', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders custom active choice', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tactive: 'bleep',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders custom inactive choice', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tinactive: 'bleep',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders options in vertical alignment', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tvertical: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('right arrow moves to next choice', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'right', { name: 'right' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe(false);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('left arrow moves to previous choice', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'right', { name: 'right' });\n\t\tinput.emit('keypress', 'left', { name: 'left' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can cancel', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can set initialValue', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tinitialValue: false,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe(false);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'yes?',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('withGuide: false removes guide', async () => {\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\twithGuide: false,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('global withGuide: false removes guide', async () => {\n\t\tupdateSettings({ withGuide: false });\n\n\t\tconst result = prompts.confirm({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/date.test.ts",
    "content": "import { updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\nconst d = (iso: string) => {\n\tconst [y, m, day] = iso.slice(0, 10).split('-').map(Number);\n\treturn new Date(Date.UTC(y, m - 1, day));\n};\n\ndescribe.each(['true', 'false'])('date (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('renders message', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders initial value', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBeInstanceOf(Date);\n\t\texpect((value as Date).toISOString().slice(0, 10)).toBe('2025-01-15');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can cancel', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders submitted value', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\tinitialValue: d('2025-06-15'),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBeInstanceOf(Date);\n\t\texpect((value as Date).toISOString().slice(0, 10)).toBe('2025-06-15');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('defaultValue used when empty submit', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\tdefaultValue: d('2025-12-25'),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBeInstanceOf(Date);\n\t\texpect((value as Date).toISOString().slice(0, 10)).toBe('2025-12-25');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('withGuide: false removes guide', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\twithGuide: false,\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('supports MDY format', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\tformat: 'MDY',\n\t\t\tinitialValue: d('2025-01-15'),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBeInstanceOf(Date);\n\t\texpect((value as Date).toISOString().slice(0, 10)).toBe('2025-01-15');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('minDate shows error when date before min and submit', async () => {\n\t\tconst result = prompts.date({\n\t\t\tmessage: 'Pick a date',\n\t\t\tinitialValue: d('2025-01-10'),\n\t\t\tminDate: d('2025-01-15'),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', undefined, { name: 'return' });\n\t\tawait new Promise((r) => setImmediate(r));\n\n\t\tconst hasError = output.buffer.some(\n\t\t\t(s) => typeof s === 'string' && s.includes('Date must be on or after')\n\t\t);\n\t\texpect(hasError).toBe(true);\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\t\tconst value = await result;\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/group-multi-select.test.ts",
    "content": "import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('groupMultiselect (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders message with options', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t\tgroup2: [{ value: 'group2value0' }],\n\t\t\t},\n\t\t});\n\n\t\t// Select the first non-group option\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\n\t\t// submit\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can select multiple options', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }, { value: 'group1value2' }],\n\t\t\t},\n\t\t});\n\n\t\t// Select the first non-group option\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t// Select the second non-group option\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\n\t\t// submit\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value0', 'group1value1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can select a group', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t},\n\t\t});\n\n\t\t// Select the group as a whole\n\t\tinput.emit('keypress', '', { name: 'space' });\n\n\t\t// submit\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value0', 'group1value1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can select a group by selecting all members', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t},\n\t\t});\n\n\t\t// Select the first group option\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t// Select the second group option\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\n\t\t// submit\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value0', 'group1value1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can deselect an option', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t},\n\t\t});\n\n\t\t// Select the first group option\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t// Select the second group option\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t// Deselect it\n\t\tinput.emit('keypress', '', { name: 'space' });\n\n\t\t// submit\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders error when nothing selected', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t},\n\t\t});\n\n\t\t// try submit\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t// now select something and submit\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\tdescribe('selectableGroups = false', () => {\n\t\ttest('cannot select groups', async () => {\n\t\t\tconst result = prompts.groupMultiselect({\n\t\t\t\tmessage: 'foo',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\toptions: {\n\t\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t\t},\n\t\t\t\tselectableGroups: false,\n\t\t\t});\n\n\t\t\t// first selectable item should be group's child\n\t\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\t\tconst value = await result;\n\n\t\t\texpect(value).toEqual(['group1value0']);\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('selecting all members of group does not select group', async () => {\n\t\t\tconst result = prompts.groupMultiselect({\n\t\t\t\tmessage: 'foo',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\toptions: {\n\t\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t\t},\n\t\t\t\tselectableGroups: false,\n\t\t\t});\n\n\t\t\t// first selectable item should be group's child\n\t\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t\t// select second item\n\t\t\tinput.emit('keypress', '', { name: 'down' });\n\t\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t\t// submit\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\t\tconst value = await result;\n\n\t\t\texpect(value).toEqual(['group1value0', 'group1value1']);\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\ttest('can submit empty selection when require = false', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t},\n\t\t\trequired: false,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual([]);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('cursorAt sets initial selection', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t},\n\t\t\tcursorAt: 'group1value1',\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('initial values can be set', async () => {\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }, { value: 'group1value1' }],\n\t\t\t},\n\t\t\tinitialValues: ['group1value1'],\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['group1value1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('values can be non-primitive', async () => {\n\t\tconst value0 = Symbol();\n\t\tconst value1 = Symbol();\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\toptions: {\n\t\t\t\tgroup1: [\n\t\t\t\t\t{ value: value0, label: 'value0' },\n\t\t\t\t\t{ value: value1, label: 'value1' },\n\t\t\t\t],\n\t\t\t},\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual([value0]);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\tdescribe('groupSpacing', () => {\n\t\ttest('renders spaced groups', async () => {\n\t\t\tconst result = prompts.groupMultiselect({\n\t\t\t\tmessage: 'foo',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\toptions: {\n\t\t\t\t\tgroup1: [{ value: 'group1value0' }],\n\t\t\t\t\tgroup2: [{ value: 'group2value0' }],\n\t\t\t\t},\n\t\t\t\tgroupSpacing: 2,\n\t\t\t});\n\n\t\t\tinput.emit('keypress', '', { name: 'down' });\n\t\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\t\tawait result;\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('negative spacing is ignored', async () => {\n\t\t\tconst result = prompts.groupMultiselect({\n\t\t\t\tmessage: 'foo',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\toptions: {\n\t\t\t\t\tgroup1: [{ value: 'group1value0' }],\n\t\t\t\t\tgroup2: [{ value: 'group2value0' }],\n\t\t\t\t},\n\t\t\t\tgroupSpacing: -2,\n\t\t\t});\n\n\t\t\tinput.emit('keypress', '', { name: 'down' });\n\t\t\tinput.emit('keypress', '', { name: 'space' });\n\t\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\t\tawait result;\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = prompts.groupMultiselect({\n\t\t\tmessage: 'Select a fruit',\n\t\t\toptions: {\n\t\t\t\tgroup1: [{ value: 'group1value0' }],\n\t\t\t\tgroup2: [{ value: 'group2value0' }],\n\t\t\t},\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/limit-options.test.ts",
    "content": "import { styleText } from 'node:util';\nimport { beforeEach, describe, expect, test } from 'vitest';\nimport { type LimitOptionsParams, limitOptions } from '../src/index.js';\nimport { MockWritable } from './test-utils.js';\n\ndescribe('limitOptions', () => {\n\tlet output: MockWritable;\n\tlet options: LimitOptionsParams<{ value: string }>;\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\toptions = {\n\t\t\toutput,\n\t\t\toptions: [],\n\t\t\tmaxItems: undefined,\n\t\t\tcursor: 0,\n\t\t\tstyle: (option) => option.value,\n\t\t\tcolumnPadding: undefined,\n\t\t\trowPadding: undefined,\n\t\t};\n\t});\n\n\ttest('returns all items if they fit', async () => {\n\t\toptions.options = [{ value: 'Item 1' }, { value: 'Item 2' }, { value: 'Item 3' }];\n\t\toptions.maxItems = 5;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual(['Item 1', 'Item 2', 'Item 3']);\n\t});\n\n\ttest('clamps to 5 rows minimum', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t];\n\t\toptions.maxItems = 3;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual(['Item 1', 'Item 2', 'Item 3', 'Item 4', styleText('dim', '...')]);\n\t});\n\n\ttest('returns sliding window when cursor moves down', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{ value: 'Item 8' },\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toutput.rows = 20;\n\t\toptions.maxItems = 5;\n\t\toptions.cursor = 6;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([\n\t\t\tstyleText('dim', '...'),\n\t\t\t'Item 6',\n\t\t\t'Item 7',\n\t\t\t'Item 8',\n\t\t\tstyleText('dim', '...'),\n\t\t]);\n\t});\n\n\ttest('returns sliding window near end of list', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{ value: 'Item 8' },\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toptions.maxItems = 5;\n\t\toptions.cursor = 8;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([styleText('dim', '...'), 'Item 7', 'Item 8', 'Item 9', 'Item 10']);\n\t});\n\n\ttest('handles empty options list', async () => {\n\t\toptions.options = [];\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([]);\n\t});\n\n\ttest('if items exceed output height, clamp to fit', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{ value: 'Item 8' },\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toutput.rows = 7;\n\t\toptions.maxItems = 10;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual(['Item 1', 'Item 2', styleText('dim', '...')]);\n\t});\n\n\ttest('handle multi-line item clamping (start)', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{\n\t\t\t\tvalue: Array.from({ length: 4 })\n\t\t\t\t\t.map((_val, index) => `A long item that will take up a lot of space (line ${index})`)\n\t\t\t\t\t.join('\\n'),\n\t\t\t},\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{ value: 'Item 8' },\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toutput.rows = 14;\n\t\toptions.maxItems = 10;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([\n\t\t\t'Item 1',\n\t\t\t'Item 2',\n\t\t\t'A long item that will take up a lot of space (line 0)',\n\t\t\t'A long item that will take up a lot of space (line 1)',\n\t\t\t'A long item that will take up a lot of space (line 2)',\n\t\t\t'A long item that will take up a lot of space (line 3)',\n\t\t\t'Item 4',\n\t\t\t'Item 5',\n\t\t\t'Item 6',\n\t\t\t'Item 7',\n\t\t\t'Item 8',\n\t\t\tstyleText('dim', '...'),\n\t\t]);\n\t});\n\n\ttest('handle multi-line item clamping (middle)', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{\n\t\t\t\tvalue: Array.from({ length: 4 })\n\t\t\t\t\t.map((_val, index) => `A long item that will take up a lot of space (line ${index})`)\n\t\t\t\t\t.join('\\n'),\n\t\t\t},\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{ value: 'Item 8' },\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toutput.rows = 14;\n\t\toptions.maxItems = 10;\n\t\toptions.cursor = 7;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([\n\t\t\tstyleText('dim', '...'),\n\t\t\t'Item 2',\n\t\t\t'Item 3',\n\t\t\t'Item 4',\n\t\t\t'A long item that will take up a lot of space (line 0)',\n\t\t\t'A long item that will take up a lot of space (line 1)',\n\t\t\t'A long item that will take up a lot of space (line 2)',\n\t\t\t'A long item that will take up a lot of space (line 3)',\n\t\t\t'Item 6',\n\t\t\t'Item 7',\n\t\t\t'Item 8',\n\t\t\tstyleText('dim', '...'),\n\t\t]);\n\t});\n\n\ttest('handle multi-line item clamping (end)', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{\n\t\t\t\tvalue: Array.from({ length: 4 })\n\t\t\t\t\t.map((_val, index) => `A long item that will take up a lot of space (line ${index})`)\n\t\t\t\t\t.join('\\n'),\n\t\t\t},\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toutput.rows = 14;\n\t\toptions.maxItems = 10;\n\t\toptions.cursor = 9;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([\n\t\t\tstyleText('dim', '...'),\n\t\t\t'Item 4',\n\t\t\t'Item 5',\n\t\t\t'Item 6',\n\t\t\t'Item 7',\n\t\t\t'A long item that will take up a lot of space (line 0)',\n\t\t\t'A long item that will take up a lot of space (line 1)',\n\t\t\t'A long item that will take up a lot of space (line 2)',\n\t\t\t'A long item that will take up a lot of space (line 3)',\n\t\t\t'Item 9',\n\t\t\t'Item 10',\n\t\t]);\n\t});\n\n\ttest('style option is used to style lines', async () => {\n\t\toptions.options = [{ value: 'Item 1' }, { value: 'Item 2' }, { value: 'Item 3' }];\n\t\toptions.maxItems = 5;\n\t\toptions.style = (option) => `-- ${option.value} --`;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual(['-- Item 1 --', '-- Item 2 --', '-- Item 3 --']);\n\t});\n\n\ttest('style option styles across multi-line items', async () => {\n\t\toptions.options = [{ value: 'Item 1' }, { value: 'Item 2' }, { value: 'Item 3\\nContinued' }];\n\t\toptions.maxItems = 5;\n\t\toptions.style = (option) => `-- ${option.value} --`;\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual(['-- Item 1 --', '-- Item 2 --', '-- Item 3', 'Continued --']);\n\t});\n\n\ttest('style option receives correct cursor index', async () => {\n\t\toptions.options = [{ value: 'Item 1' }, { value: 'Item 2' }, { value: 'Item 3' }];\n\t\toptions.maxItems = 5;\n\t\toptions.cursor = 1;\n\t\toptions.style = (option, isSelected) => {\n\t\t\treturn isSelected ? `-- ${option.value} --` : option.value;\n\t\t};\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual(['Item 1', '-- Item 2 --', 'Item 3']);\n\t});\n\n\ttest('respects custom rowPadding', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{ value: 'Item 8' },\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toutput.rows = 12;\n\t\toptions.rowPadding = 6;\n\t\t// Available rows for options = 12 - 6 = 6\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([\n\t\t\t'Item 1',\n\t\t\t'Item 2',\n\t\t\t'Item 3',\n\t\t\t'Item 4',\n\t\t\t'Item 5',\n\t\t\tstyleText('dim', '...'),\n\t\t]);\n\t});\n\n\ttest('respects custom rowPadding when scrolling', async () => {\n\t\toptions.options = [\n\t\t\t{ value: 'Item 1' },\n\t\t\t{ value: 'Item 2' },\n\t\t\t{ value: 'Item 3' },\n\t\t\t{ value: 'Item 4' },\n\t\t\t{ value: 'Item 5' },\n\t\t\t{ value: 'Item 6' },\n\t\t\t{ value: 'Item 7' },\n\t\t\t{ value: 'Item 8' },\n\t\t\t{ value: 'Item 9' },\n\t\t\t{ value: 'Item 10' },\n\t\t];\n\t\toutput.rows = 12;\n\t\t// Simulate a multiline message that takes 6 lines\n\t\toptions.rowPadding = 6;\n\t\t// Move cursor to middle of list\n\t\toptions.cursor = 5;\n\t\t// Available rows for options = 12 - 6 = 6\n\t\tconst result = limitOptions(options);\n\t\texpect(result).toEqual([\n\t\t\tstyleText('dim', '...'),\n\t\t\t'Item 4',\n\t\t\t'Item 5',\n\t\t\t'Item 6',\n\t\t\t'Item 7',\n\t\t\tstyleText('dim', '...'),\n\t\t]);\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/log.test.ts",
    "content": "import { styleText } from 'node:util';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('log (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\tdescribe('message', () => {\n\t\ttest('renders message', () => {\n\t\t\tprompts.log.message('message', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders multiline message', () => {\n\t\t\tprompts.log.message('line 1\\nline 2\\nline 3', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message from array', () => {\n\t\t\tprompts.log.message(['line 1', 'line 2', 'line 3'], {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message with custom symbols and spacing', () => {\n\t\t\tprompts.log.message('custom\\nsymbols', {\n\t\t\t\tsymbol: styleText('red', '>>'),\n\t\t\t\tsecondarySymbol: styleText('yellow', '--'),\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message with guide disabled', () => {\n\t\t\tprompts.log.message('standalone message', {\n\t\t\t\twithGuide: false,\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders multiline message with guide disabled', () => {\n\t\t\tprompts.log.message('line 1\\nline 2\\nline 3', {\n\t\t\t\twithGuide: false,\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message with custom spacing', () => {\n\t\t\tprompts.log.message('spaced message', {\n\t\t\t\tspacing: 3,\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders empty message correctly', () => {\n\t\t\tprompts.log.message('', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders empty message with guide disabled', () => {\n\t\t\tprompts.log.message('', {\n\t\t\t\twithGuide: false,\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders empty lines correctly', () => {\n\t\t\tprompts.log.message('foo\\n\\nbar', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders empty lines with guide disabled', () => {\n\t\t\tprompts.log.message('foo\\n\\nbar', {\n\t\t\t\twithGuide: false,\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('info', () => {\n\t\ttest('renders info message', () => {\n\t\t\tprompts.log.info('info message', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('success', () => {\n\t\ttest('renders success message', () => {\n\t\t\tprompts.log.success('success message', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('step', () => {\n\t\ttest('renders step message', () => {\n\t\t\tprompts.log.step('step message', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('warn', () => {\n\t\ttest('renders warn message', () => {\n\t\t\tprompts.log.warn('warn message', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('error', () => {\n\t\ttest('renders error message', () => {\n\t\t\tprompts.log.error('error message', {\n\t\t\t\toutput,\n\t\t\t});\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/multi-select.test.ts",
    "content": "import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('multiselect (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders message', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders multiple selected options', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }, { value: 'opt2' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0', 'opt1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can cancel', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders validation errors', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// try submit with nothing selected\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t// select and submit\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can submit without selection when required = false', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\trequired: false,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual([]);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can set cursorAt to preselect an option', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tcursorAt: 'opt1',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can set initial values', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinitialValues: ['opt1'],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('maxItems renders a sliding window', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [...Array(12).keys()].map((k) => ({\n\t\t\t\tvalue: `opt${k}`,\n\t\t\t})),\n\t\t\tmaxItems: 6,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tfor (let i = 0; i < 6; i++) {\n\t\t\tinput.emit('keypress', '', { name: 'down' });\n\t\t}\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt6']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('sliding window loops upwards', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [...Array(12).keys()].map((k) => ({\n\t\t\t\tvalue: `opt${k}`,\n\t\t\t})),\n\t\t\tmaxItems: 6,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'up' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt11']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('sliding window loops downwards', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [...Array(12).keys()].map((k) => ({\n\t\t\t\tvalue: `opt${k}`,\n\t\t\t})),\n\t\t\tmaxItems: 6,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tfor (let i = 0; i < 12; i++) {\n\t\t\tinput.emit('keypress', '', { name: 'down' });\n\t\t}\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can set custom labels', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', label: 'Option 0' },\n\t\t\t\t{ value: 'opt1', label: 'Option 1' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can render option hints', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', hint: 'Hint 0' },\n\t\t\t\t{ value: 'opt1', hint: 'Hint 1' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('shows hints for all selected options', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', hint: 'Hint 0' },\n\t\t\t\t{ value: 'opt1', hint: 'Hint 1' },\n\t\t\t\t{ value: 'opt2', hint: 'Hint 2' },\n\t\t\t],\n\t\t\tinitialValues: ['opt0', 'opt1'],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Check that both selected options show their hints\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0', 'opt1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders multiple cancelled values', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }, { value: 'opt2' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders disabled options', async () => {\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', disabled: true },\n\t\t\t\t{ value: 'opt1' },\n\t\t\t\t{ value: 'opt2', disabled: true, hint: 'Hint 2' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt1']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('wraps long messages', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo '.repeat(20).trim(),\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('wraps cancelled state with long options', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', label: 'Option 0 '.repeat(10).trim() },\n\t\t\t\t{ value: 'opt1', label: 'Option 1 '.repeat(10).trim() },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('wraps success state with long options', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.multiselect({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', label: 'Option 0 '.repeat(10).trim() },\n\t\t\t\t{ value: 'opt1', label: 'Option 1 '.repeat(10).trim() },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'space' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual(['opt0']);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/note.test.ts",
    "content": "import { styleText } from 'node:util';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('note (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders message with title', () => {\n\t\tprompts.note('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders as wide as longest line', () => {\n\t\tprompts.note('short\\nsomewhat questionably long line', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('formatter which adds length works', () => {\n\t\tprompts.note('line 0\\nline 1\\nline 2', 'title', {\n\t\t\tformat: (line) => `* ${line} *`,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('formatter which adds colors works', () => {\n\t\tprompts.note('line 0\\nline 1\\nline 2', 'title', {\n\t\t\tformat: (line) => styleText('red', line),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest(\"don't overflow\", () => {\n\t\tconst message = `${'test string '.repeat(32)}\\n`.repeat(4).trim();\n\t\toutput.columns = 75;\n\t\tprompts.note(message, 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest(\"don't overflow with formatter\", () => {\n\t\tconst message = `${'test string '.repeat(32)}\\n`.repeat(4).trim();\n\t\toutput.columns = 75;\n\t\tprompts.note(message, 'title', {\n\t\t\tformat: (line) => styleText('red', `* ${styleText('cyan', line)} *`),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('handle wide characters', () => {\n\t\tconst messages = ['이게 첫 번째 줄이에요', 'これは次の行です'];\n\t\toutput.columns = 10;\n\t\tprompts.note(messages.join('\\n'), '这是标题', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('handle wide characters with formatter', () => {\n\t\tconst messages = ['이게 첫 번째 줄이에요', 'これは次の行です'];\n\t\toutput.columns = 10;\n\t\tprompts.note(messages.join('\\n'), '这是标题', {\n\t\t\tformat: (line) => styleText('red', `* ${styleText('cyan', line)} *`),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('without guide', () => {\n\t\tprompts.note('message', 'title', {\n\t\t\tinput,\n\t\t\toutput,\n\t\t\twithGuide: false,\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/password.test.ts",
    "content": "import { updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('password (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('renders message', async () => {\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders masked value', async () => {\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('xy');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders custom mask', async () => {\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tmask: '*',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders and clears validation errors', async () => {\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tvalidate: (value) => {\n\t\t\t\tif (!value || value.length < 2) {\n\t\t\t\t\treturn 'Password must be at least 2 characters';\n\t\t\t\t}\n\n\t\t\t\treturn undefined;\n\t\t\t},\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('xy');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders cancelled value', async () => {\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', '', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('clears input on error when clearOnError is true', async () => {\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tvalidate: (v) => (v === 'yz' ? undefined : 'Error'),\n\t\t\tclearOnError: true,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', 'z', { name: 'z' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('yz');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('withGuide: false removes guide', async () => {\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\twithGuide: false,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('global withGuide: false removes guide', async () => {\n\t\tupdateSettings({ withGuide: false });\n\n\t\tconst result = prompts.password({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/path.test.ts",
    "content": "import { vol } from 'memfs';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\nvi.mock('node:fs');\n\ndescribe.each(['true', 'false'])('text (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t\tvol.reset();\n\t\tvol.fromJSON(\n\t\t\t{\n\t\t\t\t'./foo/bar.txt': '1',\n\t\t\t\t'./foo/baz.text': '2',\n\t\t\t\t'./hello/world.jpg': '3',\n\t\t\t\t'./hello/john.jpg': '4',\n\t\t\t\t'./hello/jeanne.png': '5',\n\t\t\t\t'./root.zip': '6',\n\t\t\t\t'./bar': '7',\n\t\t\t},\n\t\t\t'/tmp'\n\t\t);\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('renders message', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\troot: '/tmp/',\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('/tmp/bar');\n\t});\n\n\ttest('can cancel', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders cancelled value if one set', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\troot: '/tmp/',\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders submitted value', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'b', { name: 'b' });\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/bar');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('cannot submit unknown value', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '_', { name: '_' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tinput.emit('keypress', '', { name: 'h', ctrl: true });\n\t\tinput.emit('keypress', 'b', { name: 'b' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/bar');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('initialValue sets the value', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\tinitialValue: '/tmp/bar',\n\t\t\troot: '/tmp/',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/bar');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('directory mode only allows selecting directories', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tdirectory: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'f', { name: 'f' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/foo');\n\t});\n\n\ttest('directory mode submits initial directory value on enter', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tinitialValue: '/tmp',\n\t\t\tdirectory: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp');\n\t});\n\n\ttest('directory mode traverses into child when trailing slash entered', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tinitialValue: '/tmp',\n\t\t\tdirectory: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '/', { name: '/' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/foo');\n\t});\n\n\ttest('directory mode can navigate from initial directory to child directory', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tinitialValue: '/tmp/',\n\t\t\tdirectory: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'f', { name: 'f' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/foo');\n\t});\n\n\ttest('default mode allows selecting files', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'r', { name: 'r' });\n\t\tinput.emit('keypress', 'o', { name: 'o' });\n\t\tinput.emit('keypress', 'o', { name: 'o' });\n\t\tinput.emit('keypress', 't', { name: 't' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/root.zip');\n\t});\n\n\ttest('validation errors render and clear', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tvalidate: (val) => (val !== '/tmp/bar' ? 'should be /tmp/bar' : undefined),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// to match `root.zip`\n\t\tinput.emit('keypress', 'r', { name: 'r' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t// delete what we had\n\t\tinput.emit('keypress', '', { name: 'h', ctrl: true });\n\t\tinput.emit('keypress', 'b', { name: 'b' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/bar');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('validation errors render and clear (using Error)', async () => {\n\t\tconst result = prompts.path({\n\t\t\tmessage: 'foo',\n\t\t\troot: '/tmp/',\n\t\t\tvalidate: (val) => (val !== '/tmp/bar' ? new Error('should be /tmp/bar') : undefined),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// to match `root.zip`\n\t\tinput.emit('keypress', 'r', { name: 'r' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\t// delete what we had\n\t\tinput.emit('keypress', '', { name: 'h', ctrl: true });\n\t\tinput.emit('keypress', 'b', { name: 'b' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('/tmp/bar');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/progress-bar.test.ts",
    "content": "import process from 'node:process';\nimport { EventEmitter } from 'node:stream';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport type { ProgressOptions } from '../src/index.js';\nimport * as prompts from '../src/index.js';\nimport { MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('prompts - progress (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tvi.useFakeTimers();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tvi.useRealTimers();\n\t});\n\n\ttest('returns progress API', () => {\n\t\tconst api = prompts.progress({ output });\n\n\t\texpect(api.stop).toBeTypeOf('function');\n\t\texpect(api.start).toBeTypeOf('function');\n\t\texpect(api.message).toBeTypeOf('function');\n\t\texpect(api.advance).toBeTypeOf('function');\n\t});\n\n\tdescribe('start', () => {\n\t\ttest('renders frames at interval', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\t// there are 4 frames\n\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\tvi.advanceTimersByTime(80);\n\t\t\t}\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start('foo');\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders timer when indicator is \"timer\"', () => {\n\t\t\tconst result = prompts.progress({ output, indicator: 'timer' });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('stop', () => {\n\t\ttest('renders submit symbol and stops progress', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders cancel symbol when calling cancel()', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.cancel();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders error symbol when calling error()', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.error();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop('foo');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message without removing dots', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop('foo.');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message when cancelling', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.cancel('cancelled :-(');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message when erroring', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.error('FATAL ERROR!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('message', () => {\n\t\ttest('sets message for next frame', () => {\n\t\t\tconst result = prompts.progress({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.message('foo');\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('process exit handling', () => {\n\t\tlet processEmitter: EventEmitter;\n\n\t\tbeforeEach(() => {\n\t\t\tprocessEmitter = new EventEmitter();\n\n\t\t\t// Spy on process methods\n\t\t\tvi.spyOn(process, 'on').mockImplementation((ev, listener) => {\n\t\t\t\tprocessEmitter.on(ev, listener);\n\t\t\t\treturn process;\n\t\t\t});\n\t\t\tvi.spyOn(process, 'removeListener').mockImplementation((ev, listener) => {\n\t\t\t\tprocessEmitter.removeListener(ev, listener);\n\t\t\t\treturn process;\n\t\t\t});\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tprocessEmitter.removeAllListeners();\n\t\t});\n\n\t\ttest('uses default cancel message', () => {\n\t\t\tconst result = prompts.progress({ output });\n\t\t\tresult.start('Test operation');\n\n\t\t\tprocessEmitter.emit('SIGINT');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('uses custom cancel message when provided directly', () => {\n\t\t\tconst result = prompts.progress({\n\t\t\t\toutput,\n\t\t\t\tcancelMessage: 'Custom cancel message',\n\t\t\t});\n\t\t\tresult.start('Test operation');\n\n\t\t\tprocessEmitter.emit('SIGINT');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('uses custom error message when provided directly', () => {\n\t\t\tconst result = prompts.progress({\n\t\t\t\toutput,\n\t\t\t\terrorMessage: 'Custom error message',\n\t\t\t});\n\t\t\tresult.start('Test operation');\n\n\t\t\tprocessEmitter.emit('exit', 2);\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('uses global custom cancel message from settings', () => {\n\t\t\t// Store original message\n\t\t\tconst originalCancelMessage = prompts.settings.messages.cancel;\n\t\t\ttry {\n\t\t\t\t// Set custom message\n\t\t\t\tprompts.settings.messages.cancel = 'Global cancel message';\n\n\t\t\t\tconst result = prompts.progress({ output });\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('SIGINT');\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original\n\t\t\t\tprompts.settings.messages.cancel = originalCancelMessage;\n\t\t\t}\n\t\t});\n\n\t\ttest('uses global custom error message from settings', () => {\n\t\t\t// Store original message\n\t\t\tconst originalErrorMessage = prompts.settings.messages.error;\n\t\t\ttry {\n\t\t\t\t// Set custom message\n\t\t\t\tprompts.settings.messages.error = 'Global error message';\n\n\t\t\t\tconst result = prompts.progress({ output });\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('exit', 2);\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original\n\t\t\t\tprompts.settings.messages.error = originalErrorMessage;\n\t\t\t}\n\t\t});\n\n\t\ttest('prioritizes error option over global setting', () => {\n\t\t\t// Store original messages\n\t\t\tconst originalErrorMessage = prompts.settings.messages.error;\n\n\t\t\ttry {\n\t\t\t\t// Set custom global messages\n\t\t\t\tprompts.settings.messages.error = 'Global error message';\n\n\t\t\t\tconst result = prompts.progress({\n\t\t\t\t\toutput,\n\t\t\t\t\terrorMessage: 'Progress error message',\n\t\t\t\t});\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('exit', 2);\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original values\n\t\t\t\tprompts.settings.messages.error = originalErrorMessage;\n\t\t\t}\n\t\t});\n\n\t\ttest('prioritizes cancel option over global setting', () => {\n\t\t\t// Store original messages\n\t\t\tconst originalCancelMessage = prompts.settings.messages.cancel;\n\n\t\t\ttry {\n\t\t\t\t// Set custom global messages\n\t\t\t\tprompts.settings.messages.cancel = 'Global cancel message';\n\n\t\t\t\tconst result = prompts.progress({\n\t\t\t\t\toutput,\n\t\t\t\t\tcancelMessage: 'Progress cancel message',\n\t\t\t\t});\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('SIGINT');\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original values\n\t\t\t\tprompts.settings.messages.cancel = originalCancelMessage;\n\t\t\t}\n\t\t});\n\t});\n\n\tdescribe('style', () => {\n\t\ttest.each(['block', 'heavy', 'light'] satisfies Array<ProgressOptions['style']>)(\n\t\t\t'renders %s progressbar',\n\t\t\t(style) => {\n\t\t\t\tconst result = prompts.progress({ output, style, max: 2, size: 10 });\n\t\t\t\tresult.start();\n\t\t\t\tvi.advanceTimersByTime(160);\n\t\t\t\tresult.advance();\n\t\t\t\tvi.advanceTimersByTime(160);\n\t\t\t\tresult.stop();\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t}\n\t\t);\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/select-key.test.ts",
    "content": "import { updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('text (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('renders message with options', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'a' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe(undefined);\n\t});\n\n\ttest('selects option by keypress', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'a' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'b', { name: 'b' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('b');\n\t});\n\n\ttest('can cancel by pressing escape', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'a' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t});\n\n\ttest('options are case-insensitive by default', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'A' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('A');\n\t});\n\n\ttest('input is case-insensitive by default', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'a' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a', shift: true });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('a');\n\t});\n\n\ttest('caseSensitive: true makes options case-sensitive', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'A' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tcaseSensitive: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\t\tinput.emit('keypress', '', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t});\n\n\ttest('caseSensitive: true makes input case-sensitive', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option a', value: 'a' },\n\t\t\t\t{ label: 'Option A', value: 'A' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tcaseSensitive: true,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a', shift: true });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('A');\n\t});\n\n\ttest('long option labels are wrapped correctly', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'Select an option:',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'This is a somewhat long label '.repeat(10).trimEnd(),\n\t\t\t\t\tvalue: 'a',\n\t\t\t\t},\n\t\t\t\t{ label: 'Short label', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('a');\n\t});\n\n\ttest('long cancelled labels are wrapped correctly', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'Select an option:',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'This is a somewhat long label '.repeat(10).trimEnd(),\n\t\t\t\t\tvalue: 'a',\n\t\t\t\t},\n\t\t\t\t{ label: 'Short label', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'escape' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('withGuide: false removes guide', async () => {\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'a' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\twithGuide: false,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('global withGuide: false removes guide', async () => {\n\t\tupdateSettings({ withGuide: false });\n\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ label: 'Option A', value: 'a' },\n\t\t\t\t{ label: 'Option B', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('long submitted labels are wrapped correctly', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.selectKey({\n\t\t\tmessage: 'Select an option:',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: 'This is a somewhat long label '.repeat(10).trimEnd(),\n\t\t\t\t\tvalue: 'a',\n\t\t\t\t},\n\t\t\t\t{ label: 'Short label', value: 'b' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'a', { name: 'a' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/select.test.ts",
    "content": "import { updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('select (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('renders options and message', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt0');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('down arrow selects next option', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt1');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('up arrow selects previous option', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'up' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt0');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can cancel', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders option labels', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', label: 'Option 0' },\n\t\t\t\t{ value: 'opt1', label: 'Option 1' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt0');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders option hints', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', hint: 'Hint 0' },\n\t\t\t\t{ value: 'opt1', hint: 'Hint 1' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt0');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders disabled options', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', label: 'Option 0', disabled: true },\n\t\t\t\t{ value: 'opt1', label: 'Option 1' },\n\t\t\t\t{ value: 'opt2', label: 'Option 2', disabled: true, hint: 'Hint 2' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt1');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('wraps long results', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tvalue: 'opt0',\n\t\t\t\t\tlabel: 'foo '.repeat(30).trim(),\n\t\t\t\t},\n\t\t\t\t{ value: 'opt1', label: 'Option 1' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('wraps long cancelled message', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tvalue: 'opt0',\n\t\t\t\t\tlabel: 'foo '.repeat(30).trim(),\n\t\t\t\t},\n\t\t\t\t{ value: 'opt1', label: 'Option 1' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('wraps long messages', async () => {\n\t\toutput.columns = 40;\n\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo '.repeat(20).trim(),\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toEqual('opt0');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders multi-line option labels', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [\n\t\t\t\t{ value: 'opt0', label: 'Option 0\\nwith multiple lines' },\n\t\t\t\t{ value: 'opt1', label: 'Option 1' },\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('handles mixed size re-renders', async () => {\n\t\toutput.rows = 10;\n\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'Whatever',\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tvalue: 'longopt',\n\t\t\t\t\tlabel: Array.from({ length: 8 }, () => 'Long Option').join('\\n'),\n\t\t\t\t},\n\t\t\t\t...Array.from({ length: 4 }, (_, i) => ({\n\t\t\t\t\tvalue: `opt${i}`,\n\t\t\t\t\tlabel: `Option ${i}`,\n\t\t\t\t})),\n\t\t\t],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'up' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('correctly limits options when message wraps to multiple lines', async () => {\n\t\t// Simulate a narrow terminal that forces the message to wrap\n\t\toutput.columns = 30;\n\t\toutput.rows = 12;\n\n\t\tconst result = prompts.select({\n\t\t\t// Long message that will wrap to multiple lines in a 30-column terminal\n\t\t\tmessage: 'This is a very long message that will wrap to multiple lines',\n\t\t\toptions: Array.from({ length: 10 }, (_, i) => ({\n\t\t\t\tvalue: `opt${i}`,\n\t\t\t\tlabel: `Option ${i}`,\n\t\t\t})),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Scroll down through options to trigger the bug scenario\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt4');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('withGuide: false removes guide', async () => {\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\twithGuide: false,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('global withGuide: false removes guide', async () => {\n\t\tupdateSettings({ withGuide: false });\n\n\t\tconst result = prompts.select({\n\t\t\tmessage: 'foo',\n\t\t\toptions: [{ value: 'opt0' }, { value: 'opt1' }],\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('correctly limits options with explicit multiline message', async () => {\n\t\toutput.rows = 12;\n\n\t\tconst result = prompts.select({\n\t\t\t// Explicit multiline message\n\t\t\tmessage: 'Choose an option:\\nLine 2 of the message\\nLine 3 of the message',\n\t\t\toptions: Array.from({ length: 10 }, (_, i) => ({\n\t\t\t\tvalue: `opt${i}`,\n\t\t\t\tlabel: `Option ${i}`,\n\t\t\t})),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\t// Scroll down to test that options don't overflow\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'down' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('opt3');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/spinner.test.ts",
    "content": "import { EventEmitter } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { getColumns, updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('spinner (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tvi.useFakeTimers();\n\t});\n\n\tafterEach(() => {\n\t\tvi.useRealTimers();\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('returns spinner API', () => {\n\t\tconst api = prompts.spinner({ output });\n\n\t\texpect(api.stop).toBeTypeOf('function');\n\t\texpect(api.start).toBeTypeOf('function');\n\t\texpect(api.message).toBeTypeOf('function');\n\t});\n\n\tdescribe('start', () => {\n\t\ttest('renders frames at interval', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\t// there are 4 frames\n\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\tvi.advanceTimersByTime(80);\n\t\t\t}\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start('foo');\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders timer when indicator is \"timer\"', () => {\n\t\t\tconst result = prompts.spinner({ output, indicator: 'timer' });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('handles wrapping', () => {\n\t\t\tconst columns = getColumns(output);\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start('x'.repeat(columns + 10));\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop('stopped');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('handles multi-line messages', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start('foo\\nbar\\nbaz');\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('stop', () => {\n\t\ttest('renders submit symbol and stops spinner', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders cancel symbol when calling cancel()', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.cancel();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders error symbol when calling error()', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.error();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop('foo');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message without removing dots', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop('foo.');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message when cancelling', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.cancel('too dizzy — spinning cancelled');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders message when erroring', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.error('error: spun too fast!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('does not throw if called before start', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\texpect(() => result.stop()).not.toThrow();\n\t\t});\n\t});\n\n\tdescribe('message', () => {\n\t\ttest('sets message for next frame', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start();\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.message('foo');\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('indicator customization', () => {\n\t\ttest('custom frames', () => {\n\t\t\tconst result = prompts.spinner({ output, frames: ['🐴', '🦋', '🐙', '🐶'] });\n\n\t\t\tresult.start();\n\n\t\t\t// there are 4 frames\n\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\tvi.advanceTimersByTime(80);\n\t\t\t}\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('custom frames with lots of frame have consistent ellipsis display', () => {\n\t\t\tconst result = prompts.spinner({ output, frames: Object.keys(Array(10).fill(0)) });\n\n\t\t\tresult.start();\n\n\t\t\tfor (let i = 0; i < 64; i++) {\n\t\t\t\tvi.advanceTimersByTime(80);\n\t\t\t}\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('custom delay', () => {\n\t\t\tconst result = prompts.spinner({ output, delay: 200 });\n\n\t\t\tresult.start();\n\n\t\t\t// there are 4 frames\n\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\tvi.advanceTimersByTime(200);\n\t\t\t}\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('custom frame style', () => {\n\t\t\tconst result = prompts.spinner({ output, styleFrame: (text) => styleText('red', text) });\n\n\t\t\tresult.start();\n\n\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\tvi.advanceTimersByTime(80);\n\t\t\t}\n\n\t\t\tresult.stop();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('process exit handling', () => {\n\t\tlet processEmitter: EventEmitter;\n\n\t\tbeforeEach(() => {\n\t\t\tprocessEmitter = new EventEmitter();\n\n\t\t\t// Spy on process methods\n\t\t\tvi.spyOn(process, 'on').mockImplementation((ev, listener) => {\n\t\t\t\tprocessEmitter.on(ev, listener);\n\t\t\t\treturn process;\n\t\t\t});\n\t\t\tvi.spyOn(process, 'removeListener').mockImplementation((ev, listener) => {\n\t\t\t\tprocessEmitter.removeListener(ev, listener);\n\t\t\t\treturn process;\n\t\t\t});\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tprocessEmitter.removeAllListeners();\n\t\t});\n\n\t\ttest('uses default cancel message', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\t\t\tresult.start('Test operation');\n\n\t\t\tprocessEmitter.emit('SIGINT');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('uses custom cancel message when provided directly', () => {\n\t\t\tconst result = prompts.spinner({\n\t\t\t\toutput,\n\t\t\t\tcancelMessage: 'Custom cancel message',\n\t\t\t});\n\t\t\tresult.start('Test operation');\n\n\t\t\tprocessEmitter.emit('SIGINT');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('uses custom error message when provided directly', () => {\n\t\t\tconst result = prompts.spinner({\n\t\t\t\toutput,\n\t\t\t\terrorMessage: 'Custom error message',\n\t\t\t});\n\t\t\tresult.start('Test operation');\n\n\t\t\tprocessEmitter.emit('exit', 2);\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('uses global custom cancel message from settings', () => {\n\t\t\t// Store original message\n\t\t\tconst originalCancelMessage = prompts.settings.messages.cancel;\n\t\t\ttry {\n\t\t\t\t// Set custom message\n\t\t\t\tprompts.settings.messages.cancel = 'Global cancel message';\n\n\t\t\t\tconst result = prompts.spinner({ output });\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('SIGINT');\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original\n\t\t\t\tprompts.settings.messages.cancel = originalCancelMessage;\n\t\t\t}\n\t\t});\n\n\t\ttest('uses global custom error message from settings', () => {\n\t\t\t// Store original message\n\t\t\tconst originalErrorMessage = prompts.settings.messages.error;\n\n\t\t\ttry {\n\t\t\t\t// Set custom message\n\t\t\t\tprompts.settings.messages.error = 'Global error message';\n\n\t\t\t\tconst result = prompts.spinner({ output });\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('exit', 2);\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original\n\t\t\t\tprompts.settings.messages.error = originalErrorMessage;\n\t\t\t}\n\t\t});\n\n\t\ttest('prioritizes error option over global setting', () => {\n\t\t\t// Store original messages\n\t\t\tconst originalErrorMessage = prompts.settings.messages.error;\n\n\t\t\ttry {\n\t\t\t\t// Set custom global messages\n\t\t\t\tprompts.settings.messages.error = 'Global error message';\n\n\t\t\t\tconst result = prompts.spinner({\n\t\t\t\t\toutput,\n\t\t\t\t\terrorMessage: 'Spinner error message',\n\t\t\t\t});\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('exit', 2);\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original values\n\t\t\t\tprompts.settings.messages.error = originalErrorMessage;\n\t\t\t}\n\t\t});\n\n\t\ttest('prioritizes cancel option over global setting', () => {\n\t\t\t// Store original messages\n\t\t\tconst originalCancelMessage = prompts.settings.messages.cancel;\n\n\t\t\ttry {\n\t\t\t\t// Set custom global messages\n\t\t\t\tprompts.settings.messages.cancel = 'Global cancel message';\n\n\t\t\t\tconst result = prompts.spinner({\n\t\t\t\t\toutput,\n\t\t\t\t\tcancelMessage: 'Spinner cancel message',\n\t\t\t\t});\n\t\t\t\tresult.start('Test operation');\n\n\t\t\t\tprocessEmitter.emit('SIGINT');\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t} finally {\n\t\t\t\t// Reset to original values\n\t\t\t\tprompts.settings.messages.cancel = originalCancelMessage;\n\t\t\t}\n\t\t});\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = prompts.spinner({\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tresult.start('Testing');\n\n\t\tcontroller.abort();\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('withGuide: false removes guide', () => {\n\t\tconst result = prompts.spinner({ output, withGuide: false });\n\n\t\tresult.start('foo');\n\n\t\tvi.advanceTimersByTime(80);\n\n\t\tresult.stop();\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('global withGuide: false removes guide', () => {\n\t\tupdateSettings({ withGuide: false });\n\n\t\tconst result = prompts.spinner({ output });\n\n\t\tresult.start('foo');\n\n\t\tvi.advanceTimersByTime(80);\n\n\t\tresult.stop();\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\tdescribe('clear', () => {\n\t\ttest('stops and clears the spinner from the output', () => {\n\t\t\tconst result = prompts.spinner({ output });\n\n\t\t\tresult.start('Loading');\n\n\t\t\tvi.advanceTimersByTime(80);\n\n\t\t\tresult.clear();\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/task-log.test.ts",
    "content": "import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('taskLog (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\toutput.isTTY = isCI === 'false';\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t});\n\n\ttest('writes message header', () => {\n\t\tprompts.taskLog({\n\t\t\tinput,\n\t\t\toutput,\n\t\t\ttitle: 'foo',\n\t\t});\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\tdescribe('message', () => {\n\t\ttest('can write line by line', () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0');\n\t\t\tlog.message('line 1');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('can write multiple lines', () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0\\nline 1');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('enforces limit if set', () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t\tlimit: 2,\n\t\t\t});\n\n\t\t\tlog.message('line 0');\n\t\t\tlog.message('line 1');\n\t\t\tlog.message('line 2');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('raw = true appends message text until newline', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0', { raw: true });\n\t\t\tlog.message('still line 0', { raw: true });\n\t\t\tlog.message('\\nline 1', { raw: true });\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('raw = true works when mixed with non-raw messages', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0', { raw: true });\n\t\t\tlog.message('still line 0', { raw: true });\n\t\t\tlog.message('line 1');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('raw = true works when started with non-raw messages', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0');\n\t\t\tlog.message('line 1', { raw: true });\n\t\t\tlog.message('still line 1', { raw: true });\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('prints empty lines', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 1');\n\t\t\tlog.message('');\n\t\t\tlog.message('line 3');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('destructive ansi codes are stripped', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 1');\n\t\t\tlog.message('line 2\\x1b[2K bad ansi!');\n\t\t\tlog.message('line 3');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('error', () => {\n\t\ttest('renders output with message', () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0');\n\t\t\tlog.message('line 1');\n\n\t\t\tlog.error('some error!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('clears output if showLog = false', () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0');\n\t\t\tlog.message('line 1');\n\n\t\t\tlog.error('some error!', { showLog: false });\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('success', () => {\n\t\ttest('clears output and renders message', () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0');\n\t\t\tlog.message('line 1');\n\n\t\t\tlog.success('success!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders output if showLog = true', () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\ttitle: 'foo',\n\t\t\t});\n\n\t\t\tlog.message('line 0');\n\t\t\tlog.message('line 1');\n\n\t\t\tlog.success('success!', { showLog: true });\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n\n\tdescribe('retainLog', () => {\n\t\tdescribe.each(['error', 'success'] as const)('%s', (method) => {\n\t\t\ttest('retainLog = true outputs full log', () => {\n\t\t\t\tconst log = prompts.taskLog({\n\t\t\t\t\tinput,\n\t\t\t\t\toutput,\n\t\t\t\t\ttitle: 'foo',\n\t\t\t\t\tretainLog: true,\n\t\t\t\t});\n\n\t\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\t\tlog.message(`line ${i}`);\n\t\t\t\t}\n\n\t\t\t\tlog[method]('woo!', { showLog: true });\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t});\n\n\t\t\ttest('retainLog = true outputs full log with limit', () => {\n\t\t\t\tconst log = prompts.taskLog({\n\t\t\t\t\tinput,\n\t\t\t\t\toutput,\n\t\t\t\t\ttitle: 'foo',\n\t\t\t\t\tretainLog: true,\n\t\t\t\t\tlimit: 2,\n\t\t\t\t});\n\n\t\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\t\tlog.message(`line ${i}`);\n\t\t\t\t}\n\n\t\t\t\tlog[method]('woo!', { showLog: true });\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t});\n\n\t\t\ttest('retainLog = false outputs full log without limit', () => {\n\t\t\t\tconst log = prompts.taskLog({\n\t\t\t\t\tinput,\n\t\t\t\t\toutput,\n\t\t\t\t\ttitle: 'foo',\n\t\t\t\t\tretainLog: false,\n\t\t\t\t});\n\n\t\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\t\tlog.message(`line ${i}`);\n\t\t\t\t}\n\n\t\t\t\tlog[method]('woo!', { showLog: true });\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t});\n\n\t\t\ttest('retainLog = false outputs limited log with limit', () => {\n\t\t\t\tconst log = prompts.taskLog({\n\t\t\t\t\tinput,\n\t\t\t\t\toutput,\n\t\t\t\t\ttitle: 'foo',\n\t\t\t\t\tretainLog: false,\n\t\t\t\t\tlimit: 2,\n\t\t\t\t});\n\n\t\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\t\tlog.message(`line ${i}`);\n\t\t\t\t}\n\n\t\t\t\tlog[method]('woo!', { showLog: true });\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t});\n\n\t\t\ttest('outputs limited log with limit by default', () => {\n\t\t\t\tconst log = prompts.taskLog({\n\t\t\t\t\tinput,\n\t\t\t\t\toutput,\n\t\t\t\t\ttitle: 'foo',\n\t\t\t\t\tlimit: 2,\n\t\t\t\t});\n\n\t\t\t\tfor (let i = 0; i < 4; i++) {\n\t\t\t\t\tlog.message(`line ${i}`);\n\t\t\t\t}\n\n\t\t\t\tlog[method]('woo!', { showLog: true });\n\n\t\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t\t});\n\t\t});\n\t});\n\n\tdescribe('group', () => {\n\t\ttest('can render multiple groups of equal size', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group0 = log.group('Group 0');\n\t\t\tconst group1 = log.group('Group 1');\n\n\t\t\tfor (let i = 0; i < 5; i++) {\n\t\t\t\tgroup0.message(`Group 0 line ${i}`);\n\t\t\t\tgroup1.message(`Group 1 line ${i}`);\n\t\t\t}\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('can render multiple groups of different sizes', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group0 = log.group('Group 0');\n\t\t\tconst group1 = log.group('Group 1');\n\n\t\t\tfor (let i = 0; i < 3; i++) {\n\t\t\t\tgroup0.message(`Group 0 line ${i}`);\n\t\t\t}\n\t\t\tfor (let i = 0; i < 5; i++) {\n\t\t\t\tgroup1.message(`Group 1 line ${i}`);\n\t\t\t}\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders success state', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group = log.group('Group 0');\n\t\t\tgroup.message('Group 0 line 0');\n\t\t\tgroup.success('Group success!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders error state', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group = log.group('Group 0');\n\t\t\tgroup.message('Group 0 line 0');\n\t\t\tgroup.error('Group error!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('applies limit per group', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t\tlimit: 2,\n\t\t\t});\n\t\t\tconst group0 = log.group('Group 0');\n\t\t\tconst group1 = log.group('Group 1');\n\n\t\t\tfor (let i = 0; i < 5; i++) {\n\t\t\t\tgroup0.message(`Group 0 line ${i}`);\n\t\t\t\tgroup1.message(`Group 1 line ${i}`);\n\t\t\t}\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders group success state', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group = log.group('Group 0');\n\t\t\tgroup.message('Group 0 line 0');\n\t\t\tgroup.success('Group success!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('renders group error state', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group = log.group('Group 0');\n\t\t\tgroup.message('Group 0 line 0');\n\t\t\tgroup.error('Group error!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('showLog shows all groups in order', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group0 = log.group('Group 0');\n\t\t\tconst group1 = log.group('Group 1');\n\n\t\t\tfor (let i = 0; i < 3; i++) {\n\t\t\t\tgroup0.message(`Group 0 line ${i}`);\n\t\t\t}\n\t\t\tfor (let i = 0; i < 5; i++) {\n\t\t\t\tgroup1.message(`Group 1 line ${i}`);\n\t\t\t}\n\n\t\t\tgroup0.success('Group 0 success!');\n\t\t\tgroup1.error('Group 1 error!');\n\n\t\t\tlog.error('overall error', { showLog: true });\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\n\t\ttest('handles empty groups', async () => {\n\t\t\tconst log = prompts.taskLog({\n\t\t\t\ttitle: 'Some log',\n\t\t\t\tinput,\n\t\t\t\toutput,\n\t\t\t});\n\t\t\tconst group = log.group('Group 0');\n\n\t\t\tgroup.success('Group success!');\n\n\t\t\texpect(output.buffer).toMatchSnapshot();\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/test/test-utils.ts",
    "content": "import { Readable, Writable } from 'node:stream';\n\nexport class MockWritable extends Writable {\n\tpublic buffer: string[] = [];\n\tpublic isTTY = false;\n\tpublic columns = 80;\n\tpublic rows = 20;\n\n\t_write(\n\t\tchunk: any,\n\t\t_encoding: BufferEncoding,\n\t\tcallback: (error?: Error | null | undefined) => void\n\t): void {\n\t\tthis.buffer.push(chunk.toString());\n\t\tcallback();\n\t}\n}\n\nexport class MockReadable extends Readable {\n\tprotected _buffer: unknown[] | null = [];\n\n\t_read() {\n\t\tif (this._buffer === null) {\n\t\t\tthis.push(null);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const val of this._buffer) {\n\t\t\tthis.push(val);\n\t\t}\n\n\t\tthis._buffer = [];\n\t}\n\n\tpushValue(val: unknown): void {\n\t\tthis._buffer?.push(val);\n\t}\n\n\tclose(): void {\n\t\tthis._buffer = null;\n\t}\n}\n"
  },
  {
    "path": "packages/prompts/test/text.test.ts",
    "content": "import { updateSettings } from '@clack/core';\nimport { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest';\nimport * as prompts from '../src/index.js';\nimport { MockReadable, MockWritable } from './test-utils.js';\n\ndescribe.each(['true', 'false'])('text (isCI = %s)', (isCI) => {\n\tlet originalCI: string | undefined;\n\tlet output: MockWritable;\n\tlet input: MockReadable;\n\n\tbeforeAll(() => {\n\t\toriginalCI = process.env.CI;\n\t\tprocess.env.CI = isCI;\n\t});\n\n\tafterAll(() => {\n\t\tprocess.env.CI = originalCI;\n\t});\n\n\tbeforeEach(() => {\n\t\toutput = new MockWritable();\n\t\tinput = new MockReadable();\n\t});\n\n\tafterEach(() => {\n\t\tvi.restoreAllMocks();\n\t\tupdateSettings({ withGuide: true });\n\t});\n\n\ttest('renders message', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders placeholder if set', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tplaceholder: 'bar',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t\texpect(value).toBe('');\n\t});\n\n\ttest('can cancel', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'escape', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders cancelled value if one set', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'escape' });\n\n\t\tconst value = await result;\n\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('renders submitted value', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('xy');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('defaultValue sets the value but does not render', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tdefaultValue: 'bar',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('bar');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('validation errors render and clear', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tvalidate: (val) => (val !== 'xy' ? 'should be xy' : undefined),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('xy');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('validation errors render and clear (using Error)', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tvalidate: (val) => (val !== 'xy' ? new Error('should be xy') : undefined),\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', 'x', { name: 'x' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\t\tinput.emit('keypress', 'y', { name: 'y' });\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('xy');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('placeholder is not used as value when pressing enter', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tplaceholder: '  (hit Enter to use default)',\n\t\t\tdefaultValue: 'default-value',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('default-value');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('empty string when no value and no default', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tplaceholder: '  (hit Enter to use default)',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tconst value = await result;\n\n\t\texpect(value).toBe('');\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('can be aborted by a signal', async () => {\n\t\tconst controller = new AbortController();\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t\tsignal: controller.signal,\n\t\t});\n\n\t\tcontroller.abort();\n\t\tconst value = await result;\n\t\texpect(prompts.isCancel(value)).toBe(true);\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('withGuide: false removes guide', async () => {\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\twithGuide: false,\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n\n\ttest('global withGuide: false removes guide', async () => {\n\t\tupdateSettings({ withGuide: false });\n\n\t\tconst result = prompts.text({\n\t\t\tmessage: 'foo',\n\t\t\tinput,\n\t\t\toutput,\n\t\t});\n\n\t\tinput.emit('keypress', '', { name: 'return' });\n\n\t\tawait result;\n\n\t\texpect(output.buffer).toMatchSnapshot();\n\t});\n});\n"
  },
  {
    "path": "packages/prompts/tsconfig.json",
    "content": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"include\": [\"src\", \"test\"]\n}\n"
  },
  {
    "path": "packages/prompts/vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n\ttest: {\n\t\tenv: {\n\t\t\tFORCE_COLOR: '1',\n\t\t},\n\t\tsnapshotSerializers: ['vitest-ansi-serializer'],\n\t},\n});\n"
  },
  {
    "path": "pnpm-workspace.yaml",
    "content": "packages:\n  - 'examples/*'\n  - 'packages/*'\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"noEmit\": true,\n    \"module\": \"node16\",\n    \"target\": \"ESNext\",\n    \"moduleResolution\": \"node16\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"erasableSyntaxOnly\": true,\n    \"skipLibCheck\": true,\n    \"isolatedModules\": true,\n    \"verbatimModuleSyntax\": true,\n    \"noUnusedParameters\": true,\n    \"noUnusedLocals\": true,\n    \"lib\": [\"ES2022\"],\n    \"paths\": {\n      \"@clack/core\": [\"./packages/core/src/index.ts\"],\n      \"@clack/prompts\": [\"./packages/prompts/src/index.ts\"]\n    }\n  },\n  \"include\": [\"packages/*/src/**/*.ts\", \"packages/*/test/**/*.ts\"]\n}\n"
  }
]