mirror of
https://github.com/sveltejs/ai-tools.git
synced 2026-07-03 19:19:25 +08:00
Compare commits
3 Commits
@sveltejs/
...
opencode-s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b29e265f01 | ||
|
|
463068a157 | ||
|
|
19c45f1c11 |
5
.changeset/young-pots-count.md
Normal file
5
.changeset/young-pots-count.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'@sveltejs/opencode': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat: allow enabling a specific skill in opencode plugin
|
||||||
5
.github/workflows/sync-plugins.yml
vendored
5
.github/workflows/sync-plugins.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
|||||||
run: pnpm sync-cursor-plugin
|
run: pnpm sync-cursor-plugin
|
||||||
|
|
||||||
- name: Sync OpenCode plugin
|
- name: Sync OpenCode plugin
|
||||||
run: pnpm sync-opencode-plugin
|
run: pnpm sync-opencode-plugin && pnpm generate-opencode-jsonschema
|
||||||
|
|
||||||
- name: Generate skills documentation
|
- name: Generate skills documentation
|
||||||
run: pnpm generate-skill-docs
|
run: pnpm generate-skill-docs
|
||||||
@@ -69,6 +69,7 @@ jobs:
|
|||||||
plugins/cursor/svelte/ \
|
plugins/cursor/svelte/ \
|
||||||
packages/opencode/skills/ \
|
packages/opencode/skills/ \
|
||||||
packages/opencode/instructions/ \
|
packages/opencode/instructions/ \
|
||||||
|
packages/opencode/schema.json \
|
||||||
documentation/docs/ \
|
documentation/docs/ \
|
||||||
|| echo "changed=true" >> $GITHUB_OUTPUT
|
|| echo "changed=true" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ jobs:
|
|||||||
## Changes
|
## Changes
|
||||||
- Synced `plugins/claude/svelte/` (skills, agents with `permissionMode`)
|
- Synced `plugins/claude/svelte/` (skills, agents with `permissionMode`)
|
||||||
- Synced `plugins/cursor/svelte/` (skills, agents, rules)
|
- Synced `plugins/cursor/svelte/` (skills, agents, rules)
|
||||||
- Synced `packages/opencode/` (skills, instructions)
|
- Synced `packages/opencode/` (skills, instructions, schema)
|
||||||
- Updated documentation
|
- Updated documentation
|
||||||
|
|
||||||
## Generated by
|
## Generated by
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ The default configuration for the Svelte OpenCode plugin looks like this...
|
|||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"enabled": true
|
"enabled": true // it can also be an array of all the skills to enable like ['svelte-core-bestpractices']
|
||||||
},
|
},
|
||||||
"instructions": {
|
"instructions": {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
@@ -40,6 +40,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`.
|
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`.
|
||||||
|
|||||||
@@ -16,31 +16,57 @@ const default_config = {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
skills: {
|
skills: {
|
||||||
enabled: true,
|
enabled: true as boolean | string[],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const config_schema = v.object({
|
export const config_schema = v.object({
|
||||||
mcp: v.optional(
|
mcp: v.pipe(
|
||||||
v.object({
|
v.optional(
|
||||||
type: v.optional(v.picklist(['remote', 'local'])),
|
v.object({
|
||||||
enabled: v.optional(v.boolean()),
|
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(
|
subagent: v.pipe(
|
||||||
v.object({
|
v.optional(
|
||||||
enabled: v.optional(v.boolean()),
|
v.object({
|
||||||
}),
|
enabled: v.optional(v.boolean()),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
v.description('Configuration for the subagent. You can choose if it should be enabled or not.'),
|
||||||
),
|
),
|
||||||
instructions: v.optional(
|
instructions: v.pipe(
|
||||||
v.object({
|
v.optional(
|
||||||
enabled: v.optional(v.boolean()),
|
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.',
|
||||||
|
),
|
||||||
|
v.description(
|
||||||
|
'Configuration for the automatic AGENTS.md injection. You can choose if it should be enabled or not.',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
skills: v.optional(
|
skills: v.pipe(
|
||||||
v.object({
|
v.optional(
|
||||||
enabled: v.optional(v.boolean()),
|
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.',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -39,10 +39,20 @@ export const svelte_plugin: Plugin = async (ctx) => {
|
|||||||
input.instructions.push(...instructions_paths.map((file) => join(instructions_dir, file)));
|
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');
|
const skills_dir = join(current_dir, 'skills');
|
||||||
// @ts-expect-error -- skills is a new opencode feature
|
if (Array.isArray(skills_enabled)) {
|
||||||
input.skills.paths.push(skills_dir);
|
// 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 the user doesn't have the MCP server already we add one based on config
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
"type": "boolean"
|
"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": {
|
"subagent": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -23,7 +24,8 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": [],
|
||||||
|
"description": "Configuration for the subagent. You can choose if it should be enabled or not."
|
||||||
},
|
},
|
||||||
"instructions": {
|
"instructions": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -32,16 +34,39 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": [],
|
||||||
|
"description": "Configuration for the automatic AGENTS.md injection. You can choose if it should be enabled or not."
|
||||||
},
|
},
|
||||||
"skills": {
|
"skills": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"enabled": {
|
"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": [],
|
"required": [],
|
||||||
|
|||||||
@@ -3,6 +3,33 @@ import { config_schema } from '../config.js';
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
const json_schema = toJsonSchema(config_schema);
|
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' }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fs.writeFileSync(path.resolve('./schema.json'), JSON.stringify(json_schema, null, '\t'));
|
fs.writeFileSync(path.resolve('./schema.json'), JSON.stringify(json_schema, null, '\t'));
|
||||||
|
|||||||
Reference in New Issue
Block a user