Compare commits

..

15 Commits

Author SHA1 Message Date
paoloricciuti
f9e79bfd0f fix: lint 2026-03-12 18:30:44 +01:00
paoloricciuti
6887aae84b Merge remote-tracking branch 'origin/main' into chore/sync-skills 2026-03-12 18:26:59 +01:00
paoloricciuti
84ec24b6f6 fix: don't format code blocks in references 2026-03-12 18:19:43 +01:00
Paolo Ricciuti
af2975607f chore: sync skills from svelte.dev
Sync skills from svelte.dev for better alignment.
2026-03-12 18:06:48 +01:00
svelte-docs-bot[bot]
d17c7d36e8 chore: sync skills from svelte.dev 2026-03-12 17:05:11 +00:00
paoloricciuti
710cebe539 docs: opencode config link 2026-03-12 17:59:32 +01:00
paoloricciuti
b2a380c4ce docs: fix markdown blocks 2026-03-12 17:57:45 +01:00
paoloricciuti
eef0a9b4d9 docs: update opencode docs 2026-03-11 21:31:43 +01:00
Paolo Ricciuti
260b36e8af chore: undo rename for publish to registry check 2026-03-11 14:11:15 +01:00
github-actions[bot]
6df3ebe568 Version Packages (#173)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-03-11 13:08:21 +01:00
Momcilo Miladinovic
27a2fc5653 fix: merge user-configured svelte-file-editor agent settings (#176)
Co-authored-by: Momochiro <x@Mac.sweet.opnsense>
Co-authored-by: Paolo Ricciuti <ricciutipaolo@gmail.com>
2026-03-11 12:59:01 +01:00
Paolo Ricciuti
5cd99d8234 feat: allow enabling a specific skill in opencode plugin (#174) 2026-03-10 17:38:04 +01:00
Paolo Ricciuti
e9f19199cb feat: add sync skill docs (#172) 2026-03-09 17:49:18 +01:00
Willow (GHOST)
480b46df0a feat(opencode): mcp enabled option is passed to opencode (#171)
Co-authored-by: Paolo Ricciuti <ricciutipaolo@gmail.com>
2026-03-07 12:38:45 +01:00
jyc.dev
5f5fb27977 feat: display similar result & error at the end (#161) 2026-03-07 12:20:18 +01:00
26 changed files with 411 additions and 86 deletions

View File

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

View File

@@ -64,7 +64,7 @@ jobs:
publish-mcp:
needs: release
if: contains(needs.release.outputs.publishedPackages, '"@sveltejs/ai-tools"')
if: contains(needs.release.outputs.publishedPackages, '"@sveltejs/mcp"')
uses: ./.github/workflows/publish-mcp.yml
secrets:
MCP_KEY: ${{ secrets.MCP_KEY }}

View File

@@ -53,7 +53,7 @@ jobs:
run: pnpm sync-cursor-plugin
- name: Sync OpenCode plugin
run: pnpm sync-opencode-plugin
run: pnpm sync-opencode-plugin && pnpm generate-opencode-jsonschema
- name: Generate skills documentation
run: pnpm generate-skill-docs
@@ -69,6 +69,7 @@ jobs:
plugins/cursor/svelte/ \
packages/opencode/skills/ \
packages/opencode/instructions/ \
packages/opencode/schema.json \
documentation/docs/ \
|| echo "changed=true" >> $GITHUB_OUTPUT
@@ -90,7 +91,7 @@ jobs:
## Changes
- Synced `plugins/claude/svelte/` (skills, agents with `permissionMode`)
- Synced `plugins/cursor/svelte/` (skills, agents, rules)
- Synced `packages/opencode/` (skills, instructions)
- Synced `packages/opencode/` (skills, instructions, schema)
- Updated documentation
## Generated by

View File

@@ -10,6 +10,12 @@
"options": {
"parser": "svelte"
}
},
{
"files": "**/references/*.md",
"options": {
"embeddedLanguageFormatting": "off"
}
}
]
}

View File

@@ -17,6 +17,10 @@ To get the most out of the MCP server we recommend including the following promp
> [!NOTE] This is already setup for you when using `npx sv add mcp`
<!-- prettier-ignore-start -->
````markdown
@include .generated/agents.md
````
<!-- prettier-ignore-end -->
If your MCP client supports it, we also recommend using the [svelte-task](prompts#svelte-task) prompt to instruct the LLM on the best way to use the MCP server.

View File

@@ -5,10 +5,22 @@ This prompt should be used whenever you are asking the model to work on a Svelte
<details>
<summary>Copy the prompt</summary>
```md
<!-- prettier-ignore-start -->
````markdown
You are a Svelte expert tasked to build components and utilities for Svelte developers. If you need documentation for anything related to Svelte you can invoke the tool `get-documentation` with one of the following paths. However: before invoking the `get-documentation` tool, try to answer the users query using your own knowledge and the `svelte-autofixer` tool. Be mindful of how many section you request, since it is token-intensive!
<available-docs>
- title: Overview, use_cases: use title and path to estimate use case, path: ai/overview
- title: Local setup, use_cases: use title and path to estimate use case, path: ai/local-setup
- title: Remote setup, use_cases: use title and path to estimate use case, path: ai/remote-setup
- title: Tools, use_cases: use title and path to estimate use case, path: ai/tools
- title: Resources, use_cases: use title and path to estimate use case, path: ai/resources
- title: Prompts, use_cases: use title and path to estimate use case, path: ai/prompts
- title: Overview, use_cases: use title and path to estimate use case, path: ai/plugin
- title: Subagent, use_cases: use title and path to estimate use case, path: ai/subagent
- title: Overview, use_cases: use title and path to estimate use case, path: ai/opencode-plugin
- title: Subagent, use_cases: use title and path to estimate use case, path: ai/opencode-subagent
- title: Overview, use_cases: use title and path to estimate use case, path: ai/skills
- title: Overview, use_cases: project setup, creating new svelte apps, scaffolding, cli tools, initializing projects, path: cli/overview
- title: Frequently asked questions, use_cases: project setup, initializing new svelte projects, troubleshooting cli installation, package manager configuration, path: cli/faq
- title: sv create, use_cases: project setup, starting new sveltekit app, initializing project, creating from playground, choosing project template, path: cli/sv-create
@@ -18,7 +30,7 @@ You are a Svelte expert tasked to build components and utilities for Svelte deve
- title: devtools-json, use_cases: development setup, chrome devtools integration, browser-based editing, local development workflow, debugging setup, path: cli/devtools-json
- title: drizzle, use_cases: database setup, sql queries, orm integration, data modeling, postgresql, mysql, sqlite, server-side data access, database migrations, type-safe queries, path: cli/drizzle
- title: eslint, use_cases: code quality, linting, error detection, project setup, code standards, team collaboration, typescript projects, path: cli/eslint
- title: lucia, use_cases: authentication, login systems, user management, registration pages, session handling, auth setup, path: cli/lucia
- title: better-auth, use_cases: use title and path to estimate use case, path: cli/better-auth
- title: mcp, use_cases: use title and path to estimate use case, path: cli/mcp
- title: mdsvex, use_cases: blog, content sites, markdown rendering, documentation sites, technical writing, cms integration, article pages, path: cli/mdsvex
- title: paraglide, use_cases: internationalization, multi-language sites, i18n, translation, localization, language switching, global apps, multilingual content, path: cli/paraglide
@@ -29,6 +41,7 @@ You are a Svelte expert tasked to build components and utilities for Svelte deve
- title: tailwindcss, use_cases: project setup, styling, css framework, rapid prototyping, utility-first css, design systems, responsive design, adding tailwind to svelte, path: cli/tailwind
- title: vitest, use_cases: testing, unit tests, component testing, test setup, quality assurance, ci/cd pipelines, test-driven development, path: cli/vitest
- title: add-on, use_cases: use title and path to estimate use case, path: cli/add-on
- title: sv-utils, use_cases: use title and path to estimate use case, path: cli/sv-utils
- title: Introduction, use_cases: learning sveltekit, project setup, understanding framework basics, choosing between svelte and sveltekit, getting started with full-stack apps, path: kit/introduction
- title: Creating a project, use_cases: project setup, starting new sveltekit app, initial development environment, first-time sveltekit users, scaffolding projects, path: kit/creating-a-project
- title: Project types, use_cases: deployment, project setup, choosing adapters, ssg, spa, ssr, serverless, mobile apps, desktop apps, pwa, offline apps, browser extensions, separate backend, docker containers, path: kit/project-types
@@ -96,17 +109,6 @@ You are a Svelte expert tasked to build components and utilities for Svelte deve
- title: Configuration, use_cases: project setup, configuration, adapters, deployment, build settings, environment variables, routing customization, prerendering, csp security, csrf protection, path configuration, typescript setup, path: kit/configuration
- title: Command Line Interface, use_cases: project setup, typescript configuration, generated types, ./$types imports, initial project configuration, path: kit/cli
- title: Types, use_cases: typescript, type safety, route parameters, api endpoints, load functions, form actions, generated types, jsconfig setup, path: kit/types
- title: Overview, use_cases: use title and path to estimate use case, path: mcp/overview
- title: Local setup, use_cases: use title and path to estimate use case, path: mcp/local-setup
- title: Remote setup, use_cases: use title and path to estimate use case, path: mcp/remote-setup
- title: Tools, use_cases: use title and path to estimate use case, path: mcp/tools
- title: Resources, use_cases: use title and path to estimate use case, path: mcp/resources
- title: Prompts, use_cases: use title and path to estimate use case, path: mcp/prompts
- title: Overview, use_cases: use title and path to estimate use case, path: mcp/plugin
- title: Skill, use_cases: use title and path to estimate use case, path: mcp/skill
- title: Subagent, use_cases: use title and path to estimate use case, path: mcp/subagent
- title: Overview, use_cases: use title and path to estimate use case, path: mcp/opencode-plugin
- title: Subagent, use_cases: use title and path to estimate use case, path: mcp/opencode-subagent
- title: Overview, use_cases: always, any svelte project, getting started, learning svelte, introduction, project setup, understanding framework basics, path: svelte/overview
- title: Getting started, use_cases: project setup, starting new svelte project, initial installation, choosing between sveltekit and vite, editor configuration, path: svelte/getting-started
- title: .svelte files, use_cases: always, any svelte project, component creation, project setup, learning svelte basics, path: svelte/svelte-files
@@ -154,6 +156,7 @@ You are a Svelte expert tasked to build components and utilities for Svelte deve
- title: Lifecycle hooks, use_cases: component initialization, cleanup tasks, timers, subscriptions, dom measurements, chat windows, autoscroll features, migration from svelte 4, path: svelte/lifecycle-hooks
- title: Imperative component API, use_cases: project setup, client-side rendering, server-side rendering, ssr, hydration, testing, programmatic component creation, tooltips, dynamic mounting, path: svelte/imperative-component-api
- title: Hydratable data, use_cases: use title and path to estimate use case, path: svelte/hydratable
- title: Best practices, use_cases: use title and path to estimate use case, path: svelte/best-practices
- title: Testing, use_cases: testing, quality assurance, unit tests, integration tests, component tests, e2e tests, vitest setup, playwright setup, test automation, path: svelte/testing
- title: TypeScript, use_cases: typescript setup, type safety, component props typing, generic components, wrapper components, dom type augmentation, project configuration, path: svelte/typescript
- title: Custom elements, use_cases: web components, custom elements, component library, design system, framework-agnostic components, embedding svelte in non-svelte apps, shadow dom, path: svelte/custom-elements
@@ -204,6 +207,7 @@ This is the task you will work on:
</task>
If you are not writing the code into a file, once you have the final version of the code ask the user if it wants to generate a playground link to quickly check the code in it and if it answer yes call the `playground-link` tool and return the url to the user nicely formatted. The playground link MUST be generated only once you have the final version of the code and you are ready to share it, it MUST include an entry point file called `App.svelte` where the main component should live. If you have multiple files to include in the playground link you can include them all at the root.
```
````
<!-- prettier-ignore-end -->
</details>

View File

@@ -6,7 +6,7 @@ OpenCode has a [plugin system](https://opencode.ai/docs/plugins/) that allows de
## Installation
To install the plugin in OpenCode you can edit your [OpenCode config]() (either the global or the local one), adding `@sveltejs/opencode` to the list of plugins.
To install the plugin in OpenCode you can edit your [OpenCode config](https://opencode.ai/docs/config/) (either the global or the local one), adding `@sveltejs/opencode` to the list of plugins.
```json
{
@@ -23,16 +23,24 @@ The default configuration for the Svelte OpenCode plugin looks like this...
```json
{
"$schema": "https://raw.githubusercontent.com/sveltejs/ai-tools/refs/heads/main/packages/opencode/schema.json",
"$schema": "https://svelte.dev/opencode/schema.json",
"mcp": {
"type": "remote",
"enabled": true
},
"subagent": {
"enabled": true
"enabled": true,
"agents": {
"svelte-file-editor": {
"model": "other-model", // defaults to the same as main agent,
"temperature": 1, // default to unset
"top_p": 0.7, // default to unset,
"maxSteps": 20 // default to unlimited
}
}
},
"skills": {
"enabled": true
"enabled": true // it can also be an array of all the skills to enable like ['svelte-core-bestpractices']
},
"instructions": {
"enabled": true
@@ -40,6 +48,6 @@ The default configuration for the Svelte OpenCode plugin looks like this...
}
```
...but if you prefer, you can enable only the subagent, only the MCP, only the skills, or configure the kind of MCP server you want to use (`local` or `remote`).
...but if you prefer, you can enable only the subagent, only the MCP, only the skills (`enabled` supports both a boolean or an array containing the name of all the skills to enable), or configure the kind of MCP server you want to use (`local` or `remote`).
You can place this file in `./.opencode/svelte.json` (in your project), in `~/.config/opencode/svelte.json` or, if you have an `OPENCODE_CONFIG_DIR` environment variable specified, at `$OPENCODE_CONFIG_DIR/svelte.json`.

View File

@@ -217,7 +217,7 @@ The CSS in a component's `<style>` is scoped to that component. If a parent comp
</style>
```
If this impossible (for example, the child component comes from a library) you can use `:global` to override styles:
If this is impossible (for example, the child component comes from a library) you can use `:global` to override styles:
```svelte
<div>

View File

@@ -91,16 +91,56 @@ export async function get_documentation_handler({
}
});
const has_any_success = results.some((result) => result.success);
let final_text = results.map((r) => r.content).join('\n\n---\n\n');
const successes = results.filter((r) => r.success);
const failed_sections = sections.filter(
(s) =>
!available_sections.some(
(a) => a.title.toLowerCase() === s.toLowerCase() || a.slug === s || a.url === s,
),
);
if (!has_any_success) {
const formatted_sections = await format_sections_list();
final_text += `\n\n---\n\n${SECTIONS_LIST_INTRO}\n\n${formatted_sections}\n\n${SECTIONS_LIST_OUTRO}`;
if (successes.length > 0 && failed_sections.length === 0) {
return successes.map((r) => r.content).join('\n\n---\n\n');
}
return final_text;
const parts: string[] = [];
if (successes.length > 0) {
parts.push(successes.map((r) => r.content).join('\n\n---\n\n'));
}
const fuzzy_results = failed_sections.map((requested) => {
const lower = requested.toLowerCase();
const matches = available_sections.filter(
(a) =>
a.title.toLowerCase().includes(lower) ||
a.slug.includes(lower) ||
lower.includes(a.slug.split('/').pop() ?? '') ||
a.use_cases.toLowerCase().includes(lower),
);
return { requested, matches };
});
const has_fuzzy = fuzzy_results.some((r) => r.matches.length > 0);
// Full list only when no successes and no fuzzy matches
if (successes.length === 0 && !has_fuzzy) {
const formatted_sections = await format_sections_list();
parts.push(`${SECTIONS_LIST_INTRO}\n\n${formatted_sections}\n\n${SECTIONS_LIST_OUTRO}`);
}
// Similar results then errors
for (const { requested, matches } of fuzzy_results) {
if (matches.length > 0) {
const match_list = matches.map((m) => `- title: ${m.title}, section: ${m.slug}`).join('\n');
parts.push(
`${matches.length} similar result${matches.length > 1 ? 's' : ''} for "${requested}":\n${match_list}`,
);
}
parts.push(`Section not found: "${requested}".`);
}
return parts.join('\n\n---\n\n');
}
export function get_documentation(server: SvelteMcp) {

View File

@@ -1,5 +1,11 @@
# @sveltejs/mcp
## 0.1.21
### Patch Changes
- feat: display similar result & error at the end ([#161](https://github.com/sveltejs/ai-tools/pull/161))
## 0.1.20
### Patch Changes

View File

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

View File

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

View File

@@ -1,5 +1,15 @@
# @sveltejs/opencode
## 0.1.5
### Patch Changes
- fix: merge user-configured svelte-file-editor agent settings ([#176](https://github.com/sveltejs/ai-tools/pull/176))
- feat(opencode): mcp enabled option is passed to opencode ([#171](https://github.com/sveltejs/ai-tools/pull/171))
- feat: allow enabling a specific skill in opencode plugin ([#174](https://github.com/sveltejs/ai-tools/pull/174))
## 0.1.4
### Patch Changes

View File

@@ -36,39 +36,76 @@ The plugin injects instructions that teach the agent how to effectively use the
## Configuration
The default configuration:
Create `svelte.json` to customize how the plugin configures MCP, the Svelte subagent, instructions, and skills.
```json
{
"$schema": "https://raw.githubusercontent.com/sveltejs/ai-tools/refs/heads/main/packages/opencode/schema.json",
"$schema": "https://svelte.dev/opencode/schema.json",
"mcp": {
"type": "remote",
"enabled": true
},
"subagent": {
"enabled": true
"enabled": true,
"agents": {
"svelte-file-editor": {
"model": "anthropic/claude-sonnet-4-20250514",
"temperature": 0.7,
"top_p": 0.9,
"maxSteps": 20
}
}
},
"instructions": {
"enabled": true
},
"skills": {
"enabled": ["svelte-code-writer", "svelte-core-bestpractices"]
}
}
```
### Defaults
If omitted, the plugin uses these defaults:
- `mcp.type`: `"remote"`
- `mcp.enabled`: `true`
- `subagent.enabled`: `true`
- `subagent.agents`: `{}`
- `instructions.enabled`: `true`
- `skills.enabled`: `true`
### Configuration Options
| Option | Type | Default | Description |
| ---------------------- | ----------------------- | ---------- | -------------------------------------------------------------------------------- |
| `mcp.type` | `"remote"` \| `"local"` | `"remote"` | Use the remote server at `mcp.svelte.dev` or run locally via `npx @sveltejs/mcp` |
| `mcp.enabled` | `boolean` | `true` | Enable/disable the MCP server |
| `subagent.enabled` | `boolean` | `true` | Enable/disable the Svelte file editor subagent |
| `instructions.enabled` | `boolean` | `true` | Enable/disable agent instructions injection |
| Option | Type | Default | Description |
| ------------------------------------------------ | --------------------- | ---------- | ---------------------------------------------------------------------------------------------- |
| `mcp.type` | `"remote" \| "local"` | `"remote"` | Use `https://mcp.svelte.dev/mcp` (`remote`) or run `@sveltejs/mcp` via `npx` (`local`). |
| `mcp.enabled` | `boolean` | `true` | Enable or disable the Svelte MCP server entry. |
| `subagent.enabled` | `boolean` | `true` | Enable or disable registration of the `svelte-file-editor` subagent. |
| `subagent.agents.svelte-file-editor.model` | `string` | main agent | Override the model used by the Svelte file editor subagent. |
| `subagent.agents.svelte-file-editor.temperature` | `number` | unset | Set temperature for the subagent. |
| `subagent.agents.svelte-file-editor.top_p` | `number` | unset | Set top-p sampling for the subagent. |
| `subagent.agents.svelte-file-editor.maxSteps` | `number` | unlimited | Limit the number of steps the subagent can execute. |
| `instructions.enabled` | `boolean` | `true` | Enable or disable automatic instruction-file injection. |
| `skills.enabled` | `boolean \| string[]` | `true` | Enable all skills (`true`), disable all skills (`false`), or enable only specific skill names. |
### Config File Location
### Supported Skill Names
Place your configuration at one of these locations:
When using `skills.enabled` as an array, these built-in names are currently available:
- `~/.config/opencode/svelte.json` (global)
- `$OPENCODE_CONFIG_DIR/svelte.json` (if `OPENCODE_CONFIG_DIR` is set, takes priority)
- `svelte-code-writer`
- `svelte-core-bestpractices`
### Config File Locations and Precedence
The plugin reads from these files (lowest priority first, highest priority last):
- `~/.config/opencode/svelte.json`
- `$OPENCODE_CONFIG_DIR/svelte.json` (when `OPENCODE_CONFIG_DIR` is set)
- `.opencode/svelte.json` in the current project
If the same key is defined in multiple files, the later location overrides earlier ones.
## License

View File

@@ -4,6 +4,28 @@ import { homedir } from 'os';
import { join } from 'path';
import * as v from 'valibot';
// Schema for individual agent configuration
const agent_config_schema = v.object({
model: v.pipe(
v.optional(v.string()),
v.description('Model identifier for the agent (e.g., "anthropic/claude-sonnet-4-20250514")'),
),
temperature: v.pipe(
v.optional(v.number()),
v.description('Temperature setting for the agent (e.g., 0.7)'),
),
top_p: v.pipe(
v.optional(v.number()),
v.description(
'Control response diversity with the top_p option. Alternative to temperature for controlling randomness.',
),
),
maxSteps: v.pipe(
v.optional(v.number()),
v.description('Maximum number of steps the agent can take (e.g., 10)'),
),
});
const default_config = {
mcp: {
type: 'remote' as 'remote' | 'local',
@@ -11,36 +33,61 @@ const default_config = {
},
subagent: {
enabled: true,
agents: {} as Record<string, v.InferInput<typeof agent_config_schema>>,
},
instructions: {
enabled: true,
},
skills: {
enabled: true,
enabled: true as boolean | string[],
},
};
export const config_schema = v.object({
mcp: v.optional(
v.object({
type: v.optional(v.picklist(['remote', 'local'])),
enabled: v.optional(v.boolean()),
}),
mcp: v.pipe(
v.optional(
v.object({
type: v.optional(v.picklist(['remote', 'local'])),
enabled: v.optional(v.boolean()),
}),
),
v.description(
"Configuration for the MCP. You can chose if it should be enabled or not and the transport to use 'remote' (default) and 'local'.",
),
),
subagent: v.optional(
v.object({
enabled: v.optional(v.boolean()),
}),
subagent: v.pipe(
v.optional(
v.object({
enabled: v.optional(v.boolean()),
agents: v.optional(v.record(v.string(), agent_config_schema)),
}),
),
v.description('Configuration for the subagent. You can choose if it should be enabled or not.'),
),
instructions: v.optional(
v.object({
enabled: v.optional(v.boolean()),
}),
instructions: v.pipe(
v.optional(
v.object({
enabled: v.optional(v.boolean()),
}),
),
v.description(
'Configuration for the automatic AGENTS.md injection. You can choose if it should be enabled or not.',
),
),
skills: v.optional(
v.object({
enabled: v.optional(v.boolean()),
}),
skills: v.pipe(
v.optional(
v.object({
enabled: v.pipe(
v.optional(v.union([v.boolean(), v.array(v.string())])),
v.description(
'It can be either a boolean or an array containing the skills that you want to enable',
),
),
}),
),
v.description(
'Configuration for the skills. You can choose if it they should be enabled or not, or specify an array of skill names to enable only specific skills.',
),
),
});
@@ -112,8 +159,12 @@ function merge_with_defaults(user_config: Partial<McpConfig>): McpConfig {
...user_config.mcp,
},
subagent: {
...default_config.subagent,
enabled: default_config.subagent.enabled,
...user_config.subagent,
agents: {
...default_config.subagent.agents,
...user_config.subagent?.agents,
},
},
instructions: {
...default_config.instructions,
@@ -151,7 +202,11 @@ export function get_mcp_config(ctx: PluginInput) {
if (parsed.success) {
merged = {
mcp: { ...merged.mcp, ...parsed.output.mcp },
subagent: { ...merged.subagent, ...parsed.output.subagent },
subagent: {
...merged.subagent,
...parsed.output.subagent,
agents: { ...merged.subagent?.agents, ...parsed.output.subagent?.agents },
},
instructions: { ...merged.instructions, ...parsed.output.instructions },
skills: { ...merged.skills, ...parsed.output.skills },
};

View File

@@ -39,29 +39,41 @@ export const svelte_plugin: Plugin = async (ctx) => {
input.instructions.push(...instructions_paths.map((file) => join(instructions_dir, file)));
}
if (mcp_config.skills?.enabled !== false) {
const skills_enabled = mcp_config.skills?.enabled;
if (skills_enabled !== false) {
const skills_dir = join(current_dir, 'skills');
// @ts-expect-error -- skills is a new opencode feature
input.skills.paths.push(skills_dir);
if (Array.isArray(skills_enabled)) {
// only add specific skill directories by name
for (const skill_name of skills_enabled) {
const skill_path = join(skills_dir, skill_name);
// @ts-expect-error -- skills is a new opencode feature
input.skills.paths.push(skill_path);
}
} else {
// @ts-expect-error -- skills is a new opencode feature
input.skills.paths.push(skills_dir);
}
}
// if the user doesn't have the MCP server already we add one based on config
if (!input.mcp[svelte_mcp_name] && mcp_config.mcp?.enabled !== false) {
if (!input.mcp[svelte_mcp_name]) {
if (mcp_config.mcp?.type === 'remote') {
input.mcp[svelte_mcp_name] = {
type: 'remote',
url: 'https://mcp.svelte.dev/mcp',
enabled: mcp_config.mcp?.enabled ?? true,
};
} else {
input.mcp[svelte_mcp_name] = {
type: 'local',
command: ['npx', '-y', '@sveltejs/mcp'],
enabled: mcp_config.mcp?.enabled ?? true,
};
}
}
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
input.agent['svelte-file-editor'] = {
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.
@@ -138,6 +150,27 @@ After completing your work, provide:
[`${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,
}),
};
}
},
};

View File

@@ -1,6 +1,6 @@
{
"name": "@sveltejs/opencode",
"version": "0.1.4",
"version": "0.1.5",
"type": "module",
"license": "MIT",
"homepage": "https://github.com/sveltejs/ai-tools#readme",

View File

@@ -14,16 +14,55 @@
"type": "boolean"
}
},
"required": []
"required": [],
"description": "Configuration for the MCP. You can chose if it should be enabled or not and the transport to use 'remote' (default) and 'local'."
},
"subagent": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"agents": {
"type": "object",
"propertyNames": {
"anyOf": [
{
"enum": [
"svelte-file-editor"
]
},
{
"type": "string"
}
]
},
"additionalProperties": {
"type": "object",
"properties": {
"model": {
"type": "string",
"description": "Model identifier for the agent (e.g., \"anthropic/claude-sonnet-4-20250514\")"
},
"temperature": {
"type": "number",
"description": "Temperature setting for the agent (e.g., 0.7)"
},
"top_p": {
"type": "number",
"description": "Control response diversity with the top_p option. Alternative to temperature for controlling randomness."
},
"maxSteps": {
"type": "number",
"description": "Maximum number of steps the agent can take (e.g., 10)"
}
},
"required": []
}
}
},
"required": []
"required": [],
"description": "Configuration for the subagent. You can choose if it should be enabled or not."
},
"instructions": {
"type": "object",
@@ -32,16 +71,39 @@
"type": "boolean"
}
},
"required": []
"required": [],
"description": "Configuration for the automatic AGENTS.md injection. You can choose if it should be enabled or not."
},
"skills": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
"anyOf": [
{
"type": "boolean"
},
{
"type": "array",
"items": {
"anyOf": [
{
"enum": [
"svelte-code-writer",
"svelte-core-bestpractices"
]
},
{
"type": "string"
}
]
}
}
],
"description": "It can be either a boolean or an array containing the skills that you want to enable"
}
},
"required": []
"required": [],
"description": "Configuration for the skills. You can choose if it they should be enabled or not, or specify an array of skill names to enable only specific skills."
}
},
"required": [],

View File

@@ -3,6 +3,58 @@ import { config_schema } from '../config.js';
import fs from 'node:fs';
import path from 'node:path';
const json_schema = toJsonSchema(config_schema);
// Read agent names from tools/agents/*.md files
function get_agent_names(agents_dir: string) {
if (!fs.existsSync(agents_dir)) return [];
return fs
.readdirSync(agents_dir, { withFileTypes: true })
.filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
.map((entry) => entry.name.replace(/\.md$/, ''));
}
function get_skill_names(skills_dir: string) {
if (!fs.existsSync(skills_dir)) return [];
return fs
.readdirSync(skills_dir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => entry.name);
}
const skills_dir = path.resolve('./skills');
const skill_names = get_skill_names(skills_dir);
const schema = config_schema;
const json_schema = toJsonSchema(schema);
// Post-process: inject skill name suggestions into the items schema.
// This is the JSON Schema equivalent of `"a" | "b" | (string & {})` —
// editors will autocomplete the known names but any string is still valid.
if (skill_names.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const enabled = (json_schema as any).properties?.skills?.properties?.enabled;
if (enabled?.anyOf) {
const array_branch = enabled.anyOf.find((s: Record<string, unknown>) => s.type === 'array');
if (array_branch) {
array_branch.items = {
anyOf: [{ enum: skill_names }, { type: 'string' }],
};
}
}
}
// Post-process: inject known agent names for intellisense
// This is the JSON Schema equivalent of `"a" | "b" | (string & {})` —
// editors will autocomplete the known names but any string is still valid.
const agents_dir = path.resolve('../../tools/agents');
const agent_names = get_agent_names(agents_dir);
if (agent_names.length > 0) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const agents = (json_schema as any).properties?.subagent?.properties?.agents;
if (agents) {
agents.propertyNames = {
anyOf: [{ enum: agent_names }, { type: 'string' }],
};
}
}
fs.writeFileSync(path.resolve('./schema.json'), JSON.stringify(json_schema, null, '\t'));

View File

@@ -134,7 +134,7 @@ The CSS in a component's `<style>` is scoped to that component. If a parent comp
</style>
```
If this impossible (for example, the child component comes from a library) you can use `:global` to override styles:
If this is impossible (for example, the child component comes from a library) you can use `:global` to override styles:
```svelte
<div>

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.2",
"version": "1.0.3",
"author": {
"name": "Svelte"
},

View File

@@ -134,7 +134,7 @@ The CSS in a component's `<style>` is scoped to that component. If a parent comp
</style>
```
If this impossible (for example, the child component comes from a library) you can use `:global` to override styles:
If this is impossible (for example, the child component comes from a library) you can use `:global` to override styles:
```svelte
<div>

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.2",
"version": "1.0.3",
"author": {
"name": "Svelte"
},

View File

@@ -134,7 +134,7 @@ The CSS in a component's `<style>` is scoped to that component. If a parent comp
</style>
```
If this impossible (for example, the child component comes from a library) you can use `:global` to override styles:
If this is impossible (for example, the child component comes from a library) you can use `:global` to override styles:
```svelte
<div>

View File

@@ -18,9 +18,11 @@ ${module.docs_description}
<details>
<summary>Copy the prompt</summary>
\`\`\`md
<!-- prettier-ignore-start -->
\`\`\`\`markdown
${await module.generate_for_docs()}
\`\`\`
\`\`\`\`
<!-- prettier-ignore-end -->
</details>

View File

@@ -134,7 +134,7 @@ The CSS in a component's `<style>` is scoped to that component. If a parent comp
</style>
```
If this impossible (for example, the child component comes from a library) you can use `:global` to override styles:
If this is impossible (for example, the child component comes from a library) you can use `:global` to override styles:
```svelte
<div>