Compare commits

...

2 Commits

Author SHA1 Message Date
jycouet
543fff6207 add remult entities 2025-09-30 08:20:51 +02:00
jycouet
9de930dddc @libsql/client needs to be in deps 2025-09-30 07:46:11 +02:00
12 changed files with 235 additions and 15 deletions

View File

@@ -39,7 +39,6 @@
"devDependencies": {
"@eslint/compat": "^1.3.2",
"@eslint/js": "^9.36.0",
"@libsql/client": "^0.14.0",
"@modelcontextprotocol/inspector": "^0.16.7",
"@sveltejs/adapter-vercel": "^5.6.3",
"@sveltejs/kit": "^2.22.0",
@@ -53,6 +52,7 @@
"globals": "^16.0.0",
"prettier": "^3.4.2",
"prettier-plugin-svelte": "^3.3.3",
"remult": "3.3.0-next.1",
"svelte": "^5.0.0",
"svelte-check": "^4.0.0",
"svelte-eslint-parser": "^1.3.2",
@@ -62,6 +62,7 @@
"vitest": "^3.2.3"
},
"dependencies": {
"@libsql/client": "^0.14.0",
"@sveltejs/mcp-schema": "workspace:^",
"@sveltejs/mcp-server": "workspace:^",
"@tmcp/transport-http": "^0.6.3",

View File

@@ -1,9 +1,10 @@
import { http_transport } from '$lib/mcp/index.js';
import { db } from '$lib/server/db/index.js';
import { db, entities } from '$lib/server/db/index.js';
export async function handle({ event, resolve }) {
const mcp_response = await http_transport.respond(event.request, {
db,
entities,
});
// 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)

View File

@@ -1,9 +1,15 @@
import { createClient } from '@libsql/client';
import { drizzle } from 'drizzle-orm/libsql';
import * as schema from './schema.js';
import { remult, SqlDatabase } from 'remult';
import { TursoDataProvider } from 'remult/remult-turso';
// 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 { Content } from '../../../shared/entities/Content.js';
import { ContentDistilled } from '../../../shared/entities/ContentDistilled.js';
import { Distillation } from '../../../shared/entities/Distillation.js';
import { DistillationJob } from '../../../shared/entities/DistillationJob.js';
if (!DATABASE_URL) throw new Error('DATABASE_URL is not set');
if (!DATABASE_TOKEN) throw new Error('DATABASE_TOKEN is not set');
@@ -13,3 +19,13 @@ const client = createClient({
});
export const db = drizzle(client, { schema, logger: true });
remult.dataProvider = new SqlDatabase(new TursoDataProvider(client));
SqlDatabase.LogToConsole = true;
export const entities = {
Content,
ContentDistilled,
Distillation,
DistillationJob,
};

View File

@@ -0,0 +1,19 @@
import { Fields, type FieldOptions } from 'remult';
export function FieldVector<entityType = unknown>(
...options: (FieldOptions<entityType, number[]> & { dimensions?: number })[]
) {
const dimensions = options[0].dimensions ?? 1024;
return Fields.object<entityType, number[]>(
{
valueConverter: {
fieldTypeInDb: `F32_BLOB(${dimensions})`,
toDb: (val) => JSON.stringify(val),
toDbSql: (val) => `vector32(${val})`,
fromDb: (val: Buffer) => Array.from(new Float32Array(val)),
},
},
...options,
);
}

View File

@@ -0,0 +1,35 @@
import { Entity, Fields } from 'remult';
import { FieldVector } from '../FieldVector';
@Entity<Content>('content', {
allowApiCrud: true,
dbName: 'content',
})
export class Content {
@Fields.integer()
id!: number;
@Fields.string()
path!: string;
@Fields.string()
filename!: string;
@Fields.string()
content!: string;
@Fields.integer()
size_bytes!: number;
@FieldVector({ allowNull: true })
embeddings: number[] | null = null;
@Fields.string()
metadata = '{}';
@Fields.integer()
created_at!: number;
@Fields.integer()
updated_at!: number;
}

View File

@@ -0,0 +1,35 @@
import { Entity, Fields } from 'remult';
import { FieldVector } from '../FieldVector';
@Entity<ContentDistilled>('content_distilled', {
allowApiCrud: true,
dbName: 'content_distilled',
})
export class ContentDistilled {
@Fields.integer()
id!: number;
@Fields.string()
path!: string;
@Fields.string()
filename!: string;
@Fields.string()
content!: string;
@Fields.integer()
size_bytes!: number;
@FieldVector({ allowNull: true })
embeddings: number[] | null = null;
@Fields.string()
metadata = '{}';
@Fields.integer()
created_at!: number;
@Fields.integer()
updated_at!: number;
}

View File

@@ -0,0 +1,36 @@
import { Entity, Field, Fields } from "remult"
import { Relations } from "remult"
import { DistillationJob } from "./DistillationJob.js"
@Entity<Distillation>("distillations", {
allowApiCrud: true,
dbName: "distillations",
})
export class Distillation {
@Fields.integer()
id!: number
@Fields.string()
preset_name!: string
@Fields.string()
version!: string
@Fields.string()
content!: string
@Fields.integer()
size_kb!: number
@Fields.integer()
document_count!: number
@Fields.integer({ allowNull: true })
distillation_job_id?: number
@Relations.toOne(() => DistillationJob, { field: "distillation_job_id" })
distillation_job?: DistillationJob
@Fields.integer()
created_at!: number
}

View File

@@ -0,0 +1,64 @@
import { Entity, Fields } from 'remult';
import { Relations } from 'remult';
import { Distillation } from './Distillation.js';
@Entity<DistillationJob>('distillation_jobs', {
allowApiCrud: true,
dbName: 'distillation_jobs',
})
export class DistillationJob {
@Fields.integer()
id!: number;
@Fields.string()
preset_name!: string;
@Fields.string({ allowNull: true })
batch_id?: string;
@Fields.string()
status!: string;
@Fields.string()
model_used!: string;
@Fields.integer()
total_files!: number;
@Fields.integer()
processed_files = 0;
@Fields.integer()
successful_files = 0;
@Fields.boolean()
minimize_applied = false;
@Fields.integer()
total_input_tokens = 0;
@Fields.integer()
total_output_tokens = 0;
@Fields.integer({ allowNull: true })
started_at?: number;
@Fields.integer({ allowNull: true })
completed_at?: number;
@Fields.string({ allowNull: true })
error_message?: string;
@Fields.string()
metadata = '{}';
@Fields.integer()
created_at!: number;
@Fields.integer()
updated_at!: number;
// Relations toMany
@Relations.toMany(() => Distillation)
distillations?: Distillation[];
}

View File

@@ -9,7 +9,8 @@
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler"
"moduleResolution": "bundler",
"experimentalDecorators": true
}
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files

View File

@@ -36,6 +36,7 @@
"@sveltejs/kit": "^2.42.2",
"@types/eslint-scope": "^8.3.2",
"@types/estree": "^1.0.8",
"@typescript-eslint/types": "^8.44.0"
"@typescript-eslint/types": "^8.44.0",
"remult": "3.3.0-next.1"
}
}

View File

@@ -3,6 +3,7 @@ import { McpServer } from 'tmcp';
import { setup_prompts, setup_resources, setup_tools } from './handlers/index.js';
import type { LibSQLDatabase } from 'drizzle-orm/libsql';
import type { Schema } from '@sveltejs/mcp-schema';
import type { ClassType } from 'remult';
export const server = new McpServer(
{
@@ -21,7 +22,7 @@ export const server = new McpServer(
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.',
},
).withContext<{ db: LibSQLDatabase<Schema> }>();
).withContext<{ db: LibSQLDatabase<Schema>; entities: Record<string, ClassType<unknown>> }>();
export type SvelteMcp = typeof server;

30
pnpm-lock.yaml generated
View File

@@ -25,7 +25,7 @@ importers:
version: 10.1.8(eslint@9.36.0(jiti@2.6.0))
eslint-plugin-import:
specifier: ^2.32.0
version: 2.32.0(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0))
version: 2.32.0(eslint@9.36.0(jiti@2.6.0))
eslint-plugin-svelte:
specifier: ^3.12.3
version: 3.12.4(eslint@9.36.0(jiti@2.6.0))(svelte@5.39.6)(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))
@@ -50,6 +50,9 @@ importers:
apps/mcp-remote:
dependencies:
'@libsql/client':
specifier: ^0.14.0
version: 0.14.0
'@sveltejs/mcp-schema':
specifier: workspace:^
version: link:../../packages/mcp-schema
@@ -69,9 +72,6 @@ importers:
'@eslint/js':
specifier: ^9.36.0
version: 9.36.0
'@libsql/client':
specifier: ^0.14.0
version: 0.14.0
'@modelcontextprotocol/inspector':
specifier: ^0.16.7
version: 0.16.8(@types/node@24.5.2)(typescript@5.9.2)
@@ -111,6 +111,9 @@ importers:
prettier-plugin-svelte:
specifier: ^3.3.3
version: 3.4.0(prettier@3.6.2)(svelte@5.39.6)
remult:
specifier: 3.3.0-next.1
version: 3.3.0-next.1
svelte:
specifier: ^5.0.0
version: 5.39.6
@@ -193,6 +196,9 @@ importers:
'@typescript-eslint/types':
specifier: ^8.44.0
version: 8.44.1
remult:
specifier: 3.3.0-next.1
version: 3.3.0-next.1
packages/mcp-stdio:
dependencies:
@@ -3219,6 +3225,9 @@ packages:
resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}
engines: {node: '>= 0.4'}
remult@3.3.0-next.1:
resolution: {integrity: sha512-41psdKqvkch17x/lOT4fJ9iE5Ee1MchZ1yrlWGCV8oSsXhdp9H8/eIay2LPp62c3YBx9CgcZgpwwXVmRnzoWdw==}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
@@ -5775,17 +5784,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.6.0)):
eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.6.0)):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)
eslint: 9.36.0(jiti@2.6.0)
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint@9.36.0(jiti@2.6.0)):
eslint-plugin-import@2.32.0(eslint@9.36.0(jiti@2.6.0)):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -5796,7 +5804,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.36.0(jiti@2.6.0)
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.6.0))
eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.36.0(jiti@2.6.0))
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -5807,8 +5815,6 @@ snapshots:
semver: 6.3.1
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 8.44.1(eslint@9.36.0(jiti@2.6.0))(typescript@5.9.2)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
@@ -6730,6 +6736,10 @@ snapshots:
gopd: 1.2.0
set-function-name: 2.0.2
remult@3.3.0-next.1:
dependencies:
tslib: 2.8.1
require-directory@2.1.1: {}
resolve-from@4.0.0: {}