- Add ToolsPage for managing MCP tools activation and persistence - Centralize all tool handlers in services/tools/handlers/ - toolRegistry.ts is now the single source of truth for tool state - Add tools store for pinned tools (persisted in localStorage) - Tools can be pinned to stay active across page navigation - Remove old individual tool files, replaced by centralized handlers
171 lines
4.2 KiB
TypeScript
171 lines
4.2 KiB
TypeScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
|
|
export interface ToolDefinition {
|
|
name: string
|
|
description: string
|
|
category: 'global' | 'canvas' | 'component' | 'theme' | 'database' | 'source' | 'project'
|
|
schema: object
|
|
handler: Function
|
|
}
|
|
|
|
export const useToolsStore = defineStore('tools', () => {
|
|
// All available tool definitions
|
|
const toolDefinitions = ref<Map<string, ToolDefinition>>(new Map())
|
|
|
|
// Pinned tools persist across page changes (use array for reactivity)
|
|
const pinnedToolsArray = ref<string[]>([])
|
|
|
|
// Currently active tools (use array for reactivity)
|
|
const activeToolsArray = ref<string[]>([])
|
|
|
|
// Computed
|
|
const allTools = computed(() => Array.from(toolDefinitions.value.values()))
|
|
|
|
const activeToolsDefs = computed(() =>
|
|
allTools.value.filter(t => activeToolsArray.value.includes(t.name))
|
|
)
|
|
|
|
const inactiveToolsDefs = computed(() =>
|
|
allTools.value.filter(t => !activeToolsArray.value.includes(t.name))
|
|
)
|
|
|
|
const pinnedToolsDefs = computed(() =>
|
|
allTools.value.filter(t => pinnedToolsArray.value.includes(t.name))
|
|
)
|
|
|
|
const toolsByCategory = computed(() => {
|
|
const categories: Record<string, { active: ToolDefinition[], inactive: ToolDefinition[] }> = {}
|
|
|
|
for (const tool of allTools.value) {
|
|
if (!categories[tool.category]) {
|
|
categories[tool.category] = { active: [], inactive: [] }
|
|
}
|
|
|
|
if (activeToolsArray.value.includes(tool.name)) {
|
|
categories[tool.category].active.push(tool)
|
|
} else {
|
|
categories[tool.category].inactive.push(tool)
|
|
}
|
|
}
|
|
|
|
return categories
|
|
})
|
|
|
|
// Actions
|
|
function registerToolDefinition(tool: ToolDefinition) {
|
|
toolDefinitions.value.set(tool.name, tool)
|
|
}
|
|
|
|
function registerToolDefinitions(tools: ToolDefinition[]) {
|
|
for (const tool of tools) {
|
|
toolDefinitions.value.set(tool.name, tool)
|
|
}
|
|
}
|
|
|
|
function setToolActive(name: string, active: boolean) {
|
|
const index = activeToolsArray.value.indexOf(name)
|
|
if (active && index === -1) {
|
|
activeToolsArray.value.push(name)
|
|
} else if (!active && index !== -1) {
|
|
activeToolsArray.value.splice(index, 1)
|
|
}
|
|
}
|
|
|
|
function pinTool(name: string) {
|
|
if (!pinnedToolsArray.value.includes(name)) {
|
|
pinnedToolsArray.value.push(name)
|
|
savePinnedTools()
|
|
}
|
|
}
|
|
|
|
function unpinTool(name: string) {
|
|
const index = pinnedToolsArray.value.indexOf(name)
|
|
if (index !== -1) {
|
|
pinnedToolsArray.value.splice(index, 1)
|
|
savePinnedTools()
|
|
}
|
|
}
|
|
|
|
function togglePin(name: string) {
|
|
if (pinnedToolsArray.value.includes(name)) {
|
|
unpinTool(name)
|
|
} else {
|
|
pinTool(name)
|
|
}
|
|
}
|
|
|
|
function isToolPinned(name: string): boolean {
|
|
return pinnedToolsArray.value.includes(name)
|
|
}
|
|
|
|
function isToolActive(name: string): boolean {
|
|
return activeToolsArray.value.includes(name)
|
|
}
|
|
|
|
function getPinnedToolNames(): string[] {
|
|
return [...pinnedToolsArray.value]
|
|
}
|
|
|
|
function getToolDefinition(name: string): ToolDefinition | undefined {
|
|
return toolDefinitions.value.get(name)
|
|
}
|
|
|
|
// Persistence
|
|
function savePinnedTools() {
|
|
localStorage.setItem('pinnedTools', JSON.stringify(pinnedToolsArray.value))
|
|
}
|
|
|
|
function loadPinnedTools() {
|
|
try {
|
|
const saved = localStorage.getItem('pinnedTools')
|
|
if (saved) {
|
|
const parsed = JSON.parse(saved)
|
|
pinnedToolsArray.value = parsed
|
|
}
|
|
} catch (e) {
|
|
console.error('[ToolsStore] Failed to load pinned tools:', e)
|
|
}
|
|
}
|
|
|
|
function clearActiveTools() {
|
|
activeToolsArray.value = []
|
|
}
|
|
|
|
function setActiveTools(names: string[]) {
|
|
activeToolsArray.value = [...names]
|
|
}
|
|
|
|
// Initialize
|
|
loadPinnedTools()
|
|
|
|
return {
|
|
// State (reactive arrays)
|
|
activeTools: activeToolsArray,
|
|
pinnedTools: pinnedToolsArray,
|
|
toolDefinitions,
|
|
|
|
// Computed
|
|
allTools,
|
|
activeToolsDefs,
|
|
inactiveToolsDefs,
|
|
pinnedToolsDefs,
|
|
toolsByCategory,
|
|
|
|
// Actions
|
|
registerToolDefinition,
|
|
registerToolDefinitions,
|
|
setToolActive,
|
|
pinTool,
|
|
unpinTool,
|
|
togglePin,
|
|
isToolPinned,
|
|
isToolActive,
|
|
getPinnedToolNames,
|
|
getToolDefinition,
|
|
clearActiveTools,
|
|
setActiveTools,
|
|
loadPinnedTools
|
|
}
|
|
})
|