ronantakizawa/codereview-bench huggingface dataset:
Repository: moeru-ai/airi
File: apps/stage-tamagotchi/src/renderer/components/StageIslands/ControlsIsland/ControlsIslandFadeOnHover.vue (Vue)

Code before:
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

import ControlButton from './ControlButton.vue'
import ControlButtonTooltip from './ControlButtonTooltip.vue'

import { noticeWindowEventa } from '../../../../shared/eventa'
import { useElectronEventaInvoke } from '../../../composables/electron-vueuse/use-electron-eventa-context'
import { useControlsIslandStore } from '../../../stores/controls-island'

const uiStore = useControlsIslandStore()
const enabled = computed(() => uiStore.fadeOnHoverEnabled)
const { t } = useI18n()

const requestNotice = useElectronEventaInvoke(noticeWindowEventa.openWindow)
const NOTICE_WINDOW_ID = 'fade-on-hover'

async function handleToggle() {
  if (enabled.value) {
    uiStore.disableFadeOnHover()
    return
  }

  if (uiStore.fadeOnHoverNoticeDontShowAgain) {
    uiStore.enableFadeOnHover()
    return
  }

  try {
    const acknowledged = await requestNotice({
      id: NOTICE_WINDOW_ID,
      route: '/notice/fade-on-hover',
      type: 'fade-on-hover',
    })
    if (acknowledged)
      uiStore.enableFadeOnHover()
  }
  catch (error) {
    console.error('Failed to open fade-on-hover notice:', error)
  }
}
</script>

<template>
  <ControlButtonTooltip>
    <ControlButton
      :class="{ 'border-primary-300/70 shadow-[0_10px_24px_rgba(0,0,0,0.22)]': enabled }"
      @click="handleToggle"
    >

Review comment (suggestion):
```suggestion
  if (uiStore.dontShowItAgainNoticeFadeOnHover) {
```

Code after:
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

import ControlButton from './ControlButton.vue'
import ControlButtonTooltip from './ControlButtonTooltip.vue'

import { noticeWindowEventa } from '../../../../shared/eventa'
import { useElectronEventaInvoke } from '../../../composables/electron-vueuse/use-electron-eventa-context'
import { useControlsIslandStore } from '../../../stores/controls-island'

const uiStore = useControlsIslandStore()
const enabled = computed(() => uiStore.fadeOnHoverEnabled)
const { t } = useI18n()

const requestNotice = useElectronEventaInvoke(noticeWindowEventa.openWindow)
const NOTICE_WINDOW_ID = 'fade-on-hover'

async function handleToggle() {
  if (enabled.value) {
    uiStore.disableFadeOnHover()
    return
  }

  if (uiStore.dontShowItAgainNoticeFadeOnHover) {
    uiStore.enableFadeOnHover()
    return
  }

  try {
    const acknowledged = await requestNotice({
      id: NOTICE_WINDOW_ID,
      route: '/notice/fade-on-hover',
      type: 'fade-on-hover',
    })
    if (acknowledged)
      uiStore.enableFadeOnHover()
  }
  catch (error) {
    console.error('Failed to open fade-on-hover notice:', error)
  }
}
</script>

<template>
  <ControlButtonTooltip>
    <ControlButton
      :class="{ 'border-primary-300/70 shadow-[0_10px_24px_rgba(0,0,0,0.22)]': enabled }"
      @click="handleToggle"
    >
Repository: moeru-ai/airi
File: apps/stage-tamagotchi/src/renderer/pages/notice/fade-on-hover.vue (Vue)

Code before:
      requestId.value = pending.id
  }
  catch (error) {
    console.warn('Failed to notify notice window mounted:', error)
  }
})

onBeforeUnmount(async () => {
  try {
    await notifyUnmounted({ id: undefined })
  }
  catch {
    /* noop */
  }
})

async function handleAction(action: 'confirm' | 'cancel' | 'close') {
  const id = requestId.value
  if (!id) {
    window.close()
    return
  }

  try {
    if (action === 'confirm')
      toggleDontShowItAgain()
    await sendAction({ id, action })
  }
  catch (error) {
    console.warn('Failed to notify main process of notice action:', error)
  }
  finally {
    window.close()
  }
}
</script>

<template>
  <div class="h-100dvh w-100dvw">
    <div class="relative h-full w-full flex flex-col gap-4 text-neutral-900 dark:text-neutral-100">
      <div class="absolute inset-0 z-0 h-full w-full overflow-hidden text-xs text-neutral-600 dark:text-neutral-400">
        <video :src="isDark ? VideoTutorialFadeOnHoverDark : VideoTutorialFadeOnHoverLight" autoplay muted loop class="h-full w-full object-cover" />
      </div>
      <div
        :class="[
          'pointer-events-none absolute left-0 top-0',
          'h-100dvh w-100dvw',
        ]"
        class="heading-backdrop"
      />
      <div class="relative z-1 h-full w-full flex flex-col">

Review comment (suggestion):
```suggestion
      dontShowItAgainNoticeFadeOnHover.value = dontShowItAgainNoticeFadeOnHoverPending.value
```

Code after:
      requestId.value = pending.id
  }
  catch (error) {
    console.warn('Failed to notify notice window mounted:', error)
  }
})

onBeforeUnmount(async () => {
  try {
    await notifyUnmounted({ id: undefined })
  }
  catch {
    /* noop */
  }
})

async function handleAction(action: 'confirm' | 'cancel' | 'close') {
  const id = requestId.value
  if (!id) {
    window.close()
    return
  }

  try {
    if (action === 'confirm')
      dontShowItAgainNoticeFadeOnHover.value = dontShowItAgainNoticeFadeOnHoverPending.value
    await sendAction({ id, action })
  }
  catch (error) {
    console.warn('Failed to notify main process of notice action:', error)
  }
  finally {
    window.close()
  }
}
</script>

<template>
  <div class="h-100dvh w-100dvw">
    <div class="relative h-full w-full flex flex-col gap-4 text-neutral-900 dark:text-neutral-100">
      <div class="absolute inset-0 z-0 h-full w-full overflow-hidden text-xs text-neutral-600 dark:text-neutral-400">
        <video :src="isDark ? VideoTutorialFadeOnHoverDark : VideoTutorialFadeOnHoverLight" autoplay muted loop class="h-full w-full object-cover" />
      </div>
      <div
        :class="[
          'pointer-events-none absolute left-0 top-0',
          'h-100dvh w-100dvw',
        ]"
        class="heading-backdrop"
      />
      <div class="relative z-1 h-full w-full flex flex-col">
Repository: moeru-ai/airi
File: packages/stage-ui/src/components/misc/index.ts (TypeScript)

Code before:
export { default as Alert } from './Alert.vue'
export { default as Collapsable } from './Collapsable.vue'
export { default as ErrorContainer } from './ErrorContainer.vue'
export { default as Progress } from './Progress.vue'
export { default as Screen } from './Screen.vue'
export { default as Skeleton } from './Skeleton.vue'
export * from './Steppers'
export { default as WIP } from './WIP.vue'
export { DoubleCheckButton } from '@proj-airi/ui/components/Misc'


Review comment (suggestion):
```suggestion
export { DoubleCheckButton } from '@proj-airi/ui/components/misc'
```


Code after:
export { default as Alert } from './Alert.vue'
export { default as Collapsable } from './Collapsable.vue'
export { default as ErrorContainer } from './ErrorContainer.vue'
export { default as Progress } from './Progress.vue'
export { default as Screen } from './Screen.vue'
export { default as Skeleton } from './Skeleton.vue'
export * from './Steppers'
export { default as WIP } from './WIP.vue'
export { DoubleCheckButton } from '@proj-airi/ui/components/misc'
Repository: moeru-ai/airi
File: packages/stage-ui/src/stores/analytics/index.ts (TypeScript)

Code before:
import type { AboutBuildInfo } from '../../components/scenarios/about/types'

import posthog from 'posthog-js'

import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useSharedAnalyticsStore = defineStore('shared_analytics', () => {
  const isInitialized = ref(false)
  const buildInfo = ref<AboutBuildInfo>({
    version: '',
    commit: '',
    branch: '',
    builtOn: '',
  })
  const appStartTime = ref<number | null>(null)
  const firstMessageTracked = ref(false)

  function initialize(info: AboutBuildInfo) {
    if (isInitialized.value)
      return

    buildInfo.value = info
    appStartTime.value = Date.now()

    // Register metadata with PostHog after buildInfo is set
    posthog.register({
      app_version: (buildInfo.value.version && buildInfo.value.version !== '0.0.0') ? buildInfo.value.version : 'dev',
      app_commit: buildInfo.value.commit,
      app_branch: buildInfo.value.branch,
      app_build_time: buildInfo.value.builtOn,
    })


Review comment (suggestion):
```suggestion
export const useSharedAnalyticsStore = defineStore('analytics-shared', () => {
```

Code after:
import type { AboutBuildInfo } from '../../components/scenarios/about/types'

import posthog from 'posthog-js'

import { defineStore } from 'pinia'
import { ref } from 'vue'

export const useSharedAnalyticsStore = defineStore('analytics-shared', () => {
  const isInitialized = ref(false)
  const buildInfo = ref<AboutBuildInfo>({
    version: '',
    commit: '',
    branch: '',
    builtOn: '',
  })
  const appStartTime = ref<number | null>(null)
  const firstMessageTracked = ref(false)

  function initialize(info: AboutBuildInfo) {
    if (isInitialized.value)
      return

    buildInfo.value = info
    appStartTime.value = Date.now()

    // Register metadata with PostHog after buildInfo is set
    posthog.register({
      app_version: (buildInfo.value.version && buildInfo.value.version !== '0.0.0') ? buildInfo.value.version : 'dev',
      app_commit: buildInfo.value.commit,
      app_branch: buildInfo.value.branch,
      app_build_time: buildInfo.value.builtOn,
    })
Repository: moeru-ai/airi
File: packages/stage-pages/src/pages/settings/modules/speech.vue (Vue)

Code before:
<script setup lang="ts">
import type { SpeechProviderWithExtraOptions } from '@xsai-ext/shared-providers'

import {
  Alert,
  ErrorContainer,
  RadioCardManySelect,
  RadioCardSimple,
  Skeleton,
  TestDummyMarker,
  VoiceCardManySelect,
} from '@proj-airi/stage-ui/components'
import { useAnalytics } from '@proj-airi/stage-ui/composables/use-analytics'
import { useSpeechStore } from '@proj-airi/stage-ui/stores/modules/speech'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import {
  FieldCheckbox,
  FieldInput,
  FieldRange,
  Textarea,
} from '@proj-airi/ui'
import { generateSpeech } from '@xsai/generate-speech'
import { storeToRefs } from 'pinia'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterLink } from 'vue-router'

const { t } = useI18n()
const providersStore = useProvidersStore()
const speechStore = useSpeechStore()
const { configuredSpeechProvidersMetadata } = storeToRefs(providersStore)
const {
  activeSpeechProvider,
  activeSpeechModel,
  activeSpeechVoice,
  activeSpeechVoiceId,
  pitch,
  isLoadingSpeechProviderVoices,

Review comment (suggestion):
```suggestion
import { useAnalytics } from '@proj-airi/stage-ui/composables'
```

After exported, you can import them directly.

Code after:
<script setup lang="ts">
import type { SpeechProviderWithExtraOptions } from '@xsai-ext/shared-providers'

import {
  Alert,
  ErrorContainer,
  RadioCardManySelect,
  RadioCardSimple,
  Skeleton,
  TestDummyMarker,
  VoiceCardManySelect,
} from '@proj-airi/stage-ui/components'
import { useAnalytics } from '@proj-airi/stage-ui/composables'
import { useSpeechStore } from '@proj-airi/stage-ui/stores/modules/speech'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import {
  FieldCheckbox,
  FieldInput,
  FieldRange,
  Textarea,
} from '@proj-airi/ui'
import { generateSpeech } from '@xsai/generate-speech'
import { storeToRefs } from 'pinia'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterLink } from 'vue-router'

const { t } = useI18n()
const providersStore = useProvidersStore()
const speechStore = useSpeechStore()
const { configuredSpeechProvidersMetadata } = storeToRefs(providersStore)
const {
  activeSpeechProvider,
  activeSpeechModel,
  activeSpeechVoice,
  activeSpeechVoiceId,
  pitch,
  isLoadingSpeechProviderVoices,
Repository: moeru-ai/airi
File: packages/stage-pages/src/pages/settings/modules/consciousness.vue (Vue)

Code before:
<script setup lang="ts">
import { Alert, ErrorContainer, RadioCardManySelect, RadioCardSimple } from '@proj-airi/stage-ui/components'
import { useAnalytics } from '@proj-airi/stage-ui/composables/use-analytics'
import { useConsciousnessStore } from '@proj-airi/stage-ui/stores/modules/consciousness'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import { storeToRefs } from 'pinia'
import { watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterLink } from 'vue-router'

const providersStore = useProvidersStore()
const consciousnessStore = useConsciousnessStore()
const { persistedChatProvidersMetadata, configuredProviders } = storeToRefs(providersStore)
const {
  activeProvider,
  activeModel,
  customModelName,
  modelSearchQuery,
  supportsModelListing,
  providerModels,
  isLoadingActiveProviderModels,
  activeProviderModelError,
} = storeToRefs(consciousnessStore)

const { t } = useI18n()
const { trackProviderClick } = useAnalytics()

watch(activeProvider, async (provider) => {

Review comment (suggestion):
```suggestion
import { useAnalytics } from '@proj-airi/stage-ui/composables'
```

After exported, you can import them directly.

Code after:
<script setup lang="ts">
import { Alert, ErrorContainer, RadioCardManySelect, RadioCardSimple } from '@proj-airi/stage-ui/components'
import { useAnalytics } from '@proj-airi/stage-ui/composables'
import { useConsciousnessStore } from '@proj-airi/stage-ui/stores/modules/consciousness'
import { useProvidersStore } from '@proj-airi/stage-ui/stores/providers'
import { storeToRefs } from 'pinia'
import { watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterLink } from 'vue-router'

const providersStore = useProvidersStore()
const consciousnessStore = useConsciousnessStore()
const { persistedChatProvidersMetadata, configuredProviders } = storeToRefs(providersStore)
const {
  activeProvider,
  activeModel,
  customModelName,
  modelSearchQuery,
  supportsModelListing,
  providerModels,
  isLoadingActiveProviderModels,
  activeProviderModelError,
} = storeToRefs(consciousnessStore)

const { t } = useI18n()
const { trackProviderClick } = useAnalytics()

watch(activeProvider, async (provider) => {
Repository: moeru-ai/airi
File: apps/stage-web/src/main.ts (TypeScript)

Code before:
import type { Plugin } from 'vue'
import type { Router, RouteRecordRaw } from 'vue-router'

import Tres from '@tresjs/core'
import buildTime from '~build/time'
import NProgress from 'nprogress'

import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics/index'
import { MotionPlugin } from '@vueuse/motion'
import { abbreviatedSha, branch } from '~build/git'
import { version } from '~build/package'
import { createPinia } from 'pinia'
import { setupLayouts } from 'virtual:generated-layouts'
import { createApp } from 'vue'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import { routes } from 'vue-router/auto-routes'

import App from './App.vue'

import { i18n } from './modules/i18n'

import './modules/posthog'

// eslint-disable-next-line perfectionist/sort-imports
import '@proj-airi/font-cjkfonts-allseto/index.css'
import '@proj-airi/font-xiaolai/index.css'
import '@unocss/reset/tailwind.css'
import './styles/main.css'
import 'uno.css'

const pinia = createPinia()

// Initialize analytics

Review comment (suggestion):
```suggestion
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics'
```

Code after:
import type { Plugin } from 'vue'
import type { Router, RouteRecordRaw } from 'vue-router'

import Tres from '@tresjs/core'
import buildTime from '~build/time'
import NProgress from 'nprogress'

import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics'
import { MotionPlugin } from '@vueuse/motion'
import { abbreviatedSha, branch } from '~build/git'
import { version } from '~build/package'
import { createPinia } from 'pinia'
import { setupLayouts } from 'virtual:generated-layouts'
import { createApp } from 'vue'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import { routes } from 'vue-router/auto-routes'

import App from './App.vue'

import { i18n } from './modules/i18n'

import './modules/posthog'

// eslint-disable-next-line perfectionist/sort-imports
import '@proj-airi/font-cjkfonts-allseto/index.css'
import '@proj-airi/font-xiaolai/index.css'
import '@unocss/reset/tailwind.css'
import './styles/main.css'
import 'uno.css'

const pinia = createPinia()

// Initialize analytics
Repository: moeru-ai/airi
File: apps/stage-tamagotchi/src/renderer/main.ts (TypeScript)

Code before:
import type { Plugin } from 'vue'
import type { RouteRecordRaw } from 'vue-router'

import Tres from '@tresjs/core'
import buildTime from '~build/time'

import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics/index'
import { MotionPlugin } from '@vueuse/motion'
import { abbreviatedSha, branch } from '~build/git'
import { version } from '~build/package'
import { createPinia } from 'pinia'
import { setupLayouts } from 'virtual:generated-layouts'
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import { routes } from 'vue-router/auto-routes'

import App from './App.vue'

import { i18n } from './modules/i18n'

import './modules/posthog'

// eslint-disable-next-line perfectionist/sort-imports
import '@unocss/reset/tailwind.css'
import 'uno.css'
import './styles/main.css'
// Fonts
import '@proj-airi/font-cjkfonts-allseto/index.css'
import '@proj-airi/font-xiaolai/index.css'
import '@fontsource-variable/dm-sans'
import '@fontsource-variable/jura'
import '@fontsource-variable/quicksand'

Review comment (suggestion):
```suggestion
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics'
```

Code after:
import type { Plugin } from 'vue'
import type { RouteRecordRaw } from 'vue-router'

import Tres from '@tresjs/core'
import buildTime from '~build/time'

import { autoAnimatePlugin } from '@formkit/auto-animate/vue'
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics'
import { MotionPlugin } from '@vueuse/motion'
import { abbreviatedSha, branch } from '~build/git'
import { version } from '~build/package'
import { createPinia } from 'pinia'
import { setupLayouts } from 'virtual:generated-layouts'
import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'
import { routes } from 'vue-router/auto-routes'

import App from './App.vue'

import { i18n } from './modules/i18n'

import './modules/posthog'

// eslint-disable-next-line perfectionist/sort-imports
import '@unocss/reset/tailwind.css'
import 'uno.css'
import './styles/main.css'
// Fonts
import '@proj-airi/font-cjkfonts-allseto/index.css'
import '@proj-airi/font-xiaolai/index.css'
import '@fontsource-variable/dm-sans'
import '@fontsource-variable/jura'
import '@fontsource-variable/quicksand'
Repository: moeru-ai/airi
File: packages/stage-ui-three/src/components/ThreeScene.vue (Vue)

Code before:
  updateDirLightTarget(newRotation)
}, { deep: true })

defineExpose({
  setExpression: (expression: string) => {
    modelRef.value?.setExpression(expression)
  },
  setVrmFrameHook: (hook?: (vrm: VRM, delta: number) => void) => {
    vrmFrameHook.value = hook
    applyVrmFrameHook()
  },
  canvasElement: () => {
    return tresCanvasRef.value?.renderer.instance.domElement
  },
})
</script>

<template>
  <div ref="sceneContainerRef" w="100%" h="100%">
    <TresCanvas
      v-show="true"
      :camera="camera"
      :antialias="true"
      :width="width"
      :height="height"
      :window-size="true"
      :tone-mapping="ACESFilmicToneMapping"
      :tone-mapping-exposure="1"
      :clear-alpha="0"
      @ready="onTresReady"
    >
      <OrbitControls
        ref="controlsRef"
        :control-enable="controlEnable"
        :model-loaded="modelLoaded"
        :model-size="modelSize"
        :camera-position="cameraPosition"
        :camera-target="modelOrigin"
        :camera-f-o-v="cameraFOV"
        :camera-distance="cameraDistance"
        @orbit-controls-camera-changed="onOrbitControlsCameraChanged"
        @orbit-controls-ready="onOrbitControlsReady"
      />
      <SkyBox
        v-if="envSelect === 'skyBox'"
        ref="skyBoxEnvRef"
        :sky-box-src="skyBoxSrc"
        :as-background="true"
        @sky-box-ready="onSkyBoxReady"
      />
      <TresHemisphereLight

Review comment (suggestion):
`TresCanvas: The canvas has no area, so nothing can be rendered. Set it manually on the parent element or use the prop windowSize.`

Code after:
watch(directionalLightRotation, (newRotation) => {
  updateDirLightTarget(newRotation)
}, { deep: true })

defineExpose({
  setExpression: (expression: string) => {
    modelRef.value?.setExpression(expression)
  },
  setVrmFrameHook: (hook?: (vrm: VRM, delta: number) => void) => {
    vrmFrameHook.value = hook
    applyVrmFrameHook()
  },
  canvasElement: () => {
    return tresCanvasRef.value?.renderer.instance.domElement
  },
})
</script>

<template>
  <Screen>
    <div ref="sceneContainerRef" class="h-full w-full">
      <TresCanvas
        v-show="true"
        :camera="camera"
        :antialias="true"
        :width="width"
        :height="height"
        :tone-mapping="ACESFilmicToneMapping"
        :tone-mapping-exposure="1"
        :clear-alpha="0"
        @ready="onTresReady"
      >
        <OrbitControls
          ref="controlsRef"
          :control-enable="controlEnable"
          :model-loaded="modelLoaded"
          :model-size="modelSize"
          :camera-position="cameraPosition"
          :camera-target="modelOrigin"
          :camera-f-o-v="cameraFOV"
          :camera-distance="cameraDistance"
          @orbit-controls-camera-changed="onOrbitControlsCameraChanged"
          @orbit-controls-ready="onOrbitControlsReady"
        />
        <SkyBox
          v-if="envSelect === 'skyBox'"
          ref="skyBoxEnvRef"
          :sky-box-src="skyBoxSrc"
          :as-background="true"
          @sky-box-ready="onSkyBoxReady"
        />