Compare commits

..

12 Commits

Author SHA1 Message Date
Rich Harris
468acd6324 more 2026-05-13 14:25:36 -04:00
Rich Harris
2c2dd2b635 chore: add some backticks 2026-05-13 14:02:22 -04:00
Paolo Ricciuti
841af5b3a4 fix: handle non call expressions passed to is_rune (#201)
Co-authored-by: Copilot <copilot@github.com>
2026-04-28 17:12:58 +02:00
Paolo Ricciuti
1ce957ac72 chore: add LICENSE 2026-04-28 14:48:50 +02:00
Paolo Ricciuti
e429cd7839 chore: remove db requirement (#196) 2026-04-20 12:50:45 +02:00
github-actions[bot]
2ded13539a Version Packages (#192)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-10 18:39:19 +02:00
paoloricciuti
96c50acae2 fix: add server export to opencode plugin 2026-04-10 18:37:49 +02:00
github-actions[bot]
4920088e5c Version Packages (#191)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-04-10 16:57:38 +02:00
Paolo Ricciuti
8557f0af6f fix: import ts files directly (#190) 2026-04-10 16:56:23 +02:00
renovate[bot]
972d0f0bb2 chore(deps): update dependency @vercel/analytics to v2 (#177)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-27 10:15:32 +01:00
renovate[bot]
7bf364a9d5 chore(deps): update pnpm/action-setup action to v5 (#186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-03-27 10:14:49 +01:00
Paolo Ricciuti
d06d758b81 chore: sync agents with the opencode plugin too (#187) 2026-03-25 09:43:52 +01:00
34 changed files with 211 additions and 1028 deletions

View File

@@ -0,0 +1,5 @@
---
'@sveltejs/mcp': patch
---
fix: handle non call expressions passed to `is_rune`

View File

@@ -0,0 +1,5 @@
---
'@sveltejs/mcp': patch
---
chore: remove db requirement

View File

@@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v5
with:
version: 10.28.2
@@ -32,6 +32,4 @@ jobs:
- name: Run type check
run: pnpm run check
env:
DATABASE_URL: file:test.db
DATABASE_TOKEN: dummy-key
VOYAGE_API_KEY: dummy-key

View File

@@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v5
with:
version: 10.28.2
@@ -32,6 +32,4 @@ jobs:
- name: Run linting
run: pnpm run lint
env:
DATABASE_URL: file:test.db
VOYAGE_API_KEY: dummy-key
DATABASE_TOKEN: dummy-key

View File

@@ -16,7 +16,7 @@ jobs:
uses: actions/checkout@v6
- name: Setup pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v5
with:
version: 10.28.2
@@ -32,13 +32,9 @@ jobs:
- name: Build project
run: pnpm run build
env:
DATABASE_URL: file:test.db
VOYAGE_API_KEY: dummy-key
DATABASE_TOKEN: dummy-key
- name: Run tests
run: pnpm run test
env:
DATABASE_URL: file:test.db
VOYAGE_API_KEY: dummy-key
DATABASE_TOKEN: dummy-key

View File

@@ -83,7 +83,6 @@ Located in `src/lib/server/analyze/`:
Required environment variables:
- `DATABASE_URL`: SQLite database path (default: `file:test.db`)
- `VOYAGE_API_KEY`: API key for embeddings support (optional)
When connected to the svelte-llm MCP server, you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 [Svelte Contributors](https://github.com/sveltejs/ai-tools/graphs/contributors)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,3 +1 @@
DATABASE_URL=file:test.db
DATABASE_TOKEN=needs_to_be_set_but_it_can_be_anything
VOYAGE_API_KEY=your_actual_api_key_here

View File

@@ -1,12 +0,0 @@
import { defineConfig } from 'drizzle-kit';
if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is not set');
if (!process.env.DATABASE_TOKEN) throw new Error('DATABASE_TOKEN is not set');
export default defineConfig({
schema: './src/lib/server/db/schema.ts',
dialect: 'turso',
dbCredentials: { url: process.env.DATABASE_URL, authToken: process.env.DATABASE_TOKEN },
verbose: true,
strict: true,
});

View File

@@ -23,10 +23,6 @@
"test:unit": "vitest",
"test": "npm run test:unit -- --run",
"test:watch": "npm run test:unit -- --watch",
"db:push": "drizzle-kit push",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate",
"db:studio": "drizzle-kit studio",
"inspect": "pnpm mcp-inspector"
},
"keywords": [
@@ -39,15 +35,12 @@
"devDependencies": {
"@eslint/compat": "catalog:lint",
"@eslint/js": "catalog:lint",
"@libsql/client": "catalog:orm",
"@modelcontextprotocol/inspector": "catalog:ai",
"@sveltejs/adapter-vercel": "catalog:svelte",
"@sveltejs/kit": "catalog:svelte",
"@sveltejs/vite-plugin-svelte": "catalog:svelte",
"@types/node": "catalog:tooling",
"@typescript-eslint/parser": "catalog:lint",
"drizzle-kit": "catalog:orm",
"drizzle-orm": "catalog:orm",
"eslint-config-prettier": "catalog:lint",
"eslint-plugin-svelte": "catalog:lint",
"globals": "catalog:lint",
@@ -62,7 +55,6 @@
"vitest": "catalog:tooling"
},
"dependencies": {
"@sveltejs/mcp-schema": "workspace:^",
"@sveltejs/mcp-server": "workspace:^",
"@tmcp/transport-http": "catalog:tmcp",
"@vercel/analytics": "catalog:tooling",

View File

@@ -1,6 +1,5 @@
import { dev } from '$app/environment';
import { http_transport } from '$lib/mcp/index.js';
import { db } from '$lib/server/db/index.js';
import { redirect } from '@sveltejs/kit';
import { track } from '@vercel/analytics/server';
@@ -17,7 +16,6 @@ export async function handle({ event, resolve }) {
}
}
const mcp_response = await http_transport.respond(event.request, {
db,
// only add analytics in production
track: dev
? undefined

View File

@@ -1,13 +0,0 @@
import { createClient } from '@libsql/client';
import { drizzle } from 'drizzle-orm/libsql';
import * as schema from './schema.js';
import { DATABASE_TOKEN, DATABASE_URL } from '$env/static/private';
if (!DATABASE_URL) throw new Error('DATABASE_URL is not set');
if (!DATABASE_TOKEN) throw new Error('DATABASE_TOKEN is not set');
const client = createClient({
url: DATABASE_URL,
authToken: DATABASE_TOKEN,
});
export const db = drizzle(client, { schema, logger: true });

View File

@@ -1,2 +0,0 @@
// we need to re-export from here to allow for the drizzle config to pick them up for migrations
export * from '@sveltejs/mcp-schema/schema';

View File

@@ -1,6 +1,6 @@
## `svelte-code-writer`
CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (.svelte) or Svelte module (.svelte.ts/.svelte.js). If possible, this skill should be executed within the svelte-file-editor agent for optimal results.
CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (`.svelte`) or Svelte module (`.svelte.ts`/`.svelte.js`). If possible, this skill should be executed within the `svelte-file-editor` subagent for optimal results.
<a href="https://github.com/sveltejs/ai-tools/releases?q=svelte-code-writer" target="_blank" rel="noopener noreferrer">Open Releases page</a>

View File

@@ -1,19 +0,0 @@
{
"name": "@sveltejs/mcp-schema",
"version": "0.0.1",
"private": true,
"description": "",
"main": "index.js",
"exports": {
".": "./src/index.js",
"./utils": "./src/utils.js",
"./schema": "./src/schema.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"drizzle-orm": "catalog:orm"
}
}

View File

@@ -1,8 +0,0 @@
/**
* @import * as schema from './schema.js'
*/
export * from './schema.js';
/**
* @typedef {typeof schema} Schema
*/

View File

@@ -1,82 +0,0 @@
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { float_32_array } from './utils.js';
/**
* NOTE: if you modify a schema adding a vector column you need to manually add this
*
* CREATE INDEX IF NOT EXISTS name_of_the_index
* ON `name_of_the_table` (
* libsql_vector_idx(name_of_the_column, 'metric=cosine')
* )
*
* to the generated migration file
*/
export const distillations = sqliteTable('distillations', {
id: integer('id').primaryKey(),
preset_name: text('preset_name').notNull(),
version: text('version').notNull(),
content: text('content').notNull(),
size_kb: integer('size_kb').notNull(),
document_count: integer('document_count').notNull(),
distillation_job_id: integer('distillation_job_id').references(() => distillation_jobs.id),
created_at: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
});
export const distillation_jobs = sqliteTable('distillation_jobs', {
id: integer('id').primaryKey(),
preset_name: text('preset_name').notNull(),
batch_id: text('batch_id'),
status: text('status', { enum: ['pending', 'processing', 'completed', 'failed'] }).notNull(),
model_used: text('model_used').notNull(),
total_files: integer('total_files').notNull(),
processed_files: integer('processed_files').notNull().default(0),
successful_files: integer('successful_files').notNull().default(0),
minimize_applied: integer('minimize_applied', { mode: 'boolean' }).notNull().default(false),
total_input_tokens: integer('total_input_tokens').notNull().default(0),
total_output_tokens: integer('total_output_tokens').notNull().default(0),
started_at: integer('started_at', { mode: 'timestamp' }),
completed_at: integer('completed_at', { mode: 'timestamp' }),
error_message: text('error_message'),
metadata: text('metadata', { mode: 'json' }).notNull().default({}),
created_at: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
updated_at: integer('updated_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
});
export const content = sqliteTable('content', {
id: integer('id').primaryKey(),
path: text('path').notNull(),
filename: text('filename').notNull(),
content: text('content').notNull(),
size_bytes: integer('size_bytes').notNull(),
embeddings: float_32_array('embeddings', { dimensions: 1024 }),
metadata: text('metadata', { mode: 'json' }).notNull().default({}),
created_at: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
updated_at: integer('updated_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
});
export const content_distilled = sqliteTable('content_distilled', {
id: integer('id').primaryKey(),
path: text('path').notNull(),
filename: text('filename').notNull(),
content: text('content').notNull(),
size_bytes: integer('size_bytes').notNull(),
embeddings: float_32_array('embeddings', { dimensions: 1024 }),
metadata: text('metadata', { mode: 'json' }).notNull().default({}),
created_at: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
updated_at: integer('updated_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
});

View File

@@ -1,65 +0,0 @@
/**
* @import { Column } from 'drizzle-orm';
*/
import { sql } from 'drizzle-orm';
import { customType } from 'drizzle-orm/sqlite-core';
/**
* Helper function to convert an array of embeddings into a format that can be inserted into a LibSQL vector column.
* @param {number[]} arr The embeddings array.
*/
export function vector(arr) {
return sql`vector32(${JSON.stringify(arr)})`;
}
/**
* Helper function to calculate the distance between a vector column and an array of embeddings and return it as a columns.
* @param {Column} column The drizzle column representing the vector.
* @param {number} arr The embeddings array.
* @param {string} as The name of the returned column. Default is 'distance'.
*
* @example
* await db.select({
* id: vector_table.id,
* text: vector_table.text,
* distance: distance(vector_table.vector, await get_embeddings(sentence)),
* })
* .from(vector_table)
* .orderBy(sql`distance`)
* .execute();
*/
export function distance(column, arr, as = 'distance') {
return /** @type {typeof sql<number>} */ (
sql
)`CASE ${column} ISNULL WHEN 1 THEN 1 ELSE vector_distance_cos(${column}, vector32(${JSON.stringify(arr)})) END`.as(
as,
);
}
/**
* Custom drizzle type to use the LibSQL vector column type.
*/
export const float_32_array = /** @type {typeof customType<{
data: number[];
config: { dimensions: number };
configRequired: true;
driverData: Buffer;
}>} */ (customType)({
dataType(config) {
return `F32_BLOB(${config.dimensions})`;
},
/**
* @param {Buffer} value
*/
fromDriver(value) {
return Array.from(new Float32Array(value.buffer));
},
/**
*
* @param {number[]} value
* @returns
*/
toDriver(value) {
return vector(value);
},
});

View File

@@ -17,12 +17,8 @@
".": "./src/index.ts",
"./handlers": "./src/mcp/handlers/tools/handlers.ts"
},
"peerDependencies": {
"drizzle-orm": "^0.45.0"
},
"dependencies": {
"@mcp-ui/server": "catalog:ai",
"@sveltejs/mcp-schema": "workspace:^",
"@tmcp/adapter-valibot": "catalog:tmcp",
"@tmcp/transport-in-memory": "catalog:tmcp",
"@typescript-eslint/parser": "catalog:lint",

View File

@@ -775,5 +775,16 @@ describe('add_autofixers_issues', () => {
`You are reading the stateful variable "$x" with a "$" prefix. Stateful variables are not stores and should be read without the "$". Please read it as a normal variable "x"`,
);
});
// https://github.com/sveltejs/ai-tools/issues/200
it('should not crash when reading $-prefixed identifier for variable initialized with member expression', () => {
expect(() =>
run_autofixers_on_code(`<div>{$x}</div>
<script>
const x = foo.bar;
</script>`),
).not.toThrow();
});
});
});

View File

@@ -1,8 +1,6 @@
import { ValibotJsonSchemaAdapter } from '@tmcp/adapter-valibot';
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 { icons } from './icons/index.js';
export const server = new McpServer(
@@ -25,7 +23,6 @@ export const server = new McpServer(
'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>;
track?: (sessionId: string, event: string, extra?: string) => Promise<void>;
}>();

View File

@@ -69,6 +69,8 @@ export function parse(code: string, file_path: string) {
return this.all_references.find((r) => r.identifier === id);
},
is_rune(call: CallExpression, rune?: (typeof runes)[number][]) {
// it should always be a call expression but we check just in case because sometimes it's any and TS doesn't complain
if (call.type !== 'CallExpression') return false;
if (call.callee.type !== 'Identifier' && call.callee.type !== 'MemberExpression')
return false;
const id = call.callee.type === 'Identifier' ? call.callee : call.callee.object;

View File

@@ -1,5 +1,17 @@
# @sveltejs/opencode
## 0.1.8
### Patch Changes
- fix: add `server` export to opencode plugin ([`96c50ac`](https://github.com/sveltejs/ai-tools/commit/96c50acae2b4131a6c72d3579a73c44ab9158b18))
## 0.1.7
### Patch Changes
- fix: import `ts` files directly ([#190](https://github.com/sveltejs/ai-tools/pull/190))
## 0.1.6
### Patch Changes

View File

@@ -0,0 +1,11 @@
// This file is auto-generated by scripts/sync-opencode-plugin.ts
// Do not edit manually — edit the markdown files in tools/agents/ instead.
export const agents = {
'svelte-file-editor': {
description:
'Specialized Svelte 5 code editor. MUST BE USED PROACTIVELY when creating, editing, or reviewing any .svelte file or .svelte.ts/.svelte.js module and MUST use the tools from the MCP server or the `svelte-file-editor` skill if they are available. Fetches relevant documentation and validates code using the Svelte MCP server tools.',
prompt:
"You are a Svelte 5 expert responsible for writing, editing, and validating Svelte components and modules. You have access to the Svelte MCP server which provides documentation and code analysis tools. Always use the tools from the svelte MCP server to fetch documentation with `get_documentation` and validating the code with `svelte_autofixer`. If the autofixer returns any issue or suggestions try to solve them.\n\nIf the MCP tools are not available you can use the `svelte-code-writer` skill to learn how to use the `@sveltejs/mcp` cli to access the same tools.\n\nIf the skill is not available you can run `npx @sveltejs/mcp@latest -y --help` to learn how to use it.\n\n## Available MCP Tools\n\n### 1. list-sections\n\nLists all available Svelte 5 and SvelteKit documentation sections with titles and paths. Use this first to discover what documentation is available.\n\n### 2. get-documentation\n\nRetrieves full documentation for specified sections. Accepts a single section name or an array of section names. Use after `list-sections` to fetch relevant docs for the task at hand.\n\n**Example sections:** `$state`, `$derived`, `$effect`, `$props`, `$bindable`, `snippets`, `routing`, `load functions`\n\n### 3. svelte-autofixer\n\nAnalyzes Svelte code and returns suggestions to fix issues. Pass the component code directly to this tool. It will detect common mistakes like:\n\n- Using `$effect` instead of `$derived` for computations\n- Missing cleanup in effects\n- Svelte 4 syntax (`on:click`, `export let`, `<slot>`)\n- Missing keys in `{#each}` blocks\n- And more\n\n## Workflow\n\nWhen invoked to work on a Svelte file:\n\n### 1. Gather Context (if needed)\n\nIf you're uncertain about Svelte 5 syntax or patterns, use the MCP tools:\n\n1. Call `list-sections` to see available documentation\n2. Call `get-documentation` with relevant section names\n\n### 2. Read the Target File\n\nRead the file to understand the current implementation.\n\n### 3. Make Changes\n\nApply edits following Svelte 5 best practices:\n\n### 4. Validate Changes\n\nAfter editing, ALWAYS call `svelte-autofixer` with the updated code to check for issues.\n\n### 5. Fix Any Issues\n\nIf the autofixer reports problems, fix them and re-validate until no issues remain.\n\n## Output Format\n\nAfter completing your work, provide:\n\n1. Summary of changes made\n2. Any issues found and fixed by the autofixer\n3. Recommendations for further improvements (if any)",
},
} as const;

View File

@@ -2,7 +2,8 @@ import type { Plugin } from '@opencode-ai/plugin';
import { readdir } from 'node:fs/promises';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { get_mcp_config } from './config.js';
import { agents } from './agents.ts';
import { get_mcp_config } from './config.ts';
const current_dir = dirname(fileURLToPath(import.meta.url));
@@ -72,105 +73,44 @@ export const svelte_plugin: Plugin = async (ctx) => {
}
}
if (mcp_config.subagent?.enabled !== false) {
// we add the editor subagent that will be used when editing Svelte files to prevent wasting context on the main agent
const default_config: (typeof input.agent)[string] = {
color: '#ff3e00',
mode: 'subagent',
prompt: `You are a Svelte 5 expert responsible for writing, editing, and validating Svelte components and modules. You have access to the Svelte MCP server which provides documentation and code analysis tools. Always use the tools from the svelte MCP server to fetch documentation with \`get_documentation\` and validating the code with \`svelte_autofixer\`. If the autofixer returns any issue or suggestions try to solve them.
for (const [agent_name, agent_data] of Object.entries(agents)) {
// we add the editor subagent that will be used when editing Svelte files to prevent wasting context on the main agent
const default_config: (typeof input.agent)[string] = {
color: '#ff3e00',
mode: 'subagent',
prompt: agent_data.prompt,
description: agent_data.description,
permission: {
bash: 'ask',
edit: 'allow',
webfetch: 'ask',
},
tools: {
[`${svelte_mcp_name}_*`]: true,
},
};
If the MCP tools are not available you can use the \`svelte-code-writer\` skill to learn how to use the \`@sveltejs/mcp\` cli to access the same tools.
// Get per-agent config from svelte.json (if any)
const agent_config = mcp_config.subagent?.agents?.[agent_name];
If the skill is not available you can run \`npx @sveltejs/mcp@latest -y --help\` to learn how to use it.
## Available MCP Tools
### 1. list-sections
Lists all available Svelte 5 and SvelteKit documentation sections with titles and paths. Use this first to discover what documentation is available.
### 2. get-documentation
Retrieves full documentation for specified sections. Accepts a single section name or an array of section names. Use after \`list-sections\` to fetch relevant docs for the task at hand.
**Example sections:** \`$state\`, \`$derived\`, \`$effect\`, \`$props\`, \`$bindable\`, \`snippets\`, \`routing\`, \`load functions\`
### 3. svelte-autofixer
Analyzes Svelte code and returns suggestions to fix issues. Pass the component code directly to this tool. It will detect common mistakes like:
- Using \`$effect\` instead of \`$derived\` for computations
- Missing cleanup in effects
- Svelte 4 syntax (\`on:click\`, \`export let\`, \`<slot>\`)
- Missing keys in \`{#each}\` blocks
- And more
## Workflow
When invoked to work on a Svelte file:
### 1. Gather Context (if needed)
If you're uncertain about Svelte 5 syntax or patterns, use the MCP tools:
1. Call \`list-sections\` to see available documentation
2. Call \`get-documentation\` with relevant section names
### 2. Read the Target File
Read the file to understand the current implementation.
### 3. Make Changes
Apply edits following Svelte 5 best practices:
### 4. Validate Changes
After editing, ALWAYS call \`svelte-autofixer\` with the updated code to check for issues.
### 5. Fix Any Issues
If the autofixer reports problems, fix them and re-validate until no issues remain.
## Output Format
After completing your work, provide:
1. Summary of changes made
2. Any issues found and fixed by the autofixer
3. Recommendations for further improvements (if any)
`,
description:
'Specialized Svelte 5 code editor. MUST BE USED PROACTIVELY when creating, editing, or reviewing any .svelte file or .svelte.ts/.svelte.js module and MUST use the tools from the MCP server or the `svelte-code-writer` skill if they are available. Fetches relevant documentation and validates code using the Svelte MCP server tools.',
permission: {
bash: 'ask',
edit: 'allow',
webfetch: 'ask',
},
tools: {
[`${svelte_mcp_name}_*`]: true,
},
};
// Get per-agent config from svelte.json (if any)
const svelte_file_editor_config = mcp_config.subagent?.agents?.['svelte-file-editor'];
// Configure agent from svelte.json only
// Priority: svelte.json agent config > defaults
input.agent['svelte-file-editor'] = {
...default_config,
...(svelte_file_editor_config?.model !== undefined && {
model: svelte_file_editor_config.model,
}),
...(svelte_file_editor_config?.temperature !== undefined && {
temperature: svelte_file_editor_config.temperature,
}),
...(svelte_file_editor_config?.maxSteps !== undefined && {
maxSteps: svelte_file_editor_config.maxSteps,
}),
...(svelte_file_editor_config?.top_p !== undefined && {
top_p: svelte_file_editor_config.top_p,
}),
};
// Configure agent from svelte.json only
// Priority: svelte.json agent config > defaults
input.agent[agent_name] = {
...default_config,
...(agent_config?.model !== undefined && {
model: agent_config.model,
}),
...(agent_config?.temperature !== undefined && {
temperature: agent_config.temperature,
}),
...(agent_config?.maxSteps !== undefined && {
maxSteps: agent_config.maxSteps,
}),
...(agent_config?.top_p !== undefined && {
top_p: agent_config.top_p,
}),
};
}
}
},
};

View File

@@ -1,6 +1,6 @@
{
"name": "@sveltejs/opencode",
"version": "0.1.6",
"version": "0.1.8",
"type": "module",
"license": "MIT",
"homepage": "https://github.com/sveltejs/ai-tools#readme",
@@ -14,9 +14,16 @@
"files": [
"index.ts",
"config.ts",
"agents.ts",
"instructions",
"skills"
],
"exports": {
"./server": {
"types": "./index.ts",
"import": "./index.ts"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/sveltejs/ai-tools.git",

View File

@@ -1,6 +1,6 @@
---
name: svelte-code-writer
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (.svelte) or Svelte module (.svelte.ts/.svelte.js). If possible, this skill should be executed within the svelte-file-editor agent for optimal results.
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (`.svelte`) or Svelte module (`.svelte.ts`/`.svelte.js`). If possible, this skill should be executed within the `svelte-file-editor` subagent for optimal results.
---
# Svelte 5 Code Writer

View File

@@ -1,5 +1,9 @@
{
"extends": "../../tsconfig.json",
"include": ["index.ts", "config.ts", "scripts/*"],
"compilerOptions": {
"allowImportingTsExtensions": true,
"types": ["@types/node"]
},
"include": ["index.ts", "config.ts", "agents.ts", "scripts/*"],
"exclude": ["node_modules"]
}

View File

@@ -1,6 +1,6 @@
---
name: svelte-code-writer
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (.svelte) or Svelte module (.svelte.ts/.svelte.js). If possible, this skill should be executed within the svelte-file-editor agent for optimal results.
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (`.svelte`) or Svelte module (`.svelte.ts`/`.svelte.js`). If possible, this skill should be executed within the `svelte-file-editor` subagent for optimal results.
---
# Svelte 5 Code Writer

View File

@@ -1,6 +1,6 @@
---
name: svelte-code-writer
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (.svelte) or Svelte module (.svelte.ts/.svelte.js). If possible, this skill should be executed within the svelte-file-editor agent for optimal results.
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (`.svelte`) or Svelte module (`.svelte.ts`/`.svelte.js`). If possible, this skill should be executed within the `svelte-file-editor` subagent for optimal results.
---
# Svelte 5 Code Writer

700
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,10 +24,6 @@ catalogs:
prettier-plugin-svelte: ^3.3.3
svelte-eslint-parser: ^1.4.0
typescript-eslint: ^8.44.0
orm:
'@libsql/client': ^0.17.0
drizzle-kit: ^0.31.0
drizzle-orm: ^0.45.0
svelte:
'@sveltejs/adapter-vercel': ^6.0.0
'@sveltejs/kit': ^2.42.2
@@ -46,7 +42,7 @@ catalogs:
'@types/estree': ^1.0.8
'@types/node': ^24.3.1
'@valibot/to-json-schema': ^1.5.0
'@vercel/analytics': ^1.5.0
'@vercel/analytics': ^2.0.0
dotenv: ^17.2.3
node-resolve-ts: ^1.0.2
publint: ^0.3.13

View File

@@ -37,7 +37,77 @@ async function sync_agents_md() {
console.log('Synced AGENTS.md to opencode package and documentation');
}
interface AgentData {
name: string;
description: string;
prompt: string;
}
/**
* Parse a markdown agent file with frontmatter (name, description) and body (prompt)
*/
function parse_agent_md(content: string, file_path: string): AgentData | null {
const frontmatter_match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
if (!frontmatter_match) {
console.warn(`Skipping ${file_path}: no frontmatter found`);
return null;
}
const frontmatter = frontmatter_match[1] ?? '';
const body = (frontmatter_match[2] ?? '').trim();
const name = frontmatter.match(/^name:\s*(.+)$/m)?.[1]?.trim();
const description = frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim();
if (!name || !description) {
console.warn(`Skipping ${file_path}: missing name or description in frontmatter`);
return null;
}
return { name, description, prompt: body };
}
/**
* Generate agents.ts module from tools/agents/*.md files
*/
async function sync_agents() {
const agents_dir = path.join(TOOLS_DIR, 'agents');
const entries = await fs.readdir(agents_dir, { withFileTypes: true });
const md_files = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
const agents: AgentData[] = [];
for (const file of md_files) {
const file_path = path.join(agents_dir, file.name);
const content = await fs.readFile(file_path, 'utf-8');
const agent = parse_agent_md(content, file_path);
if (agent) {
agents.push(agent);
}
}
const output = [
'// This file is auto-generated by scripts/sync-opencode-plugin.ts',
'// Do not edit manually — edit the markdown files in tools/agents/ instead.',
'',
`export const agents = ${JSON.stringify(
Object.fromEntries(
agents.map((a) => [a.name, { description: a.description, prompt: a.prompt }]),
),
null,
'\t',
)} as const;`,
'',
].join('\n');
const dest = path.join(OPENCODE_PKG_DIR, 'agents.ts');
await fs.writeFile(dest, output);
console.log(`Generated agents.ts with ${agents.length} agent(s)`);
}
await sync_skills();
await sync_agents_md();
await sync_agents();
console.log('OpenCode plugin sync complete');

View File

@@ -1,6 +1,6 @@
---
name: svelte-code-writer
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (.svelte) or Svelte module (.svelte.ts/.svelte.js). If possible, this skill should be executed within the svelte-file-editor agent for optimal results.
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating, editing or analyzing any Svelte component (`.svelte`) or Svelte module (`.svelte.ts`/`.svelte.js`). If possible, this skill should be executed within the `svelte-file-editor` subagent for optimal results.
---
# Svelte 5 Code Writer