remove the desktop-pet system
Build / build (push) Canceled after 0s
Playwright / e2e (push) Canceled after 0s

The pet feature was three loosely coupled subsystems that no core flow
depended on: the Petdex catalog page, the pet install/preference store, and
the pet-state socket. All three are removed.

The only cross-boundary touch point was a try/catch-wrapped observer that
mapped chat-run events to pet animations. Removing it leaves the /chat-run
event contract unchanged: no event name, field name, field type, or emission
timing changed.

Removing petdexPublicRoutes also closes the unauthenticated outbound proxy
at /api/hermes/petdex/asset, which shrinks the SSRF surface.
This commit is contained in:
2026-10-20 13:24:17 +08:00
committed by trae-solo-agent
parent 5e1003ceb7
commit b709ec6742
30 changed files with 64 additions and 1793 deletions
@@ -1,74 +0,0 @@
import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
import {
connectPetStateSocket,
disconnectPetStateSocket,
onPetStateSnapshot,
requestPetStateSnapshot,
type PetActivity,
type PetState,
type PetStateSnapshot,
} from '@/api/hermes/pet-state'
function emptySnapshot(profile = 'default'): PetStateSnapshot {
return {
profile,
state: 'idle',
activity: {},
updatedAt: Date.now(),
activeTools: [],
awaiting: [],
}
}
export const usePetStateStore = defineStore('petState', () => {
const snapshot = ref<PetStateSnapshot>(emptySnapshot())
const connected = ref(false)
const error = ref('')
let unsubscribe: (() => void) | null = null
const state = computed<PetState>(() => snapshot.value.state)
const activity = computed<PetActivity>(() => snapshot.value.activity)
async function connect(profile?: string | null): Promise<void> {
disconnect()
error.value = ''
const socket = connectPetStateSocket(profile)
socket.on('connect', () => {
connected.value = true
error.value = ''
})
socket.on('disconnect', () => {
connected.value = false
})
socket.on('connect_error', (err: Error) => {
connected.value = false
error.value = err.message
})
unsubscribe = onPetStateSnapshot(next => {
snapshot.value = next
}, profile)
try {
snapshot.value = await requestPetStateSnapshot(profile)
} catch (err) {
error.value = err instanceof Error ? err.message : String(err)
}
}
function disconnect(): void {
unsubscribe?.()
unsubscribe = null
disconnectPetStateSocket()
connected.value = false
}
return {
activity,
connect,
connected,
disconnect,
error,
snapshot,
state,
}
})
-82
View File
@@ -1,82 +0,0 @@
import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
import * as petsApi from '@/api/hermes/pets'
import type { ActivePet, WebPetPosition } from '@/api/hermes/pets'
export const usePetsStore = defineStore('pets', () => {
const activePet = ref<ActivePet | null>(null)
const loading = ref(false)
const saving = ref(false)
const error = ref('')
const hasActivePet = computed(() => !!activePet.value?.enabled)
async function loadActivePet(): Promise<ActivePet | null> {
loading.value = true
error.value = ''
try {
activePet.value = await petsApi.fetchActivePet()
return activePet.value
} catch (err: any) {
error.value = err?.message || 'Failed to load active pet'
activePet.value = null
return null
} finally {
loading.value = false
}
}
async function adopt(slug: string): Promise<ActivePet> {
saving.value = true
error.value = ''
try {
activePet.value = await petsApi.adoptPet(slug)
return activePet.value
} catch (err: any) {
error.value = err?.message || 'Failed to adopt pet'
throw err
} finally {
saving.value = false
}
}
async function savePreferences(input: { scale?: number; position?: WebPetPosition; enabled?: boolean }): Promise<void> {
if (!activePet.value) return
activePet.value = {
...activePet.value,
...(typeof input.scale === 'number' ? { scale: input.scale } : {}),
...(input.position ? { position: input.position } : {}),
...(typeof input.enabled === 'boolean' ? { enabled: input.enabled } : {}),
}
saving.value = true
try {
const saved = await petsApi.updateActivePetPreferences(input)
if (saved) activePet.value = saved
else if (input.enabled === false) activePet.value = null
} finally {
saving.value = false
}
}
async function hideActivePet(): Promise<void> {
await savePreferences({ enabled: false })
}
function clear(): void {
activePet.value = null
error.value = ''
}
return {
activePet,
loading,
saving,
error,
hasActivePet,
loadActivePet,
adopt,
savePreferences,
hideActivePet,
clear,
}
})