Task 114 — Studio: migрація stores на Vue Query hooks
Phase: 8
Status: pending
Owner: —
Slug: studio-migrate-vue-query
Studio Stage: 0-2
Goal
Мигрировать Pinia stores в Hercules Studio с hand-written HerculesClient calls на generated Orval Vue Query hooks. Постепенная миграция по доменам. Добавить @tanstack/vue-query plugin в Vue app.
Acceptance criteria
@tanstack/vue-queryVue plugin установлен вmain.tsQueryClientсоздан и предоставлен черезapp.provide()QueryClientнастроен: staleTime, retry, onError handler (→ error store)- Pinia stores мигрированы на generated hooks (по доменам):
stores/skills.ts→useListSkillsQuery,useCreateSkillMutation,useImproveSkillMutation,useEvaluateSkillMutation,useDeprecateSkillMutation,useRollbackSkillMutationstores/chat.ts→useChatMutation(POST /api/chat)stores/mesh.ts→useMeshDashboardQuery,useMeshAgentsQuery,useMeshHealthQuery, etc.stores/config.ts→useGetConfigQuery,usePatchConfigMutation,usePutConfigMutationstores/tools.ts→useListToolsQuery,useEnableToolMutation,useDisableToolMutationstores/mcp.ts→useListMcpServersQuery,useReloadMcpServersMutationstores/stats.ts→useStatsQuery,useBudgetQuery
stores/connections.ts—HerculesClientзаменён на generated hooks (где возможно)- Auth: mutator в
src/api/mutator.tsиспользует active connection + X-Api-Key - Cache invalidation: после mutations (create/update/delete) — invalidate related queries
- Loading/error states из Vue Query (isLoading, isError, data)
- Zod runtime validation на response data (опционально, per query)
src/hercules-studio/renderer/src/sdk/client.ts— удалён или оставлен как thin wrapper для не-query calls (manifest, health)npm run build+npm run typecheckpass
Vue Query setup
// main.ts
import { VueQueryPlugin } from "@tanstack/vue-query";
import { QueryClient } from "@tanstack/vue-query";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 30_000, // 30s — same as health polling
retry: 1,
refetchOnWindowFocus: false,
},
mutations: {
onError: (err) => {
const errorStore = useErrorStore();
errorStore.report(err instanceof Error ? err.message : String(err), "mutation");
},
},
},
});
app.use(VueQueryPlugin, { queryClient });
Migration pattern
// Before (hand-written)
import { HerculesClient } from "../sdk/client";
// In store:
async function loadSkills() {
skills.value = await client.value.listSkills();
}
// After (generated Vue Query)
import { useListSkillsQuery, useCreateSkillMutation } from "../api/generated/skills/skills";
// In component <script setup>:
const { data: skills, isLoading, error } = useListSkillsQuery();
const { mutateAsync: createSkill } = useCreateSkillMutation();
Cache invalidation
import { useQueryClient } from "@tanstack/vue-query";
const queryClient = useQueryClient();
const { mutateAsync: createSkill } = useCreateSkillMutation({
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["skills"] });
},
});
Dependencies
- task_113 (Orval setup — нужны generated hooks)
- task_109-112 (backend OpenAPI + annotations — нужен качественный openapi.json)
Scope / Likely files
- Modified:
src/hercules-studio/renderer/src/main.ts(VueQueryPlugin) - Modified: all stores in
src/hercules-studio/renderer/src/stores/ - Modified: views that use stores (pass Vue Query data)
- Removed:
src/hercules-studio/renderer/src/sdk/client.ts(or reduced to thin wrapper)
Notes
- Миграция постепенная — можно мигрировать по одному домену за раз
- Stores остаются для state management (active connection, UI state), Vue Query — для data fetching
- Mock mode: MSW handlers (generated by Orval) позволяют dev без запущенного агента
Links
- Backlog: ../backlog.md
- task_113: task_113.md