From 3ef7855da2b1bd22fa27c688d852de09bf9dba0f Mon Sep 17 00:00:00 2001 From: Ariel Caplan Date: Fri, 5 Jun 2026 06:42:07 +0300 Subject: [PATCH] Remove ansi-escapes from cli-kit; inline OSC-8 hyperlink Co-Authored-By: Claude --- packages/cli-kit/package.json | 1 - packages/cli-kit/src/private/node/content-tokens.ts | 4 ++-- packages/cli-kit/src/private/node/hyperlink.ts | 10 ++++++++++ .../cli-kit/src/private/node/ui/components/Link.tsx | 4 ++-- .../private/node/ui/components/TokenizedText.test.tsx | 6 +++--- pnpm-lock.yaml | 3 --- 6 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 packages/cli-kit/src/private/node/hyperlink.ts diff --git a/packages/cli-kit/package.json b/packages/cli-kit/package.json index 7aea96c42f0..625b502f43f 100644 --- a/packages/cli-kit/package.json +++ b/packages/cli-kit/package.json @@ -115,7 +115,6 @@ "@opentelemetry/sdk-metrics": "1.30.0", "@types/archiver": "5.3.2", "ajv": "8.18.0", - "ansi-escapes": "6.2.1", "archiver": "5.3.2", "bottleneck": "2.19.5", "chalk": "5.4.1", diff --git a/packages/cli-kit/src/private/node/content-tokens.ts b/packages/cli-kit/src/private/node/content-tokens.ts index 5f2cbb5eee3..84799366c22 100644 --- a/packages/cli-kit/src/private/node/content-tokens.ts +++ b/packages/cli-kit/src/private/node/content-tokens.ts @@ -1,7 +1,7 @@ +import {osc8Link} from './hyperlink.js' import colors from '../../public/node/colors.js' import {OutputMessage, stringifyMessage} from '../../public/node/output.js' import {relativizePath} from '../../public/node/path.js' -import ansiEscapes from 'ansi-escapes' import supportsHyperlinks from 'supports-hyperlinks' import cjs from 'color-json' import type {Change} from 'diff' @@ -37,7 +37,7 @@ export class LinkContentToken extends ContentToken { const url = this.link ?? '' const defaultFallback = this.value === this.link ? text : `${text} ( ${url} )` if (supportsHyperlinks.stdout) { - return ansiEscapes.link(text, url) + return osc8Link(text, url) } return this.fallback ?? defaultFallback } diff --git a/packages/cli-kit/src/private/node/hyperlink.ts b/packages/cli-kit/src/private/node/hyperlink.ts new file mode 100644 index 00000000000..6ec71edd443 --- /dev/null +++ b/packages/cli-kit/src/private/node/hyperlink.ts @@ -0,0 +1,10 @@ +/** + * Wraps `text` in an OSC-8 terminal hyperlink escape sequence pointing at `url`. + * + * See https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda for the + * OSC-8 spec. The terminal must support hyperlinks for this to render as a link; + * callers should gate on `supports-hyperlinks` before using it. + */ +export function osc8Link(text: string, url: string): string { + return `\x1b]8;;${url}\x07${text}\x1b]8;;\x07` +} diff --git a/packages/cli-kit/src/private/node/ui/components/Link.tsx b/packages/cli-kit/src/private/node/ui/components/Link.tsx index c5e3733fbdb..9414af62882 100644 --- a/packages/cli-kit/src/private/node/ui/components/Link.tsx +++ b/packages/cli-kit/src/private/node/ui/components/Link.tsx @@ -1,7 +1,7 @@ import {LinksContext, ContextValue as LinksContextValue} from '../contexts/LinksContext.js' +import {osc8Link} from '../../hyperlink.js' import {Text} from 'ink' import React, {FunctionComponent, useContext} from 'react' -import ansiEscapes from 'ansi-escapes' import supportsHyperlinks from 'supports-hyperlinks' import chalk from 'chalk' @@ -27,7 +27,7 @@ function link(label: string | undefined, url: string, linksContext: LinksContext return label ? `${label} [${linkId}]` : `[${linkId}]` } - return ansiEscapes.link(label ?? url, url) + return osc8Link(label ?? url, url) } /** diff --git a/packages/cli-kit/src/private/node/ui/components/TokenizedText.test.tsx b/packages/cli-kit/src/private/node/ui/components/TokenizedText.test.tsx index f81b38161da..a2c89426753 100644 --- a/packages/cli-kit/src/private/node/ui/components/TokenizedText.test.tsx +++ b/packages/cli-kit/src/private/node/ui/components/TokenizedText.test.tsx @@ -9,9 +9,9 @@ import React, {FunctionComponent, useRef} from 'react' vi.mock('supports-hyperlinks') -// Matches the on-the-wire OSC 8 sequence emitted by `ansiEscapes.link`, -// which is what `` ultimately renders when the terminal supports -// hyperlinks. Format: `ESC ] 8 ; ; URL BEL TEXT ESC ] 8 ; ; BEL`. +// Matches the on-the-wire OSC 8 sequence emitted by `osc8Link`, which is what +// `` ultimately renders when the terminal supports hyperlinks. +// Format: `ESC ] 8 ; ; URL BEL TEXT ESC ] 8 ; ; BEL`. function asOsc8Link(url: string, label?: string) { return `\u001b]8;;${url}\u0007${label ?? url}\u001b]8;;\u0007` } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2425ace27fe..bde37b9f75c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -336,9 +336,6 @@ importers: ajv: specifier: 8.18.0 version: 8.18.0 - ansi-escapes: - specifier: 6.2.1 - version: 6.2.1 archiver: specifier: 5.3.2 version: 5.3.2