mirror of
https://github.com/sveltejs/ai-tools.git
synced 2026-07-04 03:19:38 +08:00
Compare commits
2 Commits
@sveltejs/
...
analytics
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48b756a21d | ||
|
|
0054d13b7e |
@@ -65,6 +65,7 @@
|
|||||||
"@sveltejs/mcp-schema": "workspace:^",
|
"@sveltejs/mcp-schema": "workspace:^",
|
||||||
"@sveltejs/mcp-server": "workspace:^",
|
"@sveltejs/mcp-server": "workspace:^",
|
||||||
"@tmcp/transport-http": "^0.7.1",
|
"@tmcp/transport-http": "^0.7.1",
|
||||||
|
"@vercel/analytics": "^1.5.0",
|
||||||
"tmcp": "^1.15.3"
|
"tmcp": "^1.15.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { dev } from '$app/environment';
|
||||||
import { http_transport } from '$lib/mcp/index.js';
|
import { http_transport } from '$lib/mcp/index.js';
|
||||||
import { db } from '$lib/server/db/index.js';
|
import { db } from '$lib/server/db/index.js';
|
||||||
import { redirect } from '@sveltejs/kit';
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
import { track } from '@vercel/analytics/server';
|
||||||
|
|
||||||
export async function handle({ event, resolve }) {
|
export async function handle({ event, resolve }) {
|
||||||
if (event.request.method === 'POST') {
|
if (event.request.method === 'POST') {
|
||||||
@@ -19,6 +21,12 @@ export async function handle({ event, resolve }) {
|
|||||||
}
|
}
|
||||||
const mcp_response = await http_transport.respond(event.request, {
|
const mcp_response = await http_transport.respond(event.request, {
|
||||||
db,
|
db,
|
||||||
|
// only add analytics in production
|
||||||
|
track: dev
|
||||||
|
? undefined
|
||||||
|
: async (session_id, event, slug) => {
|
||||||
|
await track(event, { session_id, ...(slug ? { slug } : {}) });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
// we are deploying on vercel the SSE connection will timeout after 5 minutes...for
|
// we are deploying on vercel the SSE connection will timeout after 5 minutes...for
|
||||||
// the moment we are not sending back any notifications (logs, or list changed notifications)
|
// the moment we are not sending back any notifications (logs, or list changed notifications)
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { createClient } from '@libsql/client';
|
import { createClient } from '@libsql/client';
|
||||||
import { drizzle } from 'drizzle-orm/libsql';
|
import { drizzle } from 'drizzle-orm/libsql';
|
||||||
import * as schema from './schema.js';
|
import * as schema from './schema.js';
|
||||||
// let's disable it for the moment...i can't figure out a way to make it wotk with eslint
|
|
||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import { DATABASE_TOKEN, DATABASE_URL } from '$env/static/private';
|
import { DATABASE_TOKEN, DATABASE_URL } from '$env/static/private';
|
||||||
if (!DATABASE_URL) throw new Error('DATABASE_URL is not set');
|
if (!DATABASE_URL) throw new Error('DATABASE_URL is not set');
|
||||||
if (!DATABASE_TOKEN) throw new Error('DATABASE_TOKEN is not set');
|
if (!DATABASE_TOKEN) throw new Error('DATABASE_TOKEN is not set');
|
||||||
|
|||||||
@@ -48,13 +48,17 @@ export default /** @type {import("eslint").Linter.Config} */ ([
|
|||||||
'import/no-unresolved': 'off', // this doesn't work well with typescript path mapping
|
'import/no-unresolved': 'off', // this doesn't work well with typescript path mapping
|
||||||
'import/extensions': [
|
'import/extensions': [
|
||||||
'error',
|
'error',
|
||||||
'ignorePackages',
|
|
||||||
{
|
{
|
||||||
js: 'always',
|
ignorePackages: true,
|
||||||
mjs: 'always',
|
pattern: {
|
||||||
cjs: 'always',
|
js: 'always',
|
||||||
ts: 'always',
|
mjs: 'always',
|
||||||
svelte: 'always',
|
cjs: 'always',
|
||||||
|
ts: 'always',
|
||||||
|
svelte: 'always',
|
||||||
|
svg: 'always',
|
||||||
|
json: 'always',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -68,6 +68,9 @@ export function setup_svelte_task(server: SvelteMcp) {
|
|||||||
icons,
|
icons,
|
||||||
},
|
},
|
||||||
async ({ task }) => {
|
async ({ task }) => {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(server.ctx.sessionId, 'svelte-task');
|
||||||
|
}
|
||||||
const available_docs = await format_sections_list();
|
const available_docs = await format_sections_list();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ export async function list_sections(server: SvelteMcp) {
|
|||||||
icons,
|
icons,
|
||||||
},
|
},
|
||||||
async (uri, { slug }) => {
|
async (uri, { slug }) => {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(
|
||||||
|
server.ctx.sessionId,
|
||||||
|
'svelte-doc-section',
|
||||||
|
Array.isArray(slug) ? slug.join(',') : slug,
|
||||||
|
);
|
||||||
|
}
|
||||||
const section = sections.find((section) => {
|
const section = sections.find((section) => {
|
||||||
return slug === section.slug;
|
return slug === section.slug;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ export function get_documentation(server: SvelteMcp) {
|
|||||||
icons,
|
icons,
|
||||||
},
|
},
|
||||||
async ({ section }) => {
|
async ({ section }) => {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(server.ctx.sessionId, 'get-documentation');
|
||||||
|
}
|
||||||
let sections: string[];
|
let sections: string[];
|
||||||
|
|
||||||
if (Array.isArray(section)) {
|
if (Array.isArray(section)) {
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ export function list_sections(server: SvelteMcp) {
|
|||||||
icons,
|
icons,
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(server.ctx.sessionId, 'list-sections');
|
||||||
|
}
|
||||||
const formatted_sections = await format_sections_list();
|
const formatted_sections = await format_sections_list();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ export function playground_link(server: SvelteMcp) {
|
|||||||
icons,
|
icons,
|
||||||
},
|
},
|
||||||
async ({ files, name, tailwind }) => {
|
async ({ files, name, tailwind }) => {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(server.ctx.sessionId, 'playground-link');
|
||||||
|
}
|
||||||
const playground_base = new URL('https://svelte.dev/playground');
|
const playground_base = new URL('https://svelte.dev/playground');
|
||||||
const playground_files: File[] = [];
|
const playground_files: File[] = [];
|
||||||
|
|
||||||
@@ -76,6 +79,9 @@ export function playground_link(server: SvelteMcp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!has_app_svelte) {
|
if (!has_app_svelte) {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(server.ctx.sessionId, 'playground-link-no-app-svelte');
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
isError: true,
|
isError: true,
|
||||||
content: [
|
content: [
|
||||||
|
|||||||
@@ -46,12 +46,18 @@ export function svelte_autofixer(server: SvelteMcp) {
|
|||||||
filename: filename_or_path,
|
filename: filename_or_path,
|
||||||
desired_svelte_version: desired_svelte_version_unchecked,
|
desired_svelte_version: desired_svelte_version_unchecked,
|
||||||
}) => {
|
}) => {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(server.ctx.sessionId, 'svelte-autofixer');
|
||||||
|
}
|
||||||
// we validate manually because some clients don't support union in the input schema (looking at you cursor)
|
// we validate manually because some clients don't support union in the input schema (looking at you cursor)
|
||||||
const parsed_version = v.safeParse(
|
const parsed_version = v.safeParse(
|
||||||
v.union([v.literal(4), v.literal(5), v.literal('4'), v.literal('5')]),
|
v.union([v.literal(4), v.literal(5), v.literal('4'), v.literal('5')]),
|
||||||
desired_svelte_version_unchecked,
|
desired_svelte_version_unchecked,
|
||||||
);
|
);
|
||||||
if (parsed_version.success === false) {
|
if (parsed_version.success === false) {
|
||||||
|
if (server.ctx.sessionId && server.ctx.custom?.track) {
|
||||||
|
await server.ctx.custom?.track?.(server.ctx.sessionId, 'svelte-autofixer-wrong-version');
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
isError: true,
|
isError: true,
|
||||||
content: [
|
content: [
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ export const server = new McpServer(
|
|||||||
instructions:
|
instructions:
|
||||||
'This is the official Svelte MCP server. It MUST be used whenever svelte development is involved. It can provide official documentation, code examples and correct your code. After you correct the component call this tool again to confirm all the issues are fixed.',
|
'This is the official Svelte MCP server. It MUST be used whenever svelte development is involved. It can provide official documentation, code examples and correct your code. After you correct the component call this tool again to confirm all the issues are fixed.',
|
||||||
},
|
},
|
||||||
).withContext<{ db: LibSQLDatabase<Schema> }>();
|
).withContext<{
|
||||||
|
db: LibSQLDatabase<Schema>;
|
||||||
|
track?: (sessionId: string, event: string, slug?: string) => Promise<void>;
|
||||||
|
}>();
|
||||||
|
|
||||||
export type SvelteMcp = typeof server;
|
export type SvelteMcp = typeof server;
|
||||||
|
|
||||||
|
|||||||
35
pnpm-lock.yaml
generated
35
pnpm-lock.yaml
generated
@@ -71,6 +71,9 @@ importers:
|
|||||||
'@tmcp/transport-http':
|
'@tmcp/transport-http':
|
||||||
specifier: ^0.7.1
|
specifier: ^0.7.1
|
||||||
version: 0.7.1(tmcp@1.15.3(typescript@5.9.2))
|
version: 0.7.1(tmcp@1.15.3(typescript@5.9.2))
|
||||||
|
'@vercel/analytics':
|
||||||
|
specifier: ^1.5.0
|
||||||
|
version: 1.5.0(@sveltejs/kit@2.43.5(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@24.5.2)(jiti@2.6.0)(tsx@4.20.6)))(svelte@5.39.6)(vite@7.1.7(@types/node@24.5.2)(jiti@2.6.0)(tsx@4.20.6)))(react@18.3.1)(svelte@5.39.6)
|
||||||
tmcp:
|
tmcp:
|
||||||
specifier: ^1.15.3
|
specifier: ^1.15.3
|
||||||
version: 1.15.3(typescript@5.9.2)
|
version: 1.15.3(typescript@5.9.2)
|
||||||
@@ -1685,6 +1688,32 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
valibot: ^1.1.0
|
valibot: ^1.1.0
|
||||||
|
|
||||||
|
'@vercel/analytics@1.5.0':
|
||||||
|
resolution: {integrity: sha512-MYsBzfPki4gthY5HnYN7jgInhAZ7Ac1cYDoRWFomwGHWEX7odTEzbtg9kf/QSo7XEsEAqlQugA6gJ2WS2DEa3g==}
|
||||||
|
peerDependencies:
|
||||||
|
'@remix-run/react': ^2
|
||||||
|
'@sveltejs/kit': ^1 || ^2
|
||||||
|
next: '>= 13'
|
||||||
|
react: ^18 || ^19 || ^19.0.0-rc
|
||||||
|
svelte: '>= 4'
|
||||||
|
vue: ^3
|
||||||
|
vue-router: ^4
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@remix-run/react':
|
||||||
|
optional: true
|
||||||
|
'@sveltejs/kit':
|
||||||
|
optional: true
|
||||||
|
next:
|
||||||
|
optional: true
|
||||||
|
react:
|
||||||
|
optional: true
|
||||||
|
svelte:
|
||||||
|
optional: true
|
||||||
|
vue:
|
||||||
|
optional: true
|
||||||
|
vue-router:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@vercel/nft@0.30.1':
|
'@vercel/nft@0.30.1':
|
||||||
resolution: {integrity: sha512-2mgJZv4AYBFkD/nJ4QmiX5Ymxi+AisPLPcS/KPXVqniyQNqKXX+wjieAbDXQP3HcogfEbpHoRMs49Cd4pfkk8g==}
|
resolution: {integrity: sha512-2mgJZv4AYBFkD/nJ4QmiX5Ymxi+AisPLPcS/KPXVqniyQNqKXX+wjieAbDXQP3HcogfEbpHoRMs49Cd4pfkk8g==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -5429,6 +5458,12 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
valibot: 1.1.0(typescript@5.9.2)
|
valibot: 1.1.0(typescript@5.9.2)
|
||||||
|
|
||||||
|
'@vercel/analytics@1.5.0(@sveltejs/kit@2.43.5(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@24.5.2)(jiti@2.6.0)(tsx@4.20.6)))(svelte@5.39.6)(vite@7.1.7(@types/node@24.5.2)(jiti@2.6.0)(tsx@4.20.6)))(react@18.3.1)(svelte@5.39.6)':
|
||||||
|
optionalDependencies:
|
||||||
|
'@sveltejs/kit': 2.43.5(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.39.6)(vite@7.1.7(@types/node@24.5.2)(jiti@2.6.0)(tsx@4.20.6)))(svelte@5.39.6)(vite@7.1.7(@types/node@24.5.2)(jiti@2.6.0)(tsx@4.20.6))
|
||||||
|
react: 18.3.1
|
||||||
|
svelte: 5.39.6
|
||||||
|
|
||||||
'@vercel/nft@0.30.1(rollup@4.52.2)':
|
'@vercel/nft@0.30.1(rollup@4.52.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@mapbox/node-pre-gyp': 2.0.0
|
'@mapbox/node-pre-gyp': 2.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user