{"_id":"clickable-path","_rev":"5-4affef04fe8746199e6983e623623b10","name":"clickable-path","dist-tags":{"latest":"0.1.1"},"versions":{"0.0.0":{"name":"clickable-path","version":"0.0.0","author":{"name":"Daniel Roe","email":"daniel@roe.dev"},"_id":"clickable-path@0.0.0","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"dist":{"shasum":"a3c6e0121c776834a304ff5d358f249f6d6c1e11","tarball":"https://registry.npmjs.org/clickable-path/-/clickable-path-0.0.0.tgz","fileCount":2,"integrity":"sha512-Kqu5+PSPzLnuqWdHhJ9GRbtlqmQ9XP0VOlcRv25ZGkB7DdA5E0F+trAK9yesAH+UgZhbC9rEhKsh0Ix3wnCKjA==","signatures":[{"sig":"MEQCICiVlYtufRjQQGdG7pKFCW0eiYVkEmIIJ9CksKPz7UtaAiA5ELSd9PPsonpO4kR9crjqbGdK6AEFRBZiJk6D1Z7nzA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":125},"gitHead":"738cca0bf06ba0e95a87271b86342ccfb78122b7","_npmUser":{"name":"danielroe","email":"daniel@roe.dev"},"_npmVersion":"11.15.0","directories":{},"_nodeVersion":"24.15.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/clickable-path_0.0.0_1785068862242_0.8229045463248745","host":"s3://npm-registry-packages-npm-production"}},"0.0.1":{"name":"clickable-path","version":"0.0.1","license":"MIT","_id":"clickable-path@0.0.1","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/danielroe/clickable-path#readme","bugs":{"url":"https://github.com/danielroe/clickable-path/issues"},"dist":{"shasum":"879707bd26e7ab99bd50485c59970253bd2b2d84","tarball":"https://registry.npmjs.org/clickable-path/-/clickable-path-0.0.1.tgz","fileCount":5,"integrity":"sha512-PkJJGbxFRoWoxyYImJPPyd/RW+aVe0HQVBPhbp2KUaYZdpVNcIopUcE9UmCNAwdbj9frP5SzundqaePJF4ZWrw==","signatures":[{"sig":"MEQCIHsVsElVCW+9tBnfaO738k2K0JHdlTdHLKjVAFOufsAgAiBzNIdvQ1pmktPM9TA8aw71hg7mDQjw7v2qh4oB0ZURjQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/clickable-path@0.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":19269},"type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/clickable-path-0.0.1.tgz","types":"./dist/index.d.mts","engines":{"node":">=22.1.0"},"exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"scripts":{"dev":"vitest dev","lint":"eslint . --fix","test":"pnpm test:unit && pnpm test:types","build":"tsdown","test:knip":"knip","test:unit":"vitest","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","approver":{"name":"danielroe","email":"daniel@roe.dev"},"trustedPublisher":{"id":"github","oidcConfigId":"oidc:c3c859c0-f2b3-466e-9d13-dd4b8f58ba81"}},"_resolved":"/home/runner/work/_temp/uppt-tarballs/clickable-path-0.0.1.tgz","_integrity":"sha512-PkJJGbxFRoWoxyYImJPPyd/RW+aVe0HQVBPhbp2KUaYZdpVNcIopUcE9UmCNAwdbj9frP5SzundqaePJF4ZWrw==","repository":{"url":"git+https://github.com/danielroe/clickable-path.git","type":"git"},"_npmVersion":"12.0.1","description":"Make file paths printed by CLIs ctrl/cmd-clickable, using OSC 8 hyperlinks","directories":{},"nano-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"sideEffects":false,"_nodeVersion":"24.18.0","typesVersions":{"*":{"*":["./dist/index.d.mts"]}},"_hasShrinkwrap":false,"devDependencies":{"knip":"6.27.0","eslint":"10.7.0","tsdown":"0.22.12","vitest":"4.1.10","typescript":"6.0.3","@types/node":"^26.1.1","nano-staged":"1.0.2","installed-check":"10.0.1","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.1.10","@antfu/eslint-config":"9.1.0"},"simple-git-hooks":{"pre-commit":"npx nano-staged"},"_npmOperationalInternal":{"tmp":"tmp/clickable-path_0.0.1_1785080817339_0.27580219854027543","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"clickable-path","version":"0.1.0","license":"MIT","_id":"clickable-path@0.1.0","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/danielroe/clickable-path#readme","bugs":{"url":"https://github.com/danielroe/clickable-path/issues"},"dist":{"shasum":"ef46374441d167f9882ecad22658689aac2e2bb7","tarball":"https://registry.npmjs.org/clickable-path/-/clickable-path-0.1.0.tgz","fileCount":5,"integrity":"sha512-JRBIpDbw7S1vaEGvCXfm728cfchkUDtv4I2DjWMMm7IoEygxuFWhO6UQOrg+u61TPI13c/HsGG/RLwl3NBt+4w==","signatures":[{"sig":"MEYCIQDCrTlo70UfC4JnFWu4jwCLIa6XS6l5NixiX+/KOr+w/gIhALf9ylJHAGnOaaiNcPUMbXPT2zJ/xbrM/xXbSSxsyQpT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/clickable-path@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":18838},"type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/clickable-path-0.1.0.tgz","types":"./dist/index.d.mts","engines":{"node":">=22.1.0"},"exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"scripts":{"dev":"vitest dev","lint":"eslint . --fix","test":"pnpm test:unit && pnpm test:types","build":"tsdown","test:knip":"knip","test:unit":"vitest","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","approver":{"name":"danielroe","email":"daniel@roe.dev"},"trustedPublisher":{"id":"github","oidcConfigId":"oidc:c3c859c0-f2b3-466e-9d13-dd4b8f58ba81"}},"_resolved":"/home/runner/work/_temp/uppt-tarballs/clickable-path-0.1.0.tgz","_integrity":"sha512-JRBIpDbw7S1vaEGvCXfm728cfchkUDtv4I2DjWMMm7IoEygxuFWhO6UQOrg+u61TPI13c/HsGG/RLwl3NBt+4w==","repository":{"url":"git+https://github.com/danielroe/clickable-path.git","type":"git"},"_npmVersion":"12.0.2","description":"Make file paths printed by CLIs ctrl/cmd-clickable, using OSC 8 hyperlinks","directories":{},"nano-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"sideEffects":false,"_nodeVersion":"24.19.0","typesVersions":{"*":{"*":["./dist/index.d.mts"]}},"_hasShrinkwrap":false,"devDependencies":{"knip":"6.32.2","eslint":"10.9.0","tsdown":"0.22.14","vitest":"4.1.11","typescript":"6.0.3","@types/node":"26.2.0","nano-staged":"1.0.2","installed-check":"11.0.0","simple-git-hooks":"2.13.1","@vitest/coverage-v8":"4.1.11","@antfu/eslint-config":"9.3.0"},"simple-git-hooks":{"pre-commit":"npx nano-staged"},"_npmOperationalInternal":{"tmp":"tmp/clickable-path_0.1.0_1787867145706_0.5635836010822457","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"clickable-path","version":"0.1.1","license":"MIT","_id":"clickable-path@0.1.1","maintainers":[{"name":"danielroe","email":"daniel@roe.dev"}],"homepage":"https://github.com/danielroe/clickable-path#readme","bugs":{"url":"https://github.com/danielroe/clickable-path/issues"},"dist":{"shasum":"c11c5fddbf0781f6f7382b529c5e1d7f9124839a","tarball":"https://registry.npmjs.org/clickable-path/-/clickable-path-0.1.1.tgz","fileCount":5,"integrity":"sha512-ROn/mdV2pR8WFdpJjFDCSouLRg9myf95xacO1iy8G/AVO/x5y124pjF3EaoWrTBRWC3vh0DPqa/MhKyx3mMeKg==","signatures":[{"sig":"MEQCIHcJMryvy0VWnQEiDCTMmwusOrGEpCJHlD6MiZgNxbXRAiB7OG4YQ1DrfjpAFjiDZsELkr5O7xKif8iUdDxWMDRnsg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/clickable-path@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20744},"type":"module","_from":"file:/home/runner/work/_temp/uppt-tarballs/clickable-path-0.1.1.tgz","types":"./dist/index.d.mts","engines":{"node":">=22.1.0"},"exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"scripts":{"dev":"vitest dev","lint":"eslint . --fix","test":"pnpm test:unit && pnpm test:types","build":"tsdown","test:knip":"knip","test:unit":"vitest","test:types":"tsc --noEmit","test:versions":"installed-check -d --no-workspaces"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","approver":{"name":"danielroe","email":"daniel@roe.dev"},"trustedPublisher":{"id":"github","oidcConfigId":"oidc:c3c859c0-f2b3-466e-9d13-dd4b8f58ba81"}},"_resolved":"/home/runner/work/_temp/uppt-tarballs/clickable-path-0.1.1.tgz","_integrity":"sha512-ROn/mdV2pR8WFdpJjFDCSouLRg9myf95xacO1iy8G/AVO/x5y124pjF3EaoWrTBRWC3vh0DPqa/MhKyx3mMeKg==","repository":{"url":"git+https://github.com/danielroe/clickable-path.git","type":"git"},"_npmVersion":"12.0.2","description":"Make file paths printed by CLIs ctrl/cmd-clickable, using OSC 8 hyperlinks","directories":{},"nano-staged":{"*.{js,ts,mjs,cjs,json,.*rc}":["npx eslint --fix"]},"sideEffects":false,"_nodeVersion":"24.19.0","typesVersions":{"*":{"*":["./dist/index.d.mts"]}},"_hasShrinkwrap":false,"devDependencies":{"knip":"6.34.0","eslint":"10.9.1","tsdown":"0.22.14","vitest":"4.1.11","typescript":"6.0.3","@types/node":"26.4.1","nano-staged":"1.0.2","installed-check":"11.0.0","simple-git-hooks":"2.14.0","@vitest/coverage-v8":"4.1.11","@antfu/eslint-config":"9.5.1"},"simple-git-hooks":{"pre-commit":"npx nano-staged"},"_npmOperationalInternal":{"tmp":"tmp/clickable-path_0.1.1_1788461730714_0.23564046898131763","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-07-26T12:27:42.067Z","modified":"2026-09-29T12:34:15.974Z","0.0.0":"2026-07-26T12:27:42.380Z","0.0.1":"2026-07-26T15:46:57.426Z","0.1.0":"2026-08-27T21:45:45.788Z","0.1.1":"2026-09-03T18:55:30.795Z"},"bugs":{"url":"https://github.com/danielroe/clickable-path/issues"},"license":"MIT","homepage":"https://github.com/danielroe/clickable-path#readme","repository":{"url":"git+https://github.com/danielroe/clickable-path.git","type":"git"},"description":"Make file paths printed by CLIs ctrl/cmd-clickable, using OSC 8 hyperlinks","maintainers":[{"email":"43081james@gmail.com","name":"43081j"},{"email":"daniel@roe.dev","name":"danielroe"}],"readme":"# clickable-path\n\n[![npm version][npm-version-src]][npm-version-href]\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![Github Actions][github-actions-src]][github-actions-href]\n[![Codecov][codecov-src]][codecov-href]\n\n> Make the file paths your CLI prints ctrl/cmd-clickable\n\nCLIs print paths, but making them open can be tricky.\n\nThankfully, [OSC 8 hyperlinks](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) exist. They point at an invisible absolute `file://` URL.\n\n`clickable-path` is a zero-dependency package to print paths as OSC 8 hyperlinks if your terminal supports them, falling back to a plain label if not.\n\n## Usage\n\n```sh\nnpm install clickable-path\n```\n\n> [!NOTE]\n> Requires Node 22.1 or newer, which is where `pathToFileURL` gained the `windows` option used to convert Windows-shaped paths on any platform.\n\n```js\nimport { link } from 'clickable-path'\n\nconsole.log(`Building ${link('/home/me/project/nuxt.config.ts')}`)\n// -> label `nuxt.config.ts`, linking file:///home/me/project/nuxt.config.ts\n\nconsole.log(link('src/index.ts', { line: 12 }))\n// -> label `src/index.ts:12`, linking file:///home/me/project/src/index.ts#L12\n```\n\n### API\n\n#### `link(path, options?)`\n\nWraps `path` in an OSC 8 hyperlink pointing at it on disk, labelled with the `cwd`-relative form (plus `:<line>:<column>` if given) or with whatever `options.formatter` returns. Relative input is resolved against `options.cwd`.\n\n> [!NOTE]\n> `util.stripVTControlCharacters` corrupts these sequences on current Node releases, choking on the comma in `#L12,3` ([fixed](https://github.com/nodejs/node/pull/64319) but unreleased). Measure visible width with your own OSC 8-aware regex.\n\n#### `hyperlink(label, url, options?)`\n\nWraps `label` in an OSC 8 hyperlink pointing at `url`, which is used as the target verbatim: no path resolution and no `file://` conversion. Use this for links that are already URLs (a docs page, an issue, a `vscode://` deep link); use `link` for file paths.\n\n```js\nimport { hyperlink } from 'clickable-path'\n\nconsole.log(hyperlink('E1: missing config', 'https://nuxt.com/docs/errors/e1'))\n```\n\n`label` is emitted byte-for-byte, so a label that already contains colour escapes is passed through untouched. Accepts the `enabled`, `stream` and `id` options (`HyperlinkOptions`), and returns `label` alone when hyperlinks are unsupported.\n\n#### `createLinker(defaults?)`\n\nReturns a `{ link }` with `defaults` pre-applied, so you can configure a `formatter` and cwd once rather than at every call site:\n\n```js\nconst { link } = createLinker({\n  formatter: absolute => absolute.replace(rootDir, '~'),\n})\n\nconsole.log(link('/project/app/tailwind.config.ts'))\n// label `~/tailwind.config.ts`, linking file:///project/app/tailwind.config.ts\n```\n\nThe formatter receives the resolved absolute path, plus `line` and `column` if they were passed, and its return value is used without modification. (The default formatter is `path.relative` with a `:<line>:<column>` suffix.) Showing the position is up to the formatter; a label that omits it still links to it, so the file opens at the right line either way. Every `LinkOptions` key can be defaulted this way and overridden per call.\n\n> [!TIP]\n> Pad and align inside the formatter, not on the result. The returned string contains invisible escapes, so `link(path).padEnd(20)` pads to the wrong width, while `formatter: absolute => basename(absolute).padEnd(20)` lines up as expected.\n\n#### `supportsHyperlinks(stream?)`\n\nWhether `stream` (default `process.stdout`) will render hyperlinks.\n\nThe environment is read on every call rather than snapshotted at module load, so a `.env` file or a `--no-color` flag applied after import is still respected. It costs around a microsecond; if you are linking in a hot loop, call this once and pass the result as `enabled`.\n\n#### `LinkOptions`\n\n| Option | Default | |\n| --- | --- | --- |\n| `formatter` | `cwd`-relative path plus `:<line>:<column>` | builds the label, given the absolute path, `line` and `column` |\n| `cwd` | `process.cwd()`, read at call time | base for relative paths |\n| `stream` | `process.stdout` | stream whose TTY state gates output |\n| `line` / `column` | | shown as `:<line>:<column>` and linked as `#L<line>,<column>` |\n| `id` | | OSC 8 `id` param, so a label wrapped across lines hovers as one link |\n| `enabled` | detection result | force on/off |\n\nPaths are converted with `pathToFileURL`, so spaces, `#`, `?` and non-ASCII characters are percent-encoded. Windows-shaped inputs (`C:\\...`, `\\\\server\\share\\...`) are converted on any platform.\n\n### Non-TTY and CI\n\n> [!NOTE]\n> No escapes are emitted when the target stream isn't a TTY, or when `CI` is set, as they would otherwise end up in log files. Netlify is the exception, since it renders build logs as HTML and never allocates a TTY.\n\nOverrides, in order of precedence: `FORCE_HYPERLINK` (set to `0` to disable), then `NO_COLOR` / `NO_HYPERLINK` / `NO_HYPERLINKS`.\n\n> [!WARNING]\n> `FORCE_HYPERLINK=1` bypasses every check, including the CI and non-TTY ones. Escape sequences will end up in whatever you are redirecting to.\n\n`NO_COLOR` disables hyperlinks here. Colour support and hyperlink support are not the same capability, so there is no general colour-support check, but someone who has asked for no escape sequences at all should get none.\n\n### Terminal support\n\n| Terminal | Detection |\n| --- | --- |\n| Windows Terminal >= 1.4 | `WT_SESSION` (any other terminal on win32 is treated as unsupported) |\n| VS Code >= 1.72 | `TERM_PROGRAM=vscode` + version |\n| Cursor | `TERM_PROGRAM=vscode` + `CURSOR_TRACE_ID` (own 0.x version line) |\n| iTerm2 >= 3.1 | `TERM_PROGRAM=iTerm.app` + version |\n| WezTerm >= 20200620 | `TERM_PROGRAM=WezTerm`, including Nix's `0-unstable-YYYY-MM-DD` scheme |\n| ghostty | `TERM_PROGRAM=ghostty` or `TERM=xterm-ghostty` |\n| kitty | `TERM=xterm-kitty` |\n| Alacritty >= 0.11 | `TERM=alacritty` |\n| zed, rio, Tabby, Warp, Orca | `TERM_PROGRAM` |\n| GNOME Terminal / VTE >= 0.50.1 | `VTE_VERSION` (0.50.0 is excluded: it segfaults on hyperlinks) |\n| tmux >= 3.4 | `TERM_PROGRAM=tmux` + version |\n\nTerminal.app is explicitly unsupported: it ignores OSC 8, though it degrades gracefully to the plain label. TeamCity is excluded. Anything unrecognised gets no escapes, since a wrong positive prints visible junk.\n\nPassing `line` (and optionally `column`) appends `:12:3` to the default label and `#L12,3` to the URL. Most terminals ignore the fragment and simply open the file, so treat jump-to-line as a hint. You can decide whether to show a position in a custom `formatter` if you want.\n\n> [!IMPORTANT]\n> The comma in `#L12,3` is deliberate. VS Code parses the fragment with `/^L?(\\d+)(?:,(\\d+))?/`, so `#L12:3` matches the line and silently drops the column.\n\n### Differences from `terminal-link` and `supports-hyperlinks`\n\n- **When hyperlinks are unsupported, only the label is printed.** `terminal-link` falls back to appending the raw URL (`nuxt.config.ts file:///home/me/nuxt.config.ts`), which is noise in a log file and breaks any width maths. Here the output is exactly what you would have printed anyway.\n- **tmux is detected.** tmux overwrites `TERM_PROGRAM` with `tmux`, hiding the outer terminal, so `supports-hyperlinks` reports no support inside every tmux session. tmux itself has handled OSC 8 since 3.4, so that version and up are supported directly.\n- **Detection reads the environment per call.** `supports-hyperlinks` snapshots `supportsHyperlinks.stdout` at module load, so anything that mutates the environment after import is missed, such as loading a `.env` file, or normalising `--no-color` into `NO_COLOR` while parsing argv.\n- **No colour-support coupling.** `supports-hyperlinks` returns false whenever `supports-color` does, but this isn't necessarily correct. (We still honour `NO_COLOR` if set.)\n- **The OSC 8 `id` param is exposed**, which `terminal-link` does not surface.\n- **Labels are derived, not passed in.** `terminal-link(text, url)` makes every call site build both halves; here the path is the argument and the label comes from a formatter you configure once.\n- **Zero dependencies**, versus `supports-color` + `has-flag` + `ansi-escapes`.\n\n## Credits\n\n- [`supports-hyperlinks`](https://github.com/chalk/supports-hyperlinks) and [`terminal-link`](https://github.com/sindresorhus/terminal-link) by [Sindre Sorhus](https://github.com/sindresorhus) and [James Talmage](https://github.com/jamestalmage) are excellent. Detection coverage in this package is informed by `supports-hyperlinks`, reimplemented so there are no dependencies and no module-load-time caching. If you want hyperlinks in general rather than paths specifically, `terminal-link` would be a good choice.\n- [Egmont Koblinger](https://github.com/egmontkob)'s [hyperlinks in terminal emulators](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda) is the de facto OSC 8 spec.\n\n## 💻 Development\n\n- Clone this repository\n- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`\n- Install dependencies using `pnpm install`\n- Run interactive tests using `pnpm dev`\n\n## License\n\nMade with ❤️\n\nPublished under [MIT License](./LICENCE).\n\n<!-- Badges -->\n\n[npm-version-src]: https://npmx.dev/api/registry/badge/version/clickable-path\n[npm-version-href]: https://npmx.dev/package/clickable-path\n[npm-downloads-src]: https://npmx.dev/api/registry/badge/downloads/clickable-path\n[npm-downloads-href]: https://npm.chart.dev/clickable-path\n[github-actions-src]: https://img.shields.io/github/actions/workflow/status/danielroe/clickable-path/ci.yml?branch=main&style=flat-square\n[github-actions-href]: https://github.com/danielroe/clickable-path/actions?query=workflow%3Aci\n[codecov-src]: https://img.shields.io/codecov/c/gh/danielroe/clickable-path/main?style=flat-square\n[codecov-href]: https://codecov.io/gh/danielroe/clickable-path\n","readmeFilename":"README.md"}