mirror of
https://github.com/sveltejs/ai-tools.git
synced 2026-08-03 09:04:16 +08:00
Compare commits
4 Commits
@sveltejs/
...
@sveltejs/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab14e46ec3 | ||
|
|
d6c694c778 | ||
|
|
a52c8b63bb | ||
|
|
8152ed9fd4 |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
||||||
"changelog": ["@svitejs/changesets-changelog-github-compact", { "repo": "sveltejs/ai-tools" }],
|
"changelog": ["@changesets/changelog-github", { "repo": "sveltejs/ai-tools", "template": "\n- {summary} {ref}" }],
|
||||||
"commit": false,
|
"commit": false,
|
||||||
"fixed": [],
|
"fixed": [],
|
||||||
"linked": [],
|
"linked": [],
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- 'packages/opencode/config.ts'
|
- 'packages/opencode/config.js'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -67,7 +67,7 @@ jobs:
|
|||||||
## Summary
|
## Summary
|
||||||
Automatically generated update for OpenCode JSON schema.
|
Automatically generated update for OpenCode JSON schema.
|
||||||
|
|
||||||
This PR was triggered by changes to the OpenCode configuration file `packages/opencode/config.ts`.
|
This PR was triggered by changes to the OpenCode configuration file `packages/opencode/config.js`.
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
- Updated `packages/opencode/schema.json` with latest JSON schema
|
- Updated `packages/opencode/schema.json` with latest JSON schema
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ The package also includes a TUI plugin for configuring these features interactiv
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Restart OpenCode, then run `/svelte-plugin` or select **Configure Svelte plugin** from the command palette. Choose whether to edit the project or global configuration, then use the checkboxes and radio options to configure the plugin. Changes are saved automatically, and **Revert changes** restores the values from when the dialog was opened.
|
Restart OpenCode, then run `/svelte-plugin` or select 'Configure Svelte plugin' from the command palette. Choose whether to edit the project or global configuration, then use the checkboxes and radio options to configure the plugin. Changes are saved automatically, and 'Revert changes' restores the values from when the dialog was opened.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ If possible, we recommend that you instruct the LLM to execute MCP calls with th
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
In VS Code, run the **Install plugin from source** command and use the repository URL:
|
In VS Code, run the 'Install plugin from source' command and use the repository URL:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
https://github.com/sveltejs/ai-tools
|
https://github.com/sveltejs/ai-tools
|
||||||
|
|||||||
@@ -43,12 +43,12 @@
|
|||||||
],
|
],
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@changesets/changelog-github": "catalog:tooling",
|
||||||
"@changesets/cli": "catalog:tooling",
|
"@changesets/cli": "catalog:tooling",
|
||||||
"@eslint/compat": "catalog:lint",
|
"@eslint/compat": "catalog:lint",
|
||||||
"@eslint/js": "catalog:lint",
|
"@eslint/js": "catalog:lint",
|
||||||
"@modelcontextprotocol/inspector": "catalog:ai",
|
"@modelcontextprotocol/inspector": "catalog:ai",
|
||||||
"@sveltejs/adapter-vercel": "catalog:svelte",
|
"@sveltejs/adapter-vercel": "catalog:svelte",
|
||||||
"@svitejs/changesets-changelog-github-compact": "catalog:tooling",
|
|
||||||
"eslint": "catalog:lint",
|
"eslint": "catalog:lint",
|
||||||
"eslint-config-prettier": "catalog:lint",
|
"eslint-config-prettier": "catalog:lint",
|
||||||
"eslint-plugin-import": "catalog:lint",
|
"eslint-plugin-import": "catalog:lint",
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @sveltejs/opencode
|
# @sveltejs/opencode
|
||||||
|
|
||||||
|
## 0.1.11
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- fix: ship plugin as js files instead of ts ([#236](https://github.com/sveltejs/ai-tools/pull/236))
|
||||||
|
|
||||||
## 0.1.10
|
## 0.1.10
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ export const agents = {
|
|||||||
prompt:
|
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)",
|
"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;
|
};
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import type { PluginInput } from '@opencode-ai/plugin';
|
|
||||||
import { existsSync, readFileSync } from 'fs';
|
import { existsSync, readFileSync } from 'fs';
|
||||||
import { homedir } from 'os';
|
import { homedir } from 'os';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import * as v from 'valibot';
|
import * as v from 'valibot';
|
||||||
|
|
||||||
|
/** @typedef {import('@opencode-ai/plugin').PluginInput} PluginInput */
|
||||||
|
|
||||||
// Schema for individual agent configuration
|
// Schema for individual agent configuration
|
||||||
const agent_config_schema = v.object({
|
const agent_config_schema = v.object({
|
||||||
model: v.pipe(
|
model: v.pipe(
|
||||||
@@ -28,18 +29,18 @@ const agent_config_schema = v.object({
|
|||||||
|
|
||||||
const default_config = {
|
const default_config = {
|
||||||
mcp: {
|
mcp: {
|
||||||
type: 'remote' as 'remote' | 'local',
|
type: /** @type {'remote' | 'local'} */ ('remote'),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
subagent: {
|
subagent: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
agents: {} as Record<string, v.InferInput<typeof agent_config_schema>>,
|
agents: /** @type {Record<string, v.InferInput<typeof agent_config_schema>>} */ ({}),
|
||||||
},
|
},
|
||||||
instructions: {
|
instructions: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
},
|
},
|
||||||
skills: {
|
skills: {
|
||||||
enabled: true as boolean | string[],
|
enabled: /** @type {boolean | string[]} */ (true),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,25 +92,24 @@ export const config_schema = v.object({
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type McpConfig = v.InferInput<typeof config_schema>;
|
/** @typedef {v.InferInput<typeof config_schema>} McpConfig */
|
||||||
|
|
||||||
const GLOBAL_CONFIG_DIR = join(homedir(), '.config', 'opencode');
|
const GLOBAL_CONFIG_DIR = join(homedir(), '.config', 'opencode');
|
||||||
const GLOBAL_CONFIG_PATH = join(GLOBAL_CONFIG_DIR, 'svelte.json');
|
const GLOBAL_CONFIG_PATH = join(GLOBAL_CONFIG_DIR, 'svelte.json');
|
||||||
|
|
||||||
interface ConfigLoadResult {
|
/** @typedef {{ data: Record<string, unknown> | null, parse_error?: string }} ConfigLoadResult */
|
||||||
data: Record<string, unknown> | null;
|
|
||||||
parse_error?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_config_paths() {
|
function get_config_paths() {
|
||||||
// Global: ~/.config/opencode/svelte.json
|
// Global: ~/.config/opencode/svelte.json
|
||||||
let global_path: string | null = null;
|
/** @type {string | null} */
|
||||||
|
let global_path = null;
|
||||||
if (existsSync(GLOBAL_CONFIG_PATH)) {
|
if (existsSync(GLOBAL_CONFIG_PATH)) {
|
||||||
global_path = GLOBAL_CONFIG_PATH;
|
global_path = GLOBAL_CONFIG_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom config directory: $OPENCODE_CONFIG_DIR/svelte.json
|
// Custom config directory: $OPENCODE_CONFIG_DIR/svelte.json
|
||||||
let config_dir_path: string | null = null;
|
/** @type {string | null} */
|
||||||
|
let config_dir_path = null;
|
||||||
const opencode_config_dir = process.env.OPENCODE_CONFIG_DIR;
|
const opencode_config_dir = process.env.OPENCODE_CONFIG_DIR;
|
||||||
if (opencode_config_dir) {
|
if (opencode_config_dir) {
|
||||||
const config_json = join(opencode_config_dir, 'svelte.json');
|
const config_json = join(opencode_config_dir, 'svelte.json');
|
||||||
@@ -119,7 +119,8 @@ function get_config_paths() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Project-local: ./.opencode/svelte.json (cwd)
|
// Project-local: ./.opencode/svelte.json (cwd)
|
||||||
let project_path: string | null = null;
|
/** @type {string | null} */
|
||||||
|
let project_path = null;
|
||||||
const project_config = join(process.cwd(), '.opencode', 'svelte.json');
|
const project_config = join(process.cwd(), '.opencode', 'svelte.json');
|
||||||
if (existsSync(project_config)) {
|
if (existsSync(project_config)) {
|
||||||
project_path = project_config;
|
project_path = project_config;
|
||||||
@@ -129,8 +130,13 @@ function get_config_paths() {
|
|||||||
return [global_path, config_dir_path, project_path];
|
return [global_path, config_dir_path, project_path];
|
||||||
}
|
}
|
||||||
|
|
||||||
function load_config_file(config_path: string): ConfigLoadResult {
|
/**
|
||||||
let file_content: string;
|
* @param {string} config_path
|
||||||
|
* @returns {ConfigLoadResult}
|
||||||
|
*/
|
||||||
|
function load_config_file(config_path) {
|
||||||
|
/** @type {string} */
|
||||||
|
let file_content;
|
||||||
try {
|
try {
|
||||||
file_content = readFileSync(config_path, 'utf-8');
|
file_content = readFileSync(config_path, 'utf-8');
|
||||||
} catch {
|
} catch {
|
||||||
@@ -144,7 +150,7 @@ function load_config_file(config_path: string): ConfigLoadResult {
|
|||||||
return { data: null, parse_error: 'Config file is empty or invalid' };
|
return { data: null, parse_error: 'Config file is empty or invalid' };
|
||||||
}
|
}
|
||||||
return { data: parsed };
|
return { data: parsed };
|
||||||
} catch (error: unknown) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
data: null,
|
data: null,
|
||||||
parse_error: error instanceof Error ? error.message : 'Failed to parse config',
|
parse_error: error instanceof Error ? error.message : 'Failed to parse config',
|
||||||
@@ -152,7 +158,11 @@ function load_config_file(config_path: string): ConfigLoadResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function merge_with_defaults(user_config: Partial<McpConfig>): McpConfig {
|
/**
|
||||||
|
* @param {Partial<McpConfig>} user_config
|
||||||
|
* @returns {McpConfig}
|
||||||
|
*/
|
||||||
|
function merge_with_defaults(user_config) {
|
||||||
return {
|
return {
|
||||||
mcp: {
|
mcp: {
|
||||||
...default_config.mcp,
|
...default_config.mcp,
|
||||||
@@ -177,9 +187,11 @@ function merge_with_defaults(user_config: Partial<McpConfig>): McpConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function get_mcp_config(ctx: PluginInput) {
|
/** @param {PluginInput} ctx */
|
||||||
|
export function get_mcp_config(ctx) {
|
||||||
const config_paths = get_config_paths();
|
const config_paths = get_config_paths();
|
||||||
let merged: Partial<McpConfig> = {};
|
/** @type {Partial<McpConfig>} */
|
||||||
|
let merged = {};
|
||||||
|
|
||||||
// Iterate from lowest to highest priority, merging as we go
|
// Iterate from lowest to highest priority, merging as we go
|
||||||
for (const path of config_paths) {
|
for (const path of config_paths) {
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
import type { Plugin } from '@opencode-ai/plugin';
|
|
||||||
import { readdir } from 'node:fs/promises';
|
import { readdir } from 'node:fs/promises';
|
||||||
import { dirname, join } from 'node:path';
|
import { dirname, join } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { agents } from './agents.ts';
|
import { agents } from './agents.js';
|
||||||
import { get_mcp_config } from './config.ts';
|
import { get_mcp_config } from './config.js';
|
||||||
|
|
||||||
|
/** @typedef {import('@opencode-ai/plugin').Plugin} Plugin */
|
||||||
|
|
||||||
const current_dir = dirname(fileURLToPath(import.meta.url));
|
const current_dir = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
export const svelte_plugin: Plugin = async (ctx) => {
|
/**
|
||||||
|
* @param {Parameters<Plugin>[0]} ctx
|
||||||
|
* @returns {ReturnType<Plugin>}
|
||||||
|
*/
|
||||||
|
export async function svelte_plugin(ctx) {
|
||||||
return {
|
return {
|
||||||
async config(input) {
|
async config(input) {
|
||||||
input.agent ??= {};
|
input.agent ??= {};
|
||||||
@@ -24,8 +29,7 @@ export const svelte_plugin: Plugin = async (ctx) => {
|
|||||||
const mcp = input.mcp[name];
|
const mcp = input.mcp[name];
|
||||||
if (
|
if (
|
||||||
(mcp?.type === 'remote' && mcp.url.includes('https://mcp.svelte.dev/mcp')) ||
|
(mcp?.type === 'remote' && mcp.url.includes('https://mcp.svelte.dev/mcp')) ||
|
||||||
(mcp?.type === 'local' &&
|
(mcp?.type === 'local' && mcp.command.some((cmd) => cmd.includes('@sveltejs/mcp')))
|
||||||
mcp.command.some((cmd: string) => cmd.includes('@sveltejs/mcp')))
|
|
||||||
) {
|
) {
|
||||||
// if we found the svelte MCP server, we store its name and break
|
// if we found the svelte MCP server, we store its name and break
|
||||||
svelte_mcp_name = name;
|
svelte_mcp_name = name;
|
||||||
@@ -75,7 +79,8 @@ export const svelte_plugin: Plugin = async (ctx) => {
|
|||||||
if (mcp_config.subagent?.enabled !== false) {
|
if (mcp_config.subagent?.enabled !== false) {
|
||||||
for (const [agent_name, agent_data] of Object.entries(agents)) {
|
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
|
// 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] = {
|
/** @type {(typeof input.agent)[string]} */
|
||||||
|
const default_config = {
|
||||||
color: '#ff3e00',
|
color: '#ff3e00',
|
||||||
mode: 'subagent',
|
mode: 'subagent',
|
||||||
prompt: agent_data.prompt,
|
prompt: agent_data.prompt,
|
||||||
@@ -109,4 +114,4 @@ export const svelte_plugin: Plugin = async (ctx) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@sveltejs/opencode",
|
"name": "@sveltejs/opencode",
|
||||||
"version": "0.1.10",
|
"version": "0.1.11",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"homepage": "https://github.com/sveltejs/ai-tools#readme",
|
"homepage": "https://github.com/sveltejs/ai-tools#readme",
|
||||||
@@ -9,24 +9,24 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"check": "tsc --noEmit",
|
"check": "tsc --noEmit",
|
||||||
"generate-schema": "node --import node-resolve-ts/register scripts/generate-schema.ts"
|
"generate-schema": "node scripts/generate-schema.js"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"index.ts",
|
"index.js",
|
||||||
"config.ts",
|
"config.js",
|
||||||
"tui.tsx",
|
"tui.jsx",
|
||||||
"agents.ts",
|
"agents.js",
|
||||||
"instructions",
|
"instructions",
|
||||||
"skills"
|
"skills"
|
||||||
],
|
],
|
||||||
"exports": {
|
"exports": {
|
||||||
"./server": {
|
"./server": {
|
||||||
"types": "./index.ts",
|
"types": "./index.js",
|
||||||
"import": "./index.ts"
|
"import": "./index.js"
|
||||||
},
|
},
|
||||||
"./tui": {
|
"./tui": {
|
||||||
"types": "./tui.tsx",
|
"types": "./tui.jsx",
|
||||||
"import": "./tui.tsx"
|
"import": "./tui.jsx"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import fs from 'node:fs';
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
// Read agent names from tools/agents/*.md files
|
// Read agent names from tools/agents/*.md files
|
||||||
function get_agent_names(agents_dir: string) {
|
/** @param {string} agents_dir */
|
||||||
|
function get_agent_names(agents_dir) {
|
||||||
if (!fs.existsSync(agents_dir)) return [];
|
if (!fs.existsSync(agents_dir)) return [];
|
||||||
return fs
|
return fs
|
||||||
.readdirSync(agents_dir, { withFileTypes: true })
|
.readdirSync(agents_dir, { withFileTypes: true })
|
||||||
@@ -12,7 +13,8 @@ function get_agent_names(agents_dir: string) {
|
|||||||
.map((entry) => entry.name.replace(/\.md$/, ''));
|
.map((entry) => entry.name.replace(/\.md$/, ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_skill_names(skills_dir: string) {
|
/** @param {string} skills_dir */
|
||||||
|
function get_skill_names(skills_dir) {
|
||||||
if (!fs.existsSync(skills_dir)) return [];
|
if (!fs.existsSync(skills_dir)) return [];
|
||||||
return fs
|
return fs
|
||||||
.readdirSync(skills_dir, { withFileTypes: true })
|
.readdirSync(skills_dir, { withFileTypes: true })
|
||||||
@@ -29,10 +31,13 @@ const json_schema = toJsonSchema(schema);
|
|||||||
// This is the JSON Schema equivalent of `"a" | "b" | (string & {})` —
|
// This is the JSON Schema equivalent of `"a" | "b" | (string & {})` —
|
||||||
// editors will autocomplete the known names but any string is still valid.
|
// editors will autocomplete the known names but any string is still valid.
|
||||||
if (skill_names.length > 0) {
|
if (skill_names.length > 0) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
const enabled = /** @type {any} */ (json_schema).properties?.skills?.properties?.enabled;
|
||||||
const enabled = (json_schema as any).properties?.skills?.properties?.enabled;
|
|
||||||
if (enabled?.anyOf) {
|
if (enabled?.anyOf) {
|
||||||
const array_branch = enabled.anyOf.find((s: Record<string, unknown>) => s.type === 'array');
|
const array_branch = enabled.anyOf.find(
|
||||||
|
/** @type {(schema: Record<string, unknown>) => boolean} */ (
|
||||||
|
(schema) => schema.type === 'array'
|
||||||
|
),
|
||||||
|
);
|
||||||
if (array_branch) {
|
if (array_branch) {
|
||||||
array_branch.items = {
|
array_branch.items = {
|
||||||
anyOf: [{ enum: skill_names }, { type: 'string' }],
|
anyOf: [{ enum: skill_names }, { type: 'string' }],
|
||||||
@@ -48,8 +53,7 @@ const agents_dir = path.resolve('../../tools/agents');
|
|||||||
const agent_names = get_agent_names(agents_dir);
|
const agent_names = get_agent_names(agents_dir);
|
||||||
|
|
||||||
if (agent_names.length > 0) {
|
if (agent_names.length > 0) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
const agents = /** @type {any} */ (json_schema).properties?.subagent?.properties?.agents;
|
||||||
const agents = (json_schema as any).properties?.subagent?.properties?.agents;
|
|
||||||
if (agents) {
|
if (agents) {
|
||||||
agents.propertyNames = {
|
agents.propertyNames = {
|
||||||
anyOf: [{ enum: agent_names }, { type: 'string' }],
|
anyOf: [{ enum: agent_names }, { type: 'string' }],
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowImportingTsExtensions": true,
|
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"jsxImportSource": "@opentui/solid",
|
"jsxImportSource": "@opentui/solid",
|
||||||
"types": ["@types/node"]
|
"types": ["@types/node"]
|
||||||
},
|
},
|
||||||
"include": ["index.ts", "config.ts", "agents.ts", "tui.tsx", "scripts/*"],
|
"include": ["index.js", "config.js", "agents.js", "tui.jsx", "scripts/*"],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,33 @@
|
|||||||
/** @jsxImportSource @opentui/solid */
|
/** @jsxImportSource @opentui/solid */
|
||||||
import type { TuiPlugin, TuiPluginModule } from '@opencode-ai/plugin/tui';
|
|
||||||
import { existsSync } from 'node:fs';
|
import { existsSync } from 'node:fs';
|
||||||
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||||
import { homedir } from 'node:os';
|
import { homedir } from 'node:os';
|
||||||
import { dirname, join } from 'node:path';
|
import { dirname, join } from 'node:path';
|
||||||
import * as v from 'valibot';
|
import * as v from 'valibot';
|
||||||
import { config_schema, type McpConfig } from './config.ts';
|
import { config_schema } from './config.js';
|
||||||
|
|
||||||
|
/** @typedef {import('@opencode-ai/plugin/tui').TuiPlugin} TuiPlugin */
|
||||||
|
/** @typedef {import('@opencode-ai/plugin/tui').TuiPluginApi} TuiPluginApi */
|
||||||
|
/** @typedef {import('@opencode-ai/plugin/tui').TuiPluginModule} TuiPluginModule */
|
||||||
|
/** @typedef {v.InferInput<typeof config_schema>} McpConfig */
|
||||||
|
/** @typedef {'project' | 'global'} Scope */
|
||||||
|
/** @typedef {Partial<McpConfig>} Config */
|
||||||
|
|
||||||
const plugin_id = 'svelte.configure';
|
const plugin_id = 'svelte.configure';
|
||||||
const skill_names = ['svelte-code-writer', 'svelte-core-bestpractices'] as const;
|
const skill_names = ['svelte-code-writer', 'svelte-core-bestpractices'];
|
||||||
const agent_name = 'svelte-file-editor';
|
const agent_name = 'svelte-file-editor';
|
||||||
|
|
||||||
type Scope = 'project' | 'global';
|
/** @param {TuiPluginApi} api */
|
||||||
type Config = Partial<McpConfig>;
|
function project_root(api) {
|
||||||
|
|
||||||
function project_root(api: Parameters<TuiPlugin>[0]) {
|
|
||||||
const worktree = api.state.path.worktree;
|
const worktree = api.state.path.worktree;
|
||||||
return worktree && worktree !== '/' ? worktree : api.state.path.directory;
|
return worktree && worktree !== '/' ? worktree : api.state.path.directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
function config_path(api: Parameters<TuiPlugin>[0], scope: Scope) {
|
/**
|
||||||
|
* @param {TuiPluginApi} api
|
||||||
|
* @param {Scope} scope
|
||||||
|
*/
|
||||||
|
function config_path(api, scope) {
|
||||||
if (scope === 'project') return join(project_root(api), '.opencode', 'svelte.json');
|
if (scope === 'project') return join(project_root(api), '.opencode', 'svelte.json');
|
||||||
return join(
|
return join(
|
||||||
process.env.OPENCODE_CONFIG_DIR ?? join(homedir(), '.config', 'opencode'),
|
process.env.OPENCODE_CONFIG_DIR ?? join(homedir(), '.config', 'opencode'),
|
||||||
@@ -27,26 +35,40 @@ function config_path(api: Parameters<TuiPlugin>[0], scope: Scope) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function read_config(path: string): Promise<Config> {
|
/**
|
||||||
|
* @param {string} path
|
||||||
|
* @returns {Promise<Config>}
|
||||||
|
*/
|
||||||
|
async function read_config(path) {
|
||||||
if (!existsSync(path)) return {};
|
if (!existsSync(path)) return {};
|
||||||
const parsed: unknown = JSON.parse(await readFile(path, 'utf8'));
|
/** @type {unknown} */
|
||||||
|
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
||||||
const result = v.safeParse(config_schema, parsed);
|
const result = v.safeParse(config_schema, parsed);
|
||||||
if (!result.success)
|
if (!result.success)
|
||||||
throw new Error('The existing file does not match the Svelte plugin schema.');
|
throw new Error('The existing file does not match the Svelte plugin schema.');
|
||||||
// Keep schema annotations and future fields that this version does not edit.
|
// Keep schema annotations and future fields that this version does not edit.
|
||||||
return parsed as Config;
|
return /** @type {Config} */ (parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function save_config(path: string, config: Config) {
|
/**
|
||||||
|
* @param {string} path
|
||||||
|
* @param {Config} config
|
||||||
|
*/
|
||||||
|
async function save_config(path, config) {
|
||||||
await mkdir(dirname(path), { recursive: true });
|
await mkdir(dirname(path), { recursive: true });
|
||||||
await writeFile(path, `${JSON.stringify(config, null, '\t')}\n`, 'utf8');
|
await writeFile(path, `${JSON.stringify(config, null, '\t')}\n`, 'utf8');
|
||||||
}
|
}
|
||||||
|
|
||||||
function display(value: unknown, fallback = 'default') {
|
/**
|
||||||
|
* @param {unknown} value
|
||||||
|
* @param {string} [fallback]
|
||||||
|
*/
|
||||||
|
function display(value, fallback = 'default') {
|
||||||
return value === undefined ? fallback : String(value);
|
return value === undefined ? fallback : String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const tui: TuiPlugin = async (api) => {
|
/** @type {TuiPlugin} */
|
||||||
|
const tui = async (api) => {
|
||||||
function open_scope() {
|
function open_scope() {
|
||||||
if (!api.state.path.directory) {
|
if (!api.state.path.directory) {
|
||||||
api.ui.toast({
|
api.ui.toast({
|
||||||
@@ -57,7 +79,7 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
api.ui.dialog.replace(() => (
|
api.ui.dialog.replace(() => (
|
||||||
<api.ui.DialogSelect<Scope>
|
<api.ui.DialogSelect
|
||||||
title="Configure Svelte plugin"
|
title="Configure Svelte plugin"
|
||||||
options={[
|
options={[
|
||||||
{
|
{
|
||||||
@@ -71,14 +93,16 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
description: 'Write svelte.json in the OpenCode config directory',
|
description: 'Write svelte.json in the OpenCode config directory',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
onSelect={(option) => void open_config(option.value)}
|
onSelect={(option) => void open_config(/** @type {Scope} */ (option.value))}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function open_config(scope: Scope) {
|
/** @param {Scope} scope */
|
||||||
|
async function open_config(scope) {
|
||||||
const path = config_path(api, scope);
|
const path = config_path(api, scope);
|
||||||
let config: Config;
|
/** @type {Config} */
|
||||||
|
let config;
|
||||||
try {
|
try {
|
||||||
config = await read_config(path);
|
config = await read_config(path);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -90,7 +114,8 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const original_config = structuredClone(config);
|
const original_config = structuredClone(config);
|
||||||
let current_option: string | undefined;
|
/** @type {string | undefined} */
|
||||||
|
let current_option;
|
||||||
|
|
||||||
async function persist(show_toast = true) {
|
async function persist(show_toast = true) {
|
||||||
try {
|
try {
|
||||||
@@ -102,7 +127,11 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prompt_agent_number(key: 'temperature' | 'top_p' | 'maxSteps', label: string) {
|
/**
|
||||||
|
* @param {'temperature' | 'top_p' | 'maxSteps'} key
|
||||||
|
* @param {string} label
|
||||||
|
*/
|
||||||
|
function prompt_agent_number(key, label) {
|
||||||
const agent = config.subagent?.agents?.[agent_name];
|
const agent = config.subagent?.agents?.[agent_name];
|
||||||
api.ui.dialog.replace(() => (
|
api.ui.dialog.replace(() => (
|
||||||
<api.ui.DialogPrompt
|
<api.ui.DialogPrompt
|
||||||
@@ -129,7 +158,7 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
function open_agent() {
|
function open_agent() {
|
||||||
const agent = config.subagent?.agents?.[agent_name];
|
const agent = config.subagent?.agents?.[agent_name];
|
||||||
api.ui.dialog.replace(() => (
|
api.ui.dialog.replace(() => (
|
||||||
<api.ui.DialogSelect<string>
|
<api.ui.DialogSelect
|
||||||
title={`Configure ${agent_name}`}
|
title={`Configure ${agent_name}`}
|
||||||
options={[
|
options={[
|
||||||
{ title: 'Model', value: 'model', description: display(agent?.model) },
|
{ title: 'Model', value: 'model', description: display(agent?.model) },
|
||||||
@@ -144,11 +173,12 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
]}
|
]}
|
||||||
onSelect={(option) => {
|
onSelect={(option) => {
|
||||||
if (option.value === 'back') return open_menu();
|
if (option.value === 'back') return open_menu();
|
||||||
if (option.value !== 'model')
|
if (
|
||||||
return prompt_agent_number(
|
option.value === 'temperature' ||
|
||||||
option.value as 'temperature' | 'top_p' | 'maxSteps',
|
option.value === 'top_p' ||
|
||||||
option.title,
|
option.value === 'maxSteps'
|
||||||
);
|
)
|
||||||
|
return prompt_agent_number(option.value, option.title);
|
||||||
api.ui.dialog.replace(() => (
|
api.ui.dialog.replace(() => (
|
||||||
<api.ui.DialogPrompt
|
<api.ui.DialogPrompt
|
||||||
title={`${agent_name}: model`}
|
title={`${agent_name}: model`}
|
||||||
@@ -178,14 +208,16 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
Array.isArray(skills) ? skills : skills === false ? [] : skill_names,
|
Array.isArray(skills) ? skills : skills === false ? [] : skill_names,
|
||||||
);
|
);
|
||||||
const all_skills_selected = skill_names.every((name) => selected_skills.has(name));
|
const all_skills_selected = skill_names.every((name) => selected_skills.has(name));
|
||||||
function checked(value: boolean | undefined) {
|
/** @param {boolean | undefined} value */
|
||||||
|
function checked(value) {
|
||||||
return value !== false ? '[x]' : '[ ]';
|
return value !== false ? '[x]' : '[ ]';
|
||||||
}
|
}
|
||||||
function radio(value: 'remote' | 'local') {
|
/** @param {'remote' | 'local'} value */
|
||||||
|
function radio(value) {
|
||||||
return (config.mcp?.type ?? 'remote') === value ? '(*)' : '( )';
|
return (config.mcp?.type ?? 'remote') === value ? '(*)' : '( )';
|
||||||
}
|
}
|
||||||
api.ui.dialog.replace(() => (
|
api.ui.dialog.replace(() => (
|
||||||
<api.ui.DialogSelect<string>
|
<api.ui.DialogSelect
|
||||||
title={`Svelte plugin (${scope})`}
|
title={`Svelte plugin (${scope})`}
|
||||||
{...(current_option === undefined ? {} : { current: current_option })}
|
{...(current_option === undefined ? {} : { current: current_option })}
|
||||||
skipFilter
|
skipFilter
|
||||||
@@ -285,7 +317,7 @@ const tui: TuiPlugin = async (api) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
export default /** @satisfies {TuiPluginModule & { id: string }} */ ({
|
||||||
id: plugin_id,
|
id: plugin_id,
|
||||||
tui,
|
tui,
|
||||||
} satisfies TuiPluginModule & { id: string };
|
});
|
||||||
63
pnpm-lock.yaml
generated
63
pnpm-lock.yaml
generated
@@ -107,12 +107,12 @@ catalogs:
|
|||||||
specifier: ^1.19.3
|
specifier: ^1.19.3
|
||||||
version: 1.19.3
|
version: 1.19.3
|
||||||
tooling:
|
tooling:
|
||||||
|
'@changesets/changelog-github':
|
||||||
|
specifier: 1.0.0-next.6
|
||||||
|
version: 1.0.0-next.6
|
||||||
'@changesets/cli':
|
'@changesets/cli':
|
||||||
specifier: ^2.29.7
|
specifier: ^2.29.7
|
||||||
version: 2.29.8
|
version: 2.29.8
|
||||||
'@svitejs/changesets-changelog-github-compact':
|
|
||||||
specifier: ^1.2.0
|
|
||||||
version: 1.2.0
|
|
||||||
'@types/estree':
|
'@types/estree':
|
||||||
specifier: ^1.0.8
|
specifier: ^1.0.8
|
||||||
version: 1.0.8
|
version: 1.0.8
|
||||||
@@ -166,6 +166,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@changesets/changelog-github':
|
||||||
|
specifier: catalog:tooling
|
||||||
|
version: 1.0.0-next.6
|
||||||
'@changesets/cli':
|
'@changesets/cli':
|
||||||
specifier: catalog:tooling
|
specifier: catalog:tooling
|
||||||
version: 2.29.8(@types/node@24.10.9)
|
version: 2.29.8(@types/node@24.10.9)
|
||||||
@@ -181,9 +184,6 @@ importers:
|
|||||||
'@sveltejs/adapter-vercel':
|
'@sveltejs/adapter-vercel':
|
||||||
specifier: catalog:svelte
|
specifier: catalog:svelte
|
||||||
version: 6.3.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.56.1(@typescript-eslint/types@8.54.0))(vite@7.3.1(@types/node@24.10.9)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.54.0))(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.9)(yaml@2.9.0)))(rollup@4.57.0)
|
version: 6.3.1(@sveltejs/kit@2.50.1(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.56.1(@typescript-eslint/types@8.54.0))(vite@7.3.1(@types/node@24.10.9)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.54.0))(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.9)(yaml@2.9.0)))(rollup@4.57.0)
|
||||||
'@svitejs/changesets-changelog-github-compact':
|
|
||||||
specifier: catalog:tooling
|
|
||||||
version: 1.2.0
|
|
||||||
eslint:
|
eslint:
|
||||||
specifier: catalog:lint
|
specifier: catalog:lint
|
||||||
version: 9.39.2
|
version: 9.39.2
|
||||||
@@ -605,6 +605,10 @@ packages:
|
|||||||
'@changesets/changelog-git@0.2.1':
|
'@changesets/changelog-git@0.2.1':
|
||||||
resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==}
|
resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==}
|
||||||
|
|
||||||
|
'@changesets/changelog-github@1.0.0-next.6':
|
||||||
|
resolution: {integrity: sha512-0ShCWgNt50xP0mryAYT8wtSkMUinG8uhxXgCgwHZ4UvJnR2f4ns8OsGAxYu8FIds7kHFdLOz7qX4YQ6AX4tVUA==}
|
||||||
|
engines: {node: ^22.11 || ^24 || >=26}
|
||||||
|
|
||||||
'@changesets/cli@2.29.8':
|
'@changesets/cli@2.29.8':
|
||||||
resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==}
|
resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@@ -618,8 +622,9 @@ packages:
|
|||||||
'@changesets/get-dependents-graph@2.1.3':
|
'@changesets/get-dependents-graph@2.1.3':
|
||||||
resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==}
|
resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==}
|
||||||
|
|
||||||
'@changesets/get-github-info@0.6.0':
|
'@changesets/get-github-info@1.0.0-next.4':
|
||||||
resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==}
|
resolution: {integrity: sha512-Bosh+XOoFvLMzAj301tg6phbrEggBtvEccrnceEvYsKSM7PjcIa32Fy22SU5g+501HZywkdwcAlybdWF+e/zzw==}
|
||||||
|
engines: {node: ^22.11 || ^24 || >=26}
|
||||||
|
|
||||||
'@changesets/get-release-plan@4.0.14':
|
'@changesets/get-release-plan@4.0.14':
|
||||||
resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==}
|
resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==}
|
||||||
@@ -651,6 +656,10 @@ packages:
|
|||||||
'@changesets/types@6.1.0':
|
'@changesets/types@6.1.0':
|
||||||
resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==}
|
resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==}
|
||||||
|
|
||||||
|
'@changesets/types@7.0.0-next.7':
|
||||||
|
resolution: {integrity: sha512-1XyshLw+lRCg2DWxi1Qt3hbezjBostHzXvGXVgSzAeZ+fL+r2ikcMbpaQ98D9ivwKhYFf1FBbKbEc+XsBZsIJQ==}
|
||||||
|
engines: {node: ^22.11 || ^24 || >=26}
|
||||||
|
|
||||||
'@changesets/write@0.4.0':
|
'@changesets/write@0.4.0':
|
||||||
resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==}
|
resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==}
|
||||||
|
|
||||||
@@ -2053,10 +2062,6 @@ packages:
|
|||||||
svelte: ^5.0.0
|
svelte: ^5.0.0
|
||||||
vite: ^6.3.0 || ^7.0.0
|
vite: ^6.3.0 || ^7.0.0
|
||||||
|
|
||||||
'@svitejs/changesets-changelog-github-compact@1.2.0':
|
|
||||||
resolution: {integrity: sha512-08eKiDAjj4zLug1taXSIJ0kGL5cawjVCyJkBb6EWSg5fEPX6L+Wtr0CH2If4j5KYylz85iaZiFlUItvgJvll5g==}
|
|
||||||
engines: {node: ^14.13.1 || ^16.0.0 || >=18}
|
|
||||||
|
|
||||||
'@tmcp/adapter-valibot@0.1.5':
|
'@tmcp/adapter-valibot@0.1.5':
|
||||||
resolution: {integrity: sha512-9P2wrVYPngemNK0UvPb/opC722/jfd09QxXmme1TRp/wPsl98vpSk/MXt24BCMqBRv4Dvs0xxJH4KHDcjXW52Q==}
|
resolution: {integrity: sha512-9P2wrVYPngemNK0UvPb/opC722/jfd09QxXmme1TRp/wPsl98vpSk/MXt24BCMqBRv4Dvs0xxJH4KHDcjXW52Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -2611,8 +2616,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
dataloader@1.4.0:
|
dataloader@2.2.3:
|
||||||
resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==}
|
resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==}
|
||||||
|
|
||||||
debug@3.2.7:
|
debug@3.2.7:
|
||||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||||
@@ -2698,10 +2703,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
dotenv@16.6.1:
|
|
||||||
resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
|
|
||||||
engines: {node: '>=12'}
|
|
||||||
|
|
||||||
dotenv@17.2.3:
|
dotenv@17.2.3:
|
||||||
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -3140,6 +3141,7 @@ packages:
|
|||||||
glob@9.3.5:
|
glob@9.3.5:
|
||||||
resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
|
resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
|
deprecated: Old versions of glob 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
|
||||||
|
|
||||||
globals@14.0.0:
|
globals@14.0.0:
|
||||||
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
|
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
|
||||||
@@ -4989,6 +4991,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@changesets/types': 6.1.0
|
'@changesets/types': 6.1.0
|
||||||
|
|
||||||
|
'@changesets/changelog-github@1.0.0-next.6':
|
||||||
|
dependencies:
|
||||||
|
'@changesets/get-github-info': 1.0.0-next.4
|
||||||
|
'@changesets/types': 7.0.0-next.7
|
||||||
|
|
||||||
'@changesets/cli@2.29.8(@types/node@24.10.9)':
|
'@changesets/cli@2.29.8(@types/node@24.10.9)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@changesets/apply-release-plan': 7.0.14
|
'@changesets/apply-release-plan': 7.0.14
|
||||||
@@ -5043,12 +5050,9 @@ snapshots:
|
|||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
semver: 7.7.3
|
semver: 7.7.3
|
||||||
|
|
||||||
'@changesets/get-github-info@0.6.0':
|
'@changesets/get-github-info@1.0.0-next.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
dataloader: 1.4.0
|
dataloader: 2.2.3
|
||||||
node-fetch: 2.7.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- encoding
|
|
||||||
|
|
||||||
'@changesets/get-release-plan@4.0.14':
|
'@changesets/get-release-plan@4.0.14':
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5104,6 +5108,8 @@ snapshots:
|
|||||||
|
|
||||||
'@changesets/types@6.1.0': {}
|
'@changesets/types@6.1.0': {}
|
||||||
|
|
||||||
|
'@changesets/types@7.0.0-next.7': {}
|
||||||
|
|
||||||
'@changesets/write@0.4.0':
|
'@changesets/write@0.4.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@changesets/types': 6.1.0
|
'@changesets/types': 6.1.0
|
||||||
@@ -6280,13 +6286,6 @@ snapshots:
|
|||||||
vite: 7.3.1(@types/node@24.10.9)(yaml@2.9.0)
|
vite: 7.3.1(@types/node@24.10.9)(yaml@2.9.0)
|
||||||
vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.9)(yaml@2.9.0))
|
vitefu: 1.1.1(vite@7.3.1(@types/node@24.10.9)(yaml@2.9.0))
|
||||||
|
|
||||||
'@svitejs/changesets-changelog-github-compact@1.2.0':
|
|
||||||
dependencies:
|
|
||||||
'@changesets/get-github-info': 0.6.0
|
|
||||||
dotenv: 16.6.1
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- encoding
|
|
||||||
|
|
||||||
'@tmcp/adapter-valibot@0.1.5(tmcp@1.19.3(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3))':
|
'@tmcp/adapter-valibot@0.1.5(tmcp@1.19.3(typescript@5.9.3))(valibot@1.2.0(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/spec': 1.1.0
|
'@standard-schema/spec': 1.1.0
|
||||||
@@ -6868,7 +6867,7 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
is-data-view: 1.0.2
|
is-data-view: 1.0.2
|
||||||
|
|
||||||
dataloader@1.4.0: {}
|
dataloader@2.2.3: {}
|
||||||
|
|
||||||
debug@3.2.7:
|
debug@3.2.7:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -6929,8 +6928,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
||||||
dotenv@16.6.1: {}
|
|
||||||
|
|
||||||
dotenv@17.2.3: {}
|
dotenv@17.2.3: {}
|
||||||
|
|
||||||
dts-resolver@2.1.3: {}
|
dts-resolver@2.1.3: {}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ catalogs:
|
|||||||
'@tmcp/transport-stdio': ^0.4.2
|
'@tmcp/transport-stdio': ^0.4.2
|
||||||
tmcp: ^1.19.3
|
tmcp: ^1.19.3
|
||||||
tooling:
|
tooling:
|
||||||
|
'@changesets/changelog-github': 1.0.0-next.6
|
||||||
'@changesets/cli': ^2.29.7
|
'@changesets/cli': ^2.29.7
|
||||||
'@svitejs/changesets-changelog-github-compact': ^1.2.0
|
|
||||||
'@types/estree': ^1.0.8
|
'@types/estree': ^1.0.8
|
||||||
'@types/node': ^24.3.1
|
'@types/node': ^24.3.1
|
||||||
'@valibot/to-json-schema': ^1.5.0
|
'@valibot/to-json-schema': ^1.5.0
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function parse_agent_md(content: string, file_path: string): AgentData | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate agents.ts module from tools/agents/*.md files
|
* Generate agents.js module from tools/agents/*.md files
|
||||||
*/
|
*/
|
||||||
async function sync_agents() {
|
async function sync_agents() {
|
||||||
const agents_dir = path.join(TOOLS_DIR, 'agents');
|
const agents_dir = path.join(TOOLS_DIR, 'agents');
|
||||||
@@ -96,14 +96,14 @@ async function sync_agents() {
|
|||||||
),
|
),
|
||||||
null,
|
null,
|
||||||
'\t',
|
'\t',
|
||||||
)} as const;`,
|
)};`,
|
||||||
'',
|
'',
|
||||||
].join('\n');
|
].join('\n');
|
||||||
|
|
||||||
const dest = path.join(OPENCODE_PKG_DIR, 'agents.ts');
|
const dest = path.join(OPENCODE_PKG_DIR, 'agents.js');
|
||||||
await fs.writeFile(dest, output);
|
await fs.writeFile(dest, output);
|
||||||
|
|
||||||
console.log(`Generated agents.ts with ${agents.length} agent(s)`);
|
console.log(`Generated agents.js with ${agents.length} agent(s)`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await sync_skills();
|
await sync_skills();
|
||||||
|
|||||||
Reference in New Issue
Block a user