Compare commits

..

10 Commits

Author SHA1 Message Date
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
github-actions[bot]
e5ce7437c4 Version Packages (#179)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-13 23:07:32 +01:00
Paolo Ricciuti
2f422ee190 fix: broaden checks for imported runes because LLMs are unhinged (#185) 2026-03-13 22:59:52 +01:00
paoloricciuti
14f087cd7a chore: simplify sync script/action 2026-03-13 22:22:19 +01:00
Chris Tsongas
1ef5ddf605 fix: update svelte-file-editor agent to use proper name (#183)
Co-authored-by: paoloricciuti <ricciutipaolo@gmail.com>
2026-03-13 10:37:43 +01:00
github-actions[bot]
0e55ee792d chore: sync skills from svelte.dev (#178)
Co-authored-by: svelte-docs-bot[bot] <196124396+svelte-docs-bot[bot]@users.noreply.github.com>
Co-authored-by: Paolo Ricciuti <ricciutipaolo@gmail.com>
2026-03-12 18:32:21 +01:00
24 changed files with 277 additions and 193 deletions

View File

@@ -1,5 +0,0 @@
---
"@sveltejs/opencode": patch
---
chore: sync skills from svelte.dev

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

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

View File

@@ -46,21 +46,12 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts
- name: Sync Claude plugin
run: pnpm sync-claude-plugin
- name: Sync Cursor plugin
run: pnpm sync-cursor-plugin
- name: Sync OpenCode plugin
run: pnpm sync-opencode-plugin && pnpm generate-opencode-jsonschema
- name: Sync plugins
run: pnpm sync-plugins
- name: Generate skills documentation
run: pnpm generate-skill-docs
- name: Bump plugin versions for changed plugins
run: pnpm bump-plugin-versions
- name: Check for changes
id: git-check
run: |

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

View File

@@ -25,10 +25,12 @@
"debug:generate-summaries": "pnpm --filter @sveltejs/mcp-server run debug:generate-summaries",
"release": "pnpm --filter @sveltejs/mcp run build && changeset publish",
"changeset:version": "changeset version && pnpm --filter @sveltejs/mcp run update:version && git add --all",
"sync-plugins": "pnpm sync-claude-plugin && pnpm sync-cursor-plugin && pnpm sync-opencode-plugin && pnpm bump-plugin-versions",
"sync-claude-plugin": "node scripts/sync-claude-plugin.ts",
"sync-cursor-plugin": "node scripts/sync-cursor-plugin.ts",
"sync-opencode-plugin": "node scripts/sync-opencode-plugin.ts",
"sync-opencode-plugin": "node scripts/sync-opencode-plugin.ts && pnpm generate-opencode-jsonschema",
"bump-plugin-versions": "node scripts/bump-plugin-versions.ts",
"postbump-plugin-versions": "pnpm format",
"resolve-references": "node scripts/resolve-references.ts",
"postresolve-references": "pnpm format"
},

View File

@@ -344,87 +344,111 @@ describe('add_autofixers_issues', () => {
});
describe('imported_runes', () => {
describe.each([{ source: 'svelte' }, { source: 'svelte/runes' }])(
'from "$source"',
({ source }) => {
describe.each(dollarless_runes)('single import ($rune)', ({ rune }) => {
it(`should add suggestions when importing '${rune}' from '${source}'`, () => {
const content = run_autofixers_on_code(`
describe.each([
{ source: 'svelte' },
{ source: 'svelte/runes' },
{ source: '@sveltejs/runes' },
{ source: '@sveltejs/vite-plugin-svelte' },
])('from "$source"', ({ source }) => {
describe.each(dollarless_runes)('single import ($rune)', ({ rune }) => {
it(`should add suggestions when importing '${rune}' from '${source}'`, () => {
const content = run_autofixers_on_code(`
<script>
import { ${rune} } from '${source}';
</script>`);
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
expect(content.suggestions).toContain(
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
);
});
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
expect(content.suggestions).toContain(
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
);
});
it(`should add suggestions when importing "${rune}" as the default export from '${source}'`, () => {
const content = run_autofixers_on_code(`
it(`should add suggestions when importing "${rune}" as the default export from '${source}'`, () => {
const content = run_autofixers_on_code(`
<script>
import ${rune} from '${source}';
</script>`);
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
expect(content.suggestions).toContain(
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
);
});
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
expect(content.suggestions).toContain(
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
);
});
it(`should add suggestions when importing '${rune}' as the namespace export from '${source}'`, () => {
const content = run_autofixers_on_code(`
it(`should add suggestions when importing '${rune}' as the namespace export from '${source}'`, () => {
const content = run_autofixers_on_code(`
<script>
import * as ${rune} from '${source}';
</script>`);
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
expect(content.suggestions).toContain(
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
);
});
expect(content.suggestions.length).toBeGreaterThanOrEqual(1);
expect(content.suggestions).toContain(
`You are importing "${rune}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
);
});
});
it(`should add suggestions when importing multiple runes from '${source}'`, () => {
const content = run_autofixers_on_code(`
it(`should add suggestions when importing multiple runes from '${source}'`, () => {
const content = run_autofixers_on_code(`
<script>
import { onMount, state, effect } from '${source}';
</script>`);
expect(content.suggestions.length).toBeGreaterThanOrEqual(2);
expect(content.suggestions).toContain(
`You are importing "state" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$state" directly.`,
);
expect(content.suggestions).toContain(
`You are importing "effect" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$effect" directly.`,
);
});
expect(content.suggestions.length).toBeGreaterThanOrEqual(2);
expect(content.suggestions).toContain(
`You are importing "state" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$state" directly.`,
);
expect(content.suggestions).toContain(
`You are importing "effect" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$effect" directly.`,
);
});
it(`should not add suggestions when importing other identifiers from '${source}'`, () => {
const content = run_autofixers_on_code(`
it(`should not add suggestions when importing other identifiers from '${source}'`, () => {
const content = run_autofixers_on_code(`
<script>
import { onMount } from '${source}';
</script>`);
expect(content.suggestions).not.toContain(
`You are importing "onMount" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$onMount" directly.`,
);
});
},
);
expect(content.suggestions).not.toContain(
`You are importing "onMount" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$onMount" directly.`,
);
});
});
describe.each(dollarless_runes)('importing $rune from external lib', ({ rune }) => {
it(`should not add suggestions when importing from packages that are not svelte`, () => {
it(`should not add suggestions when importing from packages whose name doesn't contain svelte`, () => {
const content = run_autofixers_on_code(`
<script>
import { ${rune} } from 'something-something';
</script>`);
expect(content.suggestions).not.toContain(
`You are importing "${rune}" from "something-something". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
);
});
it(`should add suggestions with a different hint when importing from packages whose name contains svelte but it's not official`, () => {
const content = run_autofixers_on_code(`
<script>
import { ${rune} } from 'svelte-something-something';
</script>`);
expect(content.suggestions).not.toContain(
`You are importing "${rune}" from "svelte-something-something". This is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly.`,
expect(content.suggestions).toContain(
`You are importing "${rune}" from "svelte-something-something". If you are trying to import runes to use them this is not necessary, all runes are globally available. Please remove this import and use "$${rune}" directly. If you are importing the function from a separate library ignore this suggestion.`,
);
});
});
it('should not add the imported_runes suggestion when importing derived from svelte/store', () => {
const content = run_autofixers_on_code(`
<script>
import { derived } from 'svelte/store';
</script>`);
expect(content.suggestions).not.toContain(
'You are importing "derived" from "svelte/store". This is not necessary, all runes are globally available. Please remove this import and use "$derived" directly.',
);
});
});
describe('derived_with_function', () => {

View File

@@ -3,10 +3,20 @@ import type { Autofixer } from './index.js';
const dollarless_runes = base_runes.map((r) => r.replace('$', ''));
function should_suggest_for_source(source: string, rune: string) {
if (!source.includes('svelte')) {
return false;
}
if (source === 'svelte/store' && rune === 'derived') {
return false;
}
return true;
}
export const imported_runes: Autofixer = {
ImportDeclaration(node, { state, next }) {
const source = (node.source.value || node.source.raw?.slice(1, -1))?.toString();
if (source && (source === 'svelte' || source.startsWith('svelte/'))) {
if (source) {
for (const specifier of node.specifiers) {
const id =
specifier.type === 'ImportDefaultSpecifier'
@@ -16,10 +26,25 @@ export const imported_runes: Autofixer = {
: specifier.type === 'ImportSpecifier'
? specifier.imported
: null;
if (id && id.type === 'Identifier' && dollarless_runes.includes(id.name)) {
state.output.suggestions.push(
`You are importing "${id.name}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${id.name}" directly.`,
);
if (
id &&
id.type === 'Identifier' &&
dollarless_runes.includes(id.name) &&
should_suggest_for_source(source, id.name)
) {
if (
source === 'svelte' ||
source.startsWith('svelte/') ||
source.startsWith('@sveltejs')
) {
state.output.suggestions.push(
`You are importing "${id.name}" from "${source}". This is not necessary, all runes are globally available. Please remove this import and use "$${id.name}" directly.`,
);
} else {
state.output.suggestions.push(
`You are importing "${id.name}" from "${source}". If you are trying to import runes to use them this is not necessary, all runes are globally available. Please remove this import and use "$${id.name}" directly. If you are importing the function from a separate library ignore this suggestion.`,
);
}
}
}
}

View File

@@ -1,5 +1,11 @@
# @sveltejs/mcp
## 0.1.22
### Patch Changes
- fix: broaden checks for imported runes because LLMs are unhinged ([#185](https://github.com/sveltejs/ai-tools/pull/185))
## 0.1.21
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@sveltejs/mcp",
"version": "0.1.21",
"version": "0.1.22",
"type": "module",
"license": "MIT",
"mcpName": "dev.svelte/mcp",

View File

@@ -9,7 +9,7 @@
"subfolder": "packages/mcp-stdio",
"source": "github"
},
"version": "0.1.21",
"version": "0.1.22",
"websiteUrl": "https://svelte.dev/docs/mcp/overview",
"icons": [
{
@@ -25,7 +25,7 @@
{
"registryType": "npm",
"identifier": "@sveltejs/mcp",
"version": "0.1.21",
"version": "0.1.22",
"runtimeHint": "npx",
"transport": {
"type": "stdio"

View File

@@ -1,5 +1,19 @@
# @sveltejs/opencode
## 0.1.7
### Patch Changes
- fix: import `ts` files directly ([#190](https://github.com/sveltejs/ai-tools/pull/190))
## 0.1.6
### Patch Changes
- chore: sync skills from svelte.dev ([#178](https://github.com/sveltejs/ai-tools/pull/178))
- fix: update svelte-file-editor agent to use proper name ([#183](https://github.com/sveltejs/ai-tools/pull/183))
## 0.1.5
### 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-editor\` 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.5",
"version": "0.1.7",
"type": "module",
"license": "MIT",
"homepage": "https://github.com/sveltejs/ai-tools#readme",
@@ -14,6 +14,7 @@
"files": [
"index.ts",
"config.ts",
"agents.ts",
"instructions",
"skills"
],

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,7 +1,7 @@
{
"name": "svelte",
"description": "A plugin for all things related to Svelte development, MCP, skills, and more.",
"version": "1.0.3",
"version": "1.0.4",
"author": {
"name": "Svelte"
},

View File

@@ -6,7 +6,7 @@ permissionMode: acceptEdits
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.
If the MCP tools are not available you can use the `svelte-code-editor` skill to learn how to use the `@sveltejs/mcp` cli to access the same tools.
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.
If the skill is not available you can run `npx @sveltejs/mcp@latest -y --help` to learn how to use it.

View File

@@ -1,7 +1,7 @@
{
"name": "svelte",
"description": "A plugin for all things related to Svelte development, MCP, skills, and more.",
"version": "1.0.3",
"version": "1.0.4",
"author": {
"name": "Svelte"
},

View File

@@ -5,7 +5,7 @@ description: Specialized Svelte 5 code editor. MUST BE USED PROACTIVELY when cre
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.
If the MCP tools are not available you can use the `svelte-code-editor` skill to learn how to use the `@sveltejs/mcp` cli to access the same tools.
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.
If the skill is not available you can run `npx @sveltejs/mcp@latest -y --help` to learn how to use it.

27
pnpm-lock.yaml generated
View File

@@ -123,8 +123,8 @@ catalogs:
specifier: ^1.5.0
version: 1.5.0
'@vercel/analytics':
specifier: ^1.5.0
version: 1.6.1
specifier: ^2.0.0
version: 2.0.1
dotenv:
specifier: ^17.2.3
version: 17.2.3
@@ -192,7 +192,7 @@ importers:
version: 10.1.8(eslint@9.39.2)
eslint-plugin-import:
specifier: catalog:lint
version: 2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)
version: 2.32.0(eslint@9.39.2)
eslint-plugin-pnpm:
specifier: catalog:lint
version: 1.5.0(eslint@9.39.2)
@@ -237,7 +237,7 @@ importers:
version: 0.8.4(tmcp@1.19.2(typescript@5.9.3))
'@vercel/analytics':
specifier: catalog:tooling
version: 1.6.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.4)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(svelte@5.48.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(react@18.3.1)(svelte@5.48.4)
version: 2.0.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.4)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(svelte@5.48.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(react@18.3.1)(svelte@5.48.4)
tmcp:
specifier: catalog:tmcp
version: 1.19.2(typescript@5.9.3)
@@ -2171,12 +2171,13 @@ packages:
peerDependencies:
valibot: ^1.2.0
'@vercel/analytics@1.6.1':
resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==}
'@vercel/analytics@2.0.1':
resolution: {integrity: sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==}
peerDependencies:
'@remix-run/react': ^2
'@sveltejs/kit': ^1 || ^2
next: '>= 13'
nuxt: '>= 3'
react: ^18 || ^19 || ^19.0.0-rc
svelte: '>= 4'
vue: ^3
@@ -2188,6 +2189,8 @@ packages:
optional: true
next:
optional: true
nuxt:
optional: true
react:
optional: true
svelte:
@@ -4179,6 +4182,7 @@ packages:
tar@7.5.7:
resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==}
engines: {node: '>=18'}
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
term-size@2.2.1:
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
@@ -6169,7 +6173,7 @@ snapshots:
dependencies:
valibot: 1.2.0(typescript@5.9.3)
'@vercel/analytics@1.6.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.4)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(svelte@5.48.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(react@18.3.1)(svelte@5.48.4)':
'@vercel/analytics@2.0.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.4)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(svelte@5.48.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(react@18.3.1)(svelte@5.48.4)':
optionalDependencies:
'@sveltejs/kit': 2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.48.4)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2)))(svelte@5.48.4)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.9)(yaml@2.8.2))
react: 18.3.1
@@ -6842,17 +6846,16 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2):
eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.39.2):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.54.0(eslint@9.39.2)(typescript@5.9.3)
eslint: 9.39.2
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2):
eslint-plugin-import@2.32.0(eslint@9.39.2):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -6863,7 +6866,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.39.2
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.54.0(eslint@9.39.2)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.2)
eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.39.2)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -6874,8 +6877,6 @@ snapshots:
semver: 6.3.1
string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 8.54.0(eslint@9.39.2)(typescript@5.9.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack

View File

@@ -46,7 +46,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

@@ -5,7 +5,7 @@ description: Specialized Svelte 5 code editor. MUST BE USED PROACTIVELY when cre
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.
If the MCP tools are not available you can use the `svelte-code-editor` skill to learn how to use the `@sveltejs/mcp` cli to access the same tools.
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.
If the skill is not available you can run `npx @sveltejs/mcp@latest -y --help` to learn how to use it.