{"id":13396678,"url":"https://github.com/sindresorhus/ora","last_synced_at":"2026-01-21T05:01:24.721Z","repository":{"id":37768339,"uuid":"53072654","full_name":"sindresorhus/ora","owner":"sindresorhus","description":"Elegant terminal spinner","archived":false,"fork":false,"pushed_at":"2025-09-16T03:30:24.000Z","size":689,"stargazers_count":9568,"open_issues_count":9,"forks_count":284,"subscribers_count":47,"default_branch":"main","last_synced_at":"2026-01-18T17:53:07.178Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sindresorhus.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/security.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"sindresorhus","open_collective":"sindresorhus","buy_me_a_coffee":"sindresorhus","custom":"https://sindresorhus.com/donate"}},"created_at":"2016-03-03T18:17:16.000Z","updated_at":"2026-01-16T14:21:56.000Z","dependencies_parsed_at":"2023-09-27T09:48:47.148Z","dependency_job_id":"7980600c-839e-4ab4-b72d-696a4d7367aa","html_url":"https://github.com/sindresorhus/ora","commit_stats":{"total_commits":171,"total_committers":52,"mean_commits":"3.2884615384615383","dds":"0.36257309941520466","last_synced_commit":"86aca37a324dcb010da5c04660e5c81a4d8f1f9d"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/sindresorhus/ora","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fora","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fora/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fora/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fora/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sindresorhus","download_url":"https://codeload.github.com/sindresorhus/ora/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sindresorhus%2Fora/sbom","scorecard":{"id":826654,"data":{"date":"2025-08-11","repo":{"name":"github.com/sindresorhus/ora","commit":"79d0339e000cf956ba5581013f27bd86a41d56fc"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.2,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: .github/security.md:1","Info: Found linked content: .github/security.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: .github/security.md:1","Info: Found text in security policy: .github/security.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Code-Review","score":2,"reason":"Found 6/30 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/sindresorhus/ora/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/sindresorhus/ora/main.yml/main?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/main.yml:22","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: license:0","Info: FSF or OSI recognized license: MIT License: license:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T16:45:34.402Z","repository_id":37768339,"created_at":"2025-08-23T16:45:34.403Z","updated_at":"2025-08-23T16:45:34.403Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28569044,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T12:50:50.164Z","status":"ssl_error","status_checked_at":"2026-01-19T12:50:42.704Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T18:00:59.883Z","updated_at":"2026-01-21T05:01:24.714Z","avatar_url":"https://github.com/sindresorhus.png","language":"JavaScript","readme":"# ora\n\n\u003e Elegant terminal spinner\n\n\u003cp align=\"center\"\u003e\n\t\u003cbr\u003e\n\t\u003cimg src=\"screenshot.svg\" width=\"500\"\u003e\n\t\u003cbr\u003e\n\u003c/p\u003e\n\n## Install\n\n```sh\nnpm install ora\n```\n\n*Check out [`yocto-spinner`](https://github.com/sindresorhus/yocto-spinner) for a smaller alternative.*\n\n## Usage\n\n```js\nimport ora from 'ora';\n\nconst spinner = ora('Loading unicorns').start();\n\nsetTimeout(() =\u003e {\n\tspinner.color = 'yellow';\n\tspinner.text = 'Loading rainbows';\n}, 1000);\n```\n\n## API\n\n### ora(text)\n### ora(options)\n\nIf a string is provided, it is treated as a shortcut for [`options.text`](#text).\n\n#### options\n\nType: `object`\n\n##### text\n\nType: `string`\n\nThe text to display next to the spinner.\n\n##### prefixText\n\nType: `string | () =\u003e string`\n\nText or a function that returns text to display before the spinner. No prefix text will be displayed if set to an empty string.\n\n##### suffixText\n\nType: `string | () =\u003e string`\n\nText or a function that returns text to display after the spinner text. No suffix text will be displayed if set to an empty string.\n\n##### spinner\n\nType: `string | object`\\\nDefault: `'dots'` \u003cimg src=\"screenshot-spinner.gif\" width=\"14\"\u003e\n\nThe name of one of the [provided spinners](#spinners). See `example.js` in this repo if you want to test out different spinners. On Windows (except for Windows Terminal), it will always use the `line` spinner as the Windows command-line doesn't have proper Unicode support.\n\nOr an object like:\n\n```js\n{\n\tframes: ['-', '+', '-'],\n\tinterval: 80 // Optional\n}\n```\n\n##### color\n\nType: `string | boolean`\\\nDefault: `'cyan'`\\\nValues: `'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'gray' | boolean`\n\nThe color of the spinner. Set to `false` to disable coloring.\n\n##### hideCursor\n\nType: `boolean`\\\nDefault: `true`\n\nSet to `false` to stop Ora from hiding the cursor.\n\n##### indent\n\nType: `number`\\\nDefault: `0`\n\nIndent the spinner with the given number of spaces.\n\n##### interval\n\nType: `number`\\\nDefault: Provided by the spinner or `100`\n\nInterval between each frame.\n\nSpinners provide their own recommended interval, so you don't really need to specify this.\n\n##### stream\n\nType: `stream.Writable`\\\nDefault: `process.stderr`\n\nStream to write the output.\n\nYou could for example set this to `process.stdout` instead.\n\n##### isEnabled\n\nType: `boolean`\n\nForce enable/disable the spinner. If not specified, the spinner will be enabled if the `stream` is being run inside a TTY context (not spawned or piped) and/or not in a CI environment.\n\nNote that `{isEnabled: false}` doesn't mean it won't output anything. It just means it won't output the spinner, colors, and other ansi escape codes. It will still log text.\n\n##### isSilent\n\nType: `boolean`\\\nDefault: `false`\n\nDisable the spinner and all log text. All output is suppressed and `isEnabled` will be considered `false`.\n\n##### discardStdin\n\nType: `boolean`\\\nDefault: `true`\n\nDiscard stdin input (except Ctrl+C) while running if it's TTY. This prevents the spinner from twitching on input, outputting broken lines on \u003ckbd\u003eEnter\u003c/kbd\u003e key presses, and prevents buffering of input while the spinner is running.\n\nThis has no effect on Windows as there is no good way to implement discarding stdin properly there.\n\n### Instance\n\n#### .text \u003csup\u003eget/set\u003c/sup\u003e\n\nChange the text displayed after the spinner.\n\n#### .prefixText \u003csup\u003eget/set\u003c/sup\u003e\n\nChange the text before the spinner.\n\nNo prefix text will be displayed if set to an empty string.\n\n#### .suffixText \u003csup\u003eget/set\u003c/sup\u003e\n\nChange the text after the spinner text.\n\nNo suffix text will be displayed if set to an empty string.\n\n#### .color \u003csup\u003eget/set\u003c/sup\u003e\n\nChange the spinner color.\n\n#### .spinner \u003csup\u003eget/set\u003c/sup\u003e\n\nChange the spinner.\n\n#### .indent \u003csup\u003eget/set\u003c/sup\u003e\n\nChange the spinner indent.\n\n#### .isSpinning \u003csup\u003eget\u003c/sup\u003e\n\nA boolean indicating whether the instance is currently spinning.\n\n#### .interval \u003csup\u003eget\u003c/sup\u003e\n\nThe interval between each frame.\n\nThe interval is decided by the chosen spinner.\n\n#### .start(text?)\n\nStart the spinner. Returns the instance. Set the current text if `text` is provided.\n\n#### .stop()\n\nStop and clear the spinner. Returns the instance.\n\n#### .succeed(text?)\n\nStop the spinner, change it to a green `✔` and persist the current text, or `text` if provided. Returns the instance. See the GIF below.\n\n#### .fail(text?)\n\nStop the spinner, change it to a red `✖` and persist the current text, or `text` if provided. Returns the instance. See the GIF below.\n\n#### .warn(text?)\n\nStop the spinner, change it to a yellow `⚠` and persist the current text, or `text` if provided. Returns the instance.\n\n#### .info(text?)\n\nStop the spinner, change it to a blue `ℹ` and persist the current text, or `text` if provided. Returns the instance.\n\n#### .stopAndPersist(options?)\n\nStop the spinner and change the symbol or text. Returns the instance. See the GIF below.\n\n##### options\n\nType: `object`\n\n###### symbol\n\nType: `string`\\\nDefault: `' '`\n\nSymbol to replace the spinner with.\n\n###### text\n\nType: `string`\\\nDefault: Current `'text'`\n\nText to be persisted after the symbol.\n\n###### prefixText\n\nType: `string | () =\u003e string`\\\nDefault: Current `prefixText`\n\nText or a function that returns text to be persisted before the symbol. No prefix text will be displayed if set to an empty string.\n\n###### suffixText\n\nType: `string | () =\u003e string`\\\nDefault: Current `suffixText`\n\nText or a function that returns text to be persisted after the text after the symbol. No suffix text will be displayed if set to an empty string.\n\n\u003cimg src=\"screenshot-2.gif\" width=\"480\"\u003e\n\n#### .clear()\n\nClear the spinner. Returns the instance.\n\n#### .render()\n\nManually render a new frame. Returns the instance.\n\n#### .frame()\n\nGet a new frame.\n\n### oraPromise(action, text)\n### oraPromise(action, options)\n\nStarts a spinner for a promise or promise-returning function. The spinner is stopped with `.succeed()` if the promise fulfills or with `.fail()` if it rejects. Returns the promise.\n\n```js\nimport {oraPromise} from 'ora';\n\nawait oraPromise(somePromise);\n```\n\n#### action\n\nType: `Promise | ((spinner: ora.Ora) =\u003e Promise)`\n\n#### options\n\nType: `object`\n\nAll of the [options](#options) plus the following:\n\n##### successText\n\nType: `string | ((result: T) =\u003e string) | undefined`\n\nThe new text of the spinner when the promise is resolved.\n\nKeeps the existing text if `undefined`.\n\n##### failText\n\nType: `string | ((error: Error) =\u003e string) | undefined`\n\nThe new text of the spinner when the promise is rejected.\n\nKeeps the existing text if `undefined`.\n\n### spinners\n\nType: `Record\u003cstring, Spinner\u003e`\n\nAll [provided spinners](https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json).\n\n## FAQ\n\n### How do I change the color of the text?\n\nUse [`chalk`](https://github.com/chalk/chalk) or [`yoctocolors`](https://github.com/sindresorhus/yoctocolors):\n\n```js\nimport ora from 'ora';\nimport chalk from 'chalk';\n\nconst spinner = ora(`Loading ${chalk.red('unicorns')}`).start();\n```\n\n### Why does the spinner freeze?\n\nJavaScript is single-threaded, so any synchronous operations will block the spinner's animation. To avoid this, prefer using asynchronous operations.\n\n### Can I display multiple spinners simultaneously?\n\nNo. Ora is designed to display a single spinner at a time. For multiple concurrent progress indicators, consider alternatives like [listr2](https://github.com/listr2/listr2) or [spinnies](https://github.com/jcarpanelli/spinnies).\n\n### Can I use Ora with [log-update](https://github.com/sindresorhus/log-update)?\n\nYes, use the `.frame()` method to get the current spinner frame and include it in your log-update output.\n\n### Does Ora work in Node.js Worker threads?\n\nNo. Ora requires an interactive terminal environment and Worker threads are not considered interactive, so the spinner will not animate. Run the spinner in the main thread and control it via worker messages:\n\n```js\n// main.js\nimport {Worker} from 'node:worker_threads';\nimport ora from 'ora';\n\nconst spinner = ora().start();\nconst worker = new Worker('./worker.js');\n\nworker.on('message', message =\u003e {\n\tswitch (message.type) {\n\t\tcase 'ora:text':\n\t\t\tspinner.text = message.text;\n\t\t\tbreak;\n\t\tcase 'ora:succeed':\n\t\t\tspinner.succeed(message.text);\n\t\t\tbreak;\n\t\tcase 'ora:fail':\n\t\t\tspinner.fail(message.text);\n\t\t\tbreak;\n\t}\n});\n```\n\n```js\n// worker.js\nimport {parentPort} from 'node:worker_threads';\n\nparentPort.postMessage({type: 'ora:text', text: 'Working...'});\n\n// Do work...\n\nparentPort.postMessage({type: 'ora:succeed', text: 'Done!'});\n```\n\n## Related\n\n- [yocto-spinner](https://github.com/sindresorhus/yocto-spinner) - Tiny terminal spinner\n- [cli-spinners](https://github.com/sindresorhus/cli-spinners) - Spinners for use in the terminal\n\n**Ports**\n\n- [CLISpinner](https://github.com/kiliankoe/CLISpinner) - Terminal spinner library for Swift\n- [halo](https://github.com/ManrajGrover/halo) - Python port\n- [spinners](https://github.com/FGRibreau/spinners) - Terminal spinners for Rust\n- [marquee-ora](https://github.com/joeycozza/marquee-ora) - Scrolling marquee spinner for Ora\n- [briandowns/spinner](https://github.com/briandowns/spinner) - Terminal spinner/progress indicator for Go\n- [tj/go-spin](https://github.com/tj/go-spin) - Terminal spinner package for Go\n- [observablehq.com/@victordidenko/ora](https://observablehq.com/@victordidenko/ora) - Ora port to Observable notebooks\n- [kia](https://github.com/HarryPeach/kia) - Simple terminal spinners for Deno 🦕\n","funding_links":["https://github.com/sponsors/sindresorhus","https://opencollective.com/sindresorhus","https://buymeacoffee.com/sindresorhus","https://sindresorhus.com/donate"],"categories":["打印","Packages","JavaScript","Repository","包",":package: NodeJS","Uncategorized","CLI apps development","js库(Browser/Nodejs)","命令行","目录","Animation","others","GIT 仓库","Command-line utilities","Tools","\u003ca name=\"animation\"\u003e\u003c/a\u003eAnimation","3. 命令行程序","Node","Node.js / JavaScript 🟨","CLI Tools"],"sub_categories":["Command-line utilities","Command-line Utilities","命令行工具","Styling","Uncategorized","Shell","redux 扩展","React Components","macros","命令行实用工具","3.1 开发库","命令行"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindresorhus%2Fora","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsindresorhus%2Fora","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsindresorhus%2Fora/lists"}