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