diff --git a/packages/ui/package.json b/packages/ui/package.json index 0482b008c..2132684af 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -66,6 +66,9 @@ "@types/three": "^0.172.0", "@vintl/how-ago": "^3.0.1", "@vueuse/core": "^11.1.0", + "@xterm/addon-fit": "^0.11.0", + "@xterm/addon-search": "^0.16.0", + "@xterm/xterm": "^6.0.0", "ace-builds": "^1.43.5", "apexcharts": "^4.0.0", "dayjs": "^1.11.10", @@ -74,8 +77,8 @@ "fuse.js": "^6.6.2", "highlight.js": "^11.9.0", "intl-messageformat": "^10.7.7", - "lru-cache": "^11.2.4", "jszip": "^3.10.1", + "lru-cache": "^11.2.4", "markdown-it": "^13.0.2", "postprocessing": "^6.37.6", "qrcode.vue": "^3.4.1", diff --git a/packages/ui/src/components/base/BaseTerminal.vue b/packages/ui/src/components/base/BaseTerminal.vue new file mode 100644 index 000000000..2f30e0c8e --- /dev/null +++ b/packages/ui/src/components/base/BaseTerminal.vue @@ -0,0 +1,101 @@ + + + + + diff --git a/packages/ui/src/components/base/index.ts b/packages/ui/src/components/base/index.ts index 5e13e215b..4b72a2f5e 100644 --- a/packages/ui/src/components/base/index.ts +++ b/packages/ui/src/components/base/index.ts @@ -5,6 +5,7 @@ export { default as AutoBrandIcon } from './AutoBrandIcon.vue' export { default as AutoLink } from './AutoLink.vue' export { default as Avatar } from './Avatar.vue' export { default as Badge } from './Badge.vue' +export { default as BaseTerminal } from './BaseTerminal.vue' export { default as BigOptionButton } from './BigOptionButton.vue' export { default as BulletDivider } from './BulletDivider.vue' export { default as Button } from './Button.vue' diff --git a/packages/ui/src/composables/index.ts b/packages/ui/src/composables/index.ts index 7c517e787..5d1278a45 100644 --- a/packages/ui/src/composables/index.ts +++ b/packages/ui/src/composables/index.ts @@ -9,4 +9,5 @@ export * from './i18n-debug' export * from './page-leave-safety' export * from './scroll-indicator' export * from './sticky-observer' +export * from './terminal' export * from './virtual-scroll' diff --git a/packages/ui/src/composables/terminal.ts b/packages/ui/src/composables/terminal.ts new file mode 100644 index 000000000..ddfd50240 --- /dev/null +++ b/packages/ui/src/composables/terminal.ts @@ -0,0 +1,252 @@ +import type { FitAddon } from '@xterm/addon-fit' +import type { SearchAddon } from '@xterm/addon-search' +import type { ITerminalOptions, Terminal } from '@xterm/xterm' +import { + nextTick, + onBeforeUnmount, + onMounted, + type Ref, + ref, + type ShallowRef, + shallowRef, +} from 'vue' + +function getCssVar(name: string, fallback: string): string { + if (typeof document === 'undefined') return fallback + const value = getComputedStyle(document.documentElement).getPropertyValue(name).trim() + return value || fallback +} + +function buildTerminalTheme() { + const surface2 = getCssVar('--surface-2', '#1d1f23') + const surface5 = getCssVar('--surface-5', '#42444a') + const textDefault = getCssVar('--color-text-default', '#b0bac5') + const textTertiary = getCssVar('--color-text-tertiary', '#96a2b0') + const textPrimary = getCssVar('--color-text-primary', '#ffffff') + const red = getCssVar('--color-red', '#ff496e') + const orange = getCssVar('--color-orange', '#ffa347') + const green = getCssVar('--color-green', '#1bd96a') + const blue = getCssVar('--color-blue', '#4a9eff') + const purple = getCssVar('--color-purple', '#bc3fbc') + + return { + background: surface2, + foreground: textDefault, + cursor: textDefault, + cursorAccent: surface2, + selectionBackground: 'rgba(128, 128, 128, 0.3)', + black: surface2, + red, + green, + yellow: orange, + blue, + magenta: purple, + cyan: textTertiary, + white: textDefault, + brightBlack: surface5, + brightRed: red, + brightGreen: green, + brightYellow: orange, + brightBlue: blue, + brightMagenta: purple, + brightCyan: textTertiary, + brightWhite: textPrimary, + scrollbarSliderBackground: surface5, + scrollbarSliderHoverBackground: surface5, + scrollbarSliderActiveBackground: surface5, + } +} + +export interface UseTerminalOptions { + container: Ref + options?: ITerminalOptions + scrollback?: number + onReady?: (terminal: Terminal) => void +} + +export interface UseTerminalReturn { + terminal: ShallowRef + fitAddon: ShallowRef + searchAddon: ShallowRef + isAtBottom: Ref + write: (data: string) => void + writeln: (data: string) => void + clear: () => void + reset: () => void + fit: () => void + scrollToBottom: () => void +} + +export function useTerminal(options: UseTerminalOptions): UseTerminalReturn { + const terminal = shallowRef(null) + const fitAddon = shallowRef(null) + const searchAddon = shallowRef(null) + const isAtBottom = ref(true) + + let resizeObserver: ResizeObserver | null = null + let themeObserver: MutationObserver | null = null + let hasWritten = false + const pendingWrites: Array<{ data: string; newline: boolean }> = [] + + const write = (data: string) => { + if (terminal.value) { + terminal.value.write(data) + hasWritten = true + } else { + pendingWrites.push({ data, newline: false }) + } + } + + const writeln = (data: string) => { + if (terminal.value) { + if (hasWritten) { + terminal.value.write('\r\n' + data) + } else { + terminal.value.write(data) + hasWritten = true + } + } else { + pendingWrites.push({ data, newline: true }) + } + } + + const clear = () => { + terminal.value?.clear() + hasWritten = false + } + + const reset = () => { + terminal.value?.reset() + hasWritten = false + } + + const fit = () => { + const fa = fitAddon.value + const term = terminal.value + if (!fa || !term) return + const dims = fa.proposeDimensions() + if (dims) { + term.resize(dims.cols, dims.rows + 1) + } + } + + const scrollToBottom = () => { + terminal.value?.scrollToBottom() + isAtBottom.value = true + + // dont even ask, shit is broken as hell + // scrollToBottom is unreliable so we have to spam it to make sure it actually goes to the bottom + let calls = 0 + const interval = setInterval(() => { + terminal.value?.scrollToBottom() + if (++calls >= 10) clearInterval(interval) + }, 25) + } + + const checkIfAtBottom = () => { + const term = terminal.value + if (!term) return + const buffer = term.buffer.active + isAtBottom.value = buffer.baseY - buffer.viewportY <= 2 + } + + onMounted(async () => { + const container = options.container.value + if (!container) return + + const [{ Terminal }, { FitAddon }, { SearchAddon }] = await Promise.all([ + import('@xterm/xterm'), + import('@xterm/addon-fit'), + import('@xterm/addon-search'), + ]) + + await import('@xterm/xterm/css/xterm.css') + + const term = new Terminal({ + disableStdin: true, + scrollback: options.scrollback ?? 10000, + convertEol: true, + smoothScrollDuration: 125, + fontFamily: 'monospace', + fontSize: 14, + lineHeight: 1.5, + theme: buildTerminalTheme(), + ...options.options, + }) + + const fit = new FitAddon() + const search = new SearchAddon() + + term.loadAddon(fit) + term.loadAddon(search) + term.open(container) + await nextTick() + const dims = fit.proposeDimensions() + if (dims) { + term.resize(dims.cols, dims.rows + 1) + } + + term.options.disableStdin = true + term.write('\x1b[?25l') + + term.onScroll(() => checkIfAtBottom()) + term.onWriteParsed(() => { + if (isAtBottom.value) { + term.scrollToBottom() + } + }) + + terminal.value = term + fitAddon.value = fit + searchAddon.value = search + + for (const pending of pendingWrites) { + if (pending.newline) { + writeln(pending.data) + } else { + write(pending.data) + } + } + pendingWrites.length = 0 + + resizeObserver = new ResizeObserver(() => { + const d = fit.proposeDimensions() + if (d) { + term.resize(d.cols, d.rows + 1) + } + }) + resizeObserver.observe(container) + + themeObserver = new MutationObserver(() => { + term.options.theme = buildTerminalTheme() + }) + themeObserver.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-theme', 'class'], + }) + + options.onReady?.(term) + }) + + onBeforeUnmount(() => { + resizeObserver?.disconnect() + resizeObserver = null + themeObserver?.disconnect() + themeObserver = null + terminal.value?.dispose() + terminal.value = null + }) + + return { + terminal, + fitAddon, + searchAddon, + isAtBottom, + write, + writeln, + clear, + reset, + fit, + scrollToBottom, + } +} diff --git a/packages/ui/src/stories/base/BaseTerminal.stories.ts b/packages/ui/src/stories/base/BaseTerminal.stories.ts new file mode 100644 index 000000000..d70950152 --- /dev/null +++ b/packages/ui/src/stories/base/BaseTerminal.stories.ts @@ -0,0 +1,135 @@ +import type { Meta, StoryObj } from '@storybook/vue3-vite' +import { onMounted, onUnmounted, ref } from 'vue' + +import BaseTerminal from '../../components/base/BaseTerminal.vue' + +const meta = { + title: 'Base/BaseTerminal', + component: BaseTerminal, +} satisfies Meta + +export default meta + +export const Default: StoryObj = { + render: () => ({ + components: { BaseTerminal }, + setup() { + const termRef = ref | null>(null) + + onMounted(() => { + const t = termRef.value + if (!t) return + t.writeln('\x1b[1;32m=== Modrinth Server Console ===\x1b[0m') + t.writeln('') + t.writeln('\x1b[36m[10:15:30]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Loading properties') + t.writeln( + '\x1b[36m[10:15:30]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Default game type: SURVIVAL', + ) + t.writeln( + '\x1b[36m[10:15:31]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Starting Minecraft server on *:25565', + ) + t.writeln('\x1b[36m[10:15:32]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Preparing level "world"') + t.writeln( + "\x1b[36m[10:15:33]\x1b[0m \x1b[33m[Server/WARN]\x1b[0m: Can't keep up! Is the server overloaded?", + ) + t.writeln( + '\x1b[36m[10:15:34]\x1b[0m \x1b[31m[Server/ERROR]\x1b[0m: Connection reset by peer', + ) + t.writeln( + '\x1b[36m[10:15:35]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Done (4.523s)! For help, type "help"', + ) + }) + + return { termRef } + }, + template: /*html*/ ` +
+ +
+ `, + }), +} + +const SAMPLE_LINES = [ + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Player Steve joined the game', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Steve has made the advancement [Getting an Upgrade]', + "\x1b[36m[{time}]\x1b[0m \x1b[33m[Server/WARN]\x1b[0m: Can't keep up! Is the server overloaded? Running 2501ms behind", + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Preparing spawn area: 84%', + '\x1b[36m[{time}]\x1b[0m \x1b[31m[Server/ERROR]\x1b[0m: java.net.ConnectException: Connection timed out', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: [Fabric] Loading 127 mods', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Environment: authlib=6.0.54, java=21.0.3', + '\x1b[36m[{time}]\x1b[0m \x1b[33m[Server/WARN]\x1b[0m: Ambiguity between arguments at position 1', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Player Alex left the game', + '\x1b[36m[{time}]\x1b[0m \x1b[31m[Server/ERROR]\x1b[0m: Chunk file at [-3, 12] is missing level data, skipping', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: ThreadedAnvilChunkStorage: All chunks are saved', + '\x1b[36m[{time}]\x1b[0m \x1b[34m[Server/DEBUG]\x1b[0m: Reloading ResourceManager: Default, fabric', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Hello everyone!', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Saving the game (this may take a moment!)', + '\x1b[36m[{time}]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Saved the game', +] + +function getTimeString(): string { + const now = new Date() + return `${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}` +} + +export const StreamingLogs: StoryObj = { + render: () => ({ + components: { BaseTerminal }, + setup() { + const termRef = ref | null>(null) + let interval: ReturnType | null = null + let index = 0 + + onMounted(() => { + termRef.value?.writeln('\x1b[1;32m=== Modrinth Server Console ===\x1b[0m') + termRef.value?.writeln('') + + interval = setInterval(() => { + const line = SAMPLE_LINES[index % SAMPLE_LINES.length].replace('{time}', getTimeString()) + termRef.value?.writeln(line) + index++ + }, 25) + }) + + onUnmounted(() => { + if (interval) clearInterval(interval) + }) + + return { termRef } + }, + template: /*html*/ ` +
+ +
+ `, + }), +} + +export const WithInput: StoryObj = { + render: () => ({ + components: { BaseTerminal }, + setup() { + const termRef = ref | null>(null) + + const onCommand = (cmd: string) => { + termRef.value?.writeln(`\x1b[32m> ${cmd}\x1b[0m`) + } + + onMounted(() => { + termRef.value?.writeln('\x1b[1;32m=== Modrinth Server Console ===\x1b[0m') + termRef.value?.writeln('') + termRef.value?.writeln( + '\x1b[36m[10:15:35]\x1b[0m \x1b[32m[Server/INFO]\x1b[0m: Done! For help, type "help"', + ) + }) + + return { termRef, onCommand } + }, + template: /*html*/ ` +
+ +
+ `, + }), +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6e64a6e10..acb12e2cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -164,7 +164,7 @@ importers: devDependencies: '@eslint/compat': specifier: ^1.1.1 - version: 1.4.1(eslint@9.39.2(jiti@1.21.7)) + version: 1.4.1(eslint@9.39.2(jiti@2.6.1)) '@formatjs/cli': specifier: ^6.2.12 version: 6.12.2(@vue/compiler-core@3.5.27)(vue@3.5.27(typescript@5.9.3)) @@ -173,22 +173,22 @@ importers: version: link:../../packages/tooling-config '@nuxt/eslint-config': specifier: ^0.5.6 - version: 0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + version: 0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@taijased/vue-render-tracker': specifier: ^1.0.7 version: 1.0.7(vue@3.5.27(typescript@5.9.3)) '@vitejs/plugin-vue': specifier: ^6.0.3 - version: 6.0.4(vite@8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) + version: 6.0.4(vite@8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3)) autoprefixer: specifier: ^10.4.19 version: 10.4.24(postcss@8.5.6) eslint: specifier: ^9.9.1 - version: 9.39.2(jiti@1.21.7) + version: 9.39.2(jiti@2.6.1) eslint-plugin-turbo: specifier: ^2.5.4 - version: 2.8.2(eslint@9.39.2(jiti@1.21.7))(turbo@2.8.2) + version: 2.8.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.8.2) postcss: specifier: ^8.4.39 version: 8.5.6 @@ -206,7 +206,7 @@ importers: version: 5.9.3 vite: specifier: ^8.0.0 - version: 8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + version: 8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vue-component-type-helpers: specifier: ^3.1.8 version: 3.2.4 @@ -646,6 +646,15 @@ importers: '@vueuse/core': specifier: ^11.1.0 version: 11.3.0(vue@3.5.27(typescript@5.9.3)) + '@xterm/addon-fit': + specifier: ^0.11.0 + version: 0.11.0 + '@xterm/addon-search': + specifier: ^0.16.0 + version: 0.16.0 + '@xterm/xterm': + specifier: ^6.0.0 + version: 6.0.0 ace-builds: specifier: ^1.43.5 version: 1.43.6 @@ -736,7 +745,7 @@ importers: version: 5.2.4(vite@5.4.21(@types/node@20.19.31)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0))(vue@3.5.27(typescript@5.9.3)) eslint-plugin-storybook: specifier: ^10.1.10 - version: 10.2.4(eslint@9.39.2(jiti@2.6.1))(storybook@10.2.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) + version: 10.2.4(eslint@9.39.2(jiti@1.21.7))(storybook@10.2.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3) storybook: specifier: ^10.1.10 version: 10.2.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -4898,6 +4907,15 @@ packages: '@xml-tools/parser@1.0.11': resolution: {integrity: sha512-aKqQ077XnR+oQtHJlrAflaZaL7qZsulWc/i/ZEooar5JiWj1eLt0+Wg28cpa+XLney107wXqneC+oG1IZvxkTA==} + '@xterm/addon-fit@0.11.0': + resolution: {integrity: sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g==} + + '@xterm/addon-search@0.16.0': + resolution: {integrity: sha512-9OeuBFu0/uZJPu+9AHKY6g/w0Czyb/Ut0A5t79I4ULoU4IfU5BEpPFVGQxP4zTTMdfZEYkVIRYbHBX1xWwjeSA==} + + '@xterm/xterm@6.0.0': + resolution: {integrity: sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==} + '@yr/monotone-cubic-spline@1.0.3': resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==} @@ -10956,11 +10974,11 @@ snapshots: '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@1.4.1(eslint@9.39.2(jiti@1.21.7))': + '@eslint/compat@1.4.1(eslint@9.39.2(jiti@2.6.1))': dependencies: '@eslint/core': 0.17.0 optionalDependencies: - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) '@eslint/config-array@0.21.1': dependencies: @@ -11581,36 +11599,36 @@ snapshots: - utf-8-validate - vue - '@nuxt/eslint-config@0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@nuxt/eslint-config@0.5.7(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint/js': 9.39.2 - '@nuxt/eslint-plugin': 0.5.7(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) - eslint-config-flat-gitignore: 0.3.0(eslint@9.39.2(jiti@1.21.7)) + '@nuxt/eslint-plugin': 0.5.7(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) + eslint-config-flat-gitignore: 0.3.0(eslint@9.39.2(jiti@2.6.1)) eslint-flat-config-utils: 0.4.0 - eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-jsdoc: 50.8.0(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-unicorn: 55.0.0(eslint@9.39.2(jiti@1.21.7)) - eslint-plugin-vue: 9.33.0(eslint@9.39.2(jiti@1.21.7)) + eslint-plugin-import-x: 4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-jsdoc: 50.8.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-regexp: 2.10.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-unicorn: 55.0.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-vue: 9.33.0(eslint@9.39.2(jiti@2.6.1)) globals: 15.15.0 local-pkg: 0.5.1 pathe: 1.1.2 - vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@1.21.7)) + vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@2.6.1)) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-node - supports-color - typescript - '@nuxt/eslint-plugin@0.5.7(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': + '@nuxt/eslint-plugin@0.5.7(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.2(jiti@2.6.1) transitivePeerDependencies: - supports-color - typescript @@ -13087,18 +13105,6 @@ snapshots: '@stripe/stripe-js@7.9.0': {} - '@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - eslint: 9.39.2(jiti@1.21.7) - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - estraverse: 5.3.0 - picomatch: 4.0.3 - transitivePeerDependencies: - - supports-color - - typescript - '@stylistic/eslint-plugin@2.13.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) @@ -13110,7 +13116,6 @@ snapshots: transitivePeerDependencies: - supports-color - typescript - optional: true '@svgdotjs/svg.draggable.js@3.0.6(@svgdotjs/svg.js@3.2.5)': dependencies: @@ -13512,22 +13517,6 @@ snapshots: dependencies: '@types/node': 20.19.31 - '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 - eslint: 9.39.2(jiti@1.21.7) - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -13544,18 +13533,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 - debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.54.0 @@ -13586,18 +13563,6 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.54.0 @@ -13768,10 +13733,10 @@ snapshots: vite: 7.3.1(@types/node@20.19.31)(jiti@2.6.1)(lightningcss@1.32.0)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vue: 3.5.27(typescript@5.9.3) - '@vitejs/plugin-vue@6.0.4(vite@8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.4(vite@8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) + vite: 8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2) vue: 3.5.27(typescript@5.9.3) '@vitest/expect@3.2.4': @@ -14214,6 +14179,12 @@ snapshots: dependencies: chevrotain: 7.1.1 + '@xterm/addon-fit@0.11.0': {} + + '@xterm/addon-search@0.16.0': {} + + '@xterm/xterm@6.0.0': {} + '@yr/monotone-cubic-spline@1.0.3': {} abbrev@2.0.0: {} @@ -15291,10 +15262,10 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-flat-gitignore@0.3.0(eslint@9.39.2(jiti@1.21.7)): + eslint-config-flat-gitignore@0.3.0(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@1.21.7)) - eslint: 9.39.2(jiti@1.21.7) + '@eslint/compat': 1.4.1(eslint@9.39.2(jiti@2.6.1)) + eslint: 9.39.2(jiti@2.6.1) find-up-simple: 1.0.1 eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)): @@ -15312,12 +15283,12 @@ snapshots: optionalDependencies: unrs-resolver: 1.11.1 - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1)): dependencies: '@typescript-eslint/types': 8.54.0 comment-parser: 1.4.5 debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) eslint-import-context: 0.1.9(unrs-resolver@1.11.1) is-glob: 4.0.3 minimatch: 10.1.2 @@ -15325,18 +15296,18 @@ snapshots: stable-hash-x: 0.2.0 unrs-resolver: 1.11.1 optionalDependencies: - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - supports-color - eslint-plugin-jsdoc@50.8.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-jsdoc@50.8.0(eslint@9.39.2(jiti@2.6.1)): dependencies: '@es-joy/jsdoccomment': 0.50.2 are-docs-informative: 0.0.2 comment-parser: 1.4.1 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) espree: 10.4.0 esquery: 1.7.0 parse-imports-exports: 0.2.4 @@ -15354,12 +15325,12 @@ snapshots: optionalDependencies: eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-regexp@2.10.0(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 comment-parser: 1.4.5 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) jsdoc-type-pratt-parser: 4.8.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 @@ -15369,29 +15340,29 @@ snapshots: dependencies: eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-storybook@10.2.4(eslint@9.39.2(jiti@2.6.1))(storybook@10.2.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3): + eslint-plugin-storybook@10.2.4(eslint@9.39.2(jiti@1.21.7))(storybook@10.2.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) + '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@1.21.7))(typescript@5.9.3) + eslint: 9.39.2(jiti@1.21.7) storybook: 10.2.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) transitivePeerDependencies: - supports-color - typescript - eslint-plugin-turbo@2.8.2(eslint@9.39.2(jiti@1.21.7))(turbo@2.8.2): + eslint-plugin-turbo@2.8.2(eslint@9.39.2(jiti@2.6.1))(turbo@2.8.2): dependencies: dotenv: 16.0.3 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) turbo: 2.8.2 - eslint-plugin-unicorn@55.0.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-unicorn@55.0.0(eslint@9.39.2(jiti@2.6.1)): dependencies: '@babel/helper-validator-identifier': 7.28.5 - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) ci-info: 4.4.0 clean-regexp: 1.0.0 core-js-compat: 3.48.0 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) esquery: 1.7.0 globals: 15.15.0 indent-string: 4.0.0 @@ -15418,16 +15389,16 @@ snapshots: '@stylistic/eslint-plugin': 2.13.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-vue@9.33.0(eslint@9.39.2(jiti@1.21.7)): + eslint-plugin-vue@9.33.0(eslint@9.39.2(jiti@2.6.1)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@1.21.7)) - eslint: 9.39.2(jiti@1.21.7) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + eslint: 9.39.2(jiti@2.6.1) globals: 13.24.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.1.2 semver: 7.7.3 - vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@1.21.7)) + vue-eslint-parser: 9.4.3(eslint@9.39.2(jiti@2.6.1)) xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -19811,7 +19782,7 @@ snapshots: terser: 5.46.0 yaml: 2.8.2 - vite@8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@1.21.7)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2): + vite@8.0.3(@types/node@20.19.31)(esbuild@0.27.3)(jiti@2.6.1)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.2): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -19822,7 +19793,7 @@ snapshots: '@types/node': 20.19.31 esbuild: 0.27.3 fsevents: 2.3.3 - jiti: 1.21.7 + jiti: 2.6.1 sass: 1.97.3 terser: 5.46.0 yaml: 2.8.2 @@ -19987,10 +19958,10 @@ snapshots: transitivePeerDependencies: - supports-color - vue-eslint-parser@9.4.3(eslint@9.39.2(jiti@1.21.7)): + vue-eslint-parser@9.4.3(eslint@9.39.2(jiti@2.6.1)): dependencies: debug: 4.4.3 - eslint: 9.39.2(jiti@1.21.7) + eslint: 9.39.2(jiti@2.6.1) eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1