mirror of
https://github.com/sveltejs/ai-tools.git
synced 2026-08-03 09:04:16 +08:00
Compare commits
1 Commits
@sveltejs/
...
quotemarks
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18c183babb |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
|
||||
"changelog": ["@changesets/changelog-github", { "repo": "sveltejs/ai-tools", "template": "\n- {summary} {ref}" }],
|
||||
"changelog": ["@svitejs/changesets-changelog-github-compact", { "repo": "sveltejs/ai-tools" }],
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
|
||||
@@ -5,7 +5,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'packages/opencode/config.js'
|
||||
- 'packages/opencode/config.ts'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
## Summary
|
||||
Automatically generated update for OpenCode JSON schema.
|
||||
|
||||
This PR was triggered by changes to the OpenCode configuration file `packages/opencode/config.js`.
|
||||
This PR was triggered by changes to the OpenCode configuration file `packages/opencode/config.ts`.
|
||||
|
||||
## Changes
|
||||
- Updated `packages/opencode/schema.json` with latest JSON schema
|
||||
|
||||
@@ -43,12 +43,12 @@
|
||||
],
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@changesets/changelog-github": "catalog:tooling",
|
||||
"@changesets/cli": "catalog:tooling",
|
||||
"@eslint/compat": "catalog:lint",
|
||||
"@eslint/js": "catalog:lint",
|
||||
"@modelcontextprotocol/inspector": "catalog:ai",
|
||||
"@sveltejs/adapter-vercel": "catalog:svelte",
|
||||
"@svitejs/changesets-changelog-github-compact": "catalog:tooling",
|
||||
"eslint": "catalog:lint",
|
||||
"eslint-config-prettier": "catalog:lint",
|
||||
"eslint-plugin-import": "catalog:lint",
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
# @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
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -8,4 +8,4 @@ export const agents = {
|
||||
prompt:
|
||||
"You are a Svelte 5 expert responsible for writing, editing, and validating Svelte components and modules. You have access to the Svelte MCP server which provides documentation and code analysis tools. Always use the tools from the svelte MCP server to fetch documentation with `get_documentation` and validating the code with `svelte_autofixer`. If the autofixer returns any issue or suggestions try to solve them.\n\nIf the MCP tools are not available you can use the `svelte-code-writer` skill to learn how to use the `@sveltejs/mcp` cli to access the same tools.\n\nIf the skill is not available you can run `npx @sveltejs/mcp@latest -y --help` to learn how to use it.\n\n## Available MCP Tools\n\n### 1. list-sections\n\nLists all available Svelte 5 and SvelteKit documentation sections with titles and paths. Use this first to discover what documentation is available.\n\n### 2. get-documentation\n\nRetrieves full documentation for specified sections. Accepts a single section name or an array of section names. Use after `list-sections` to fetch relevant docs for the task at hand.\n\n**Example sections:** `$state`, `$derived`, `$effect`, `$props`, `$bindable`, `snippets`, `routing`, `load functions`\n\n### 3. svelte-autofixer\n\nAnalyzes Svelte code and returns suggestions to fix issues. Pass the component code directly to this tool. It will detect common mistakes like:\n\n- Using `$effect` instead of `$derived` for computations\n- Missing cleanup in effects\n- Svelte 4 syntax (`on:click`, `export let`, `<slot>`)\n- Missing keys in `{#each}` blocks\n- And more\n\n## Workflow\n\nWhen invoked to work on a Svelte file:\n\n### 1. Gather Context (if needed)\n\nIf you're uncertain about Svelte 5 syntax or patterns, use the MCP tools:\n\n1. Call `list-sections` to see available documentation\n2. Call `get-documentation` with relevant section names\n\n### 2. Read the Target File\n\nRead the file to understand the current implementation.\n\n### 3. Make Changes\n\nApply edits following Svelte 5 best practices:\n\n### 4. Validate Changes\n\nAfter editing, ALWAYS call `svelte-autofixer` with the updated code to check for issues.\n\n### 5. Fix Any Issues\n\nIf the autofixer reports problems, fix them and re-validate until no issues remain.\n\n## Output Format\n\nAfter completing your work, provide:\n\n1. Summary of changes made\n2. Any issues found and fixed by the autofixer\n3. Recommendations for further improvements (if any)",
|
||||
},
|
||||
};
|
||||
} as const;
|
||||
@@ -1,10 +1,9 @@
|
||||
import type { PluginInput } from '@opencode-ai/plugin';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { homedir } from 'os';
|
||||
import { join } from 'path';
|
||||
import * as v from 'valibot';
|
||||
|
||||
/** @typedef {import('@opencode-ai/plugin').PluginInput} PluginInput */
|
||||
|
||||
// Schema for individual agent configuration
|
||||
const agent_config_schema = v.object({
|
||||
model: v.pipe(
|
||||
@@ -29,18 +28,18 @@ const agent_config_schema = v.object({
|
||||
|
||||
const default_config = {
|
||||
mcp: {
|
||||
type: /** @type {'remote' | 'local'} */ ('remote'),
|
||||
type: 'remote' as 'remote' | 'local',
|
||||
enabled: true,
|
||||
},
|
||||
subagent: {
|
||||
enabled: true,
|
||||
agents: /** @type {Record<string, v.InferInput<typeof agent_config_schema>>} */ ({}),
|
||||
agents: {} as Record<string, v.InferInput<typeof agent_config_schema>>,
|
||||
},
|
||||
instructions: {
|
||||
enabled: true,
|
||||
},
|
||||
skills: {
|
||||
enabled: /** @type {boolean | string[]} */ (true),
|
||||
enabled: true as boolean | string[],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -92,24 +91,25 @@ export const config_schema = v.object({
|
||||
),
|
||||
});
|
||||
|
||||
/** @typedef {v.InferInput<typeof config_schema>} McpConfig */
|
||||
export type McpConfig = v.InferInput<typeof config_schema>;
|
||||
|
||||
const GLOBAL_CONFIG_DIR = join(homedir(), '.config', 'opencode');
|
||||
const GLOBAL_CONFIG_PATH = join(GLOBAL_CONFIG_DIR, 'svelte.json');
|
||||
|
||||
/** @typedef {{ data: Record<string, unknown> | null, parse_error?: string }} ConfigLoadResult */
|
||||
interface ConfigLoadResult {
|
||||
data: Record<string, unknown> | null;
|
||||
parse_error?: string;
|
||||
}
|
||||
|
||||
function get_config_paths() {
|
||||
// Global: ~/.config/opencode/svelte.json
|
||||
/** @type {string | null} */
|
||||
let global_path = null;
|
||||
let global_path: string | null = null;
|
||||
if (existsSync(GLOBAL_CONFIG_PATH)) {
|
||||
global_path = GLOBAL_CONFIG_PATH;
|
||||
}
|
||||
|
||||
// Custom config directory: $OPENCODE_CONFIG_DIR/svelte.json
|
||||
/** @type {string | null} */
|
||||
let config_dir_path = null;
|
||||
let config_dir_path: string | null = null;
|
||||
const opencode_config_dir = process.env.OPENCODE_CONFIG_DIR;
|
||||
if (opencode_config_dir) {
|
||||
const config_json = join(opencode_config_dir, 'svelte.json');
|
||||
@@ -119,8 +119,7 @@ function get_config_paths() {
|
||||
}
|
||||
|
||||
// Project-local: ./.opencode/svelte.json (cwd)
|
||||
/** @type {string | null} */
|
||||
let project_path = null;
|
||||
let project_path: string | null = null;
|
||||
const project_config = join(process.cwd(), '.opencode', 'svelte.json');
|
||||
if (existsSync(project_config)) {
|
||||
project_path = project_config;
|
||||
@@ -130,13 +129,8 @@ function get_config_paths() {
|
||||
return [global_path, config_dir_path, project_path];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} config_path
|
||||
* @returns {ConfigLoadResult}
|
||||
*/
|
||||
function load_config_file(config_path) {
|
||||
/** @type {string} */
|
||||
let file_content;
|
||||
function load_config_file(config_path: string): ConfigLoadResult {
|
||||
let file_content: string;
|
||||
try {
|
||||
file_content = readFileSync(config_path, 'utf-8');
|
||||
} catch {
|
||||
@@ -150,7 +144,7 @@ function load_config_file(config_path) {
|
||||
return { data: null, parse_error: 'Config file is empty or invalid' };
|
||||
}
|
||||
return { data: parsed };
|
||||
} catch (error) {
|
||||
} catch (error: unknown) {
|
||||
return {
|
||||
data: null,
|
||||
parse_error: error instanceof Error ? error.message : 'Failed to parse config',
|
||||
@@ -158,11 +152,7 @@ function load_config_file(config_path) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Partial<McpConfig>} user_config
|
||||
* @returns {McpConfig}
|
||||
*/
|
||||
function merge_with_defaults(user_config) {
|
||||
function merge_with_defaults(user_config: Partial<McpConfig>): McpConfig {
|
||||
return {
|
||||
mcp: {
|
||||
...default_config.mcp,
|
||||
@@ -187,11 +177,9 @@ function merge_with_defaults(user_config) {
|
||||
};
|
||||
}
|
||||
|
||||
/** @param {PluginInput} ctx */
|
||||
export function get_mcp_config(ctx) {
|
||||
export function get_mcp_config(ctx: PluginInput) {
|
||||
const config_paths = get_config_paths();
|
||||
/** @type {Partial<McpConfig>} */
|
||||
let merged = {};
|
||||
let merged: Partial<McpConfig> = {};
|
||||
|
||||
// Iterate from lowest to highest priority, merging as we go
|
||||
for (const path of config_paths) {
|
||||
@@ -1,18 +1,13 @@
|
||||
import type { Plugin } from '@opencode-ai/plugin';
|
||||
import { readdir } from 'node:fs/promises';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { agents } from './agents.js';
|
||||
import { get_mcp_config } from './config.js';
|
||||
|
||||
/** @typedef {import('@opencode-ai/plugin').Plugin} Plugin */
|
||||
import { agents } from './agents.ts';
|
||||
import { get_mcp_config } from './config.ts';
|
||||
|
||||
const current_dir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/**
|
||||
* @param {Parameters<Plugin>[0]} ctx
|
||||
* @returns {ReturnType<Plugin>}
|
||||
*/
|
||||
export async function svelte_plugin(ctx) {
|
||||
export const svelte_plugin: Plugin = async (ctx) => {
|
||||
return {
|
||||
async config(input) {
|
||||
input.agent ??= {};
|
||||
@@ -29,7 +24,8 @@ export async function svelte_plugin(ctx) {
|
||||
const mcp = input.mcp[name];
|
||||
if (
|
||||
(mcp?.type === 'remote' && mcp.url.includes('https://mcp.svelte.dev/mcp')) ||
|
||||
(mcp?.type === 'local' && mcp.command.some((cmd) => cmd.includes('@sveltejs/mcp')))
|
||||
(mcp?.type === 'local' &&
|
||||
mcp.command.some((cmd: string) => cmd.includes('@sveltejs/mcp')))
|
||||
) {
|
||||
// if we found the svelte MCP server, we store its name and break
|
||||
svelte_mcp_name = name;
|
||||
@@ -79,8 +75,7 @@ export async function svelte_plugin(ctx) {
|
||||
if (mcp_config.subagent?.enabled !== false) {
|
||||
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
|
||||
/** @type {(typeof input.agent)[string]} */
|
||||
const default_config = {
|
||||
const default_config: (typeof input.agent)[string] = {
|
||||
color: '#ff3e00',
|
||||
mode: 'subagent',
|
||||
prompt: agent_data.prompt,
|
||||
@@ -114,4 +109,4 @@ export async function svelte_plugin(ctx) {
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@sveltejs/opencode",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.10",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/sveltejs/ai-tools#readme",
|
||||
@@ -9,24 +9,24 @@
|
||||
},
|
||||
"scripts": {
|
||||
"check": "tsc --noEmit",
|
||||
"generate-schema": "node scripts/generate-schema.js"
|
||||
"generate-schema": "node --import node-resolve-ts/register scripts/generate-schema.ts"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"config.js",
|
||||
"tui.jsx",
|
||||
"agents.js",
|
||||
"index.ts",
|
||||
"config.ts",
|
||||
"tui.tsx",
|
||||
"agents.ts",
|
||||
"instructions",
|
||||
"skills"
|
||||
],
|
||||
"exports": {
|
||||
"./server": {
|
||||
"types": "./index.js",
|
||||
"import": "./index.js"
|
||||
"types": "./index.ts",
|
||||
"import": "./index.ts"
|
||||
},
|
||||
"./tui": {
|
||||
"types": "./tui.jsx",
|
||||
"import": "./tui.jsx"
|
||||
"types": "./tui.tsx",
|
||||
"import": "./tui.tsx"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -4,8 +4,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
// Read agent names from tools/agents/*.md files
|
||||
/** @param {string} agents_dir */
|
||||
function get_agent_names(agents_dir) {
|
||||
function get_agent_names(agents_dir: string) {
|
||||
if (!fs.existsSync(agents_dir)) return [];
|
||||
return fs
|
||||
.readdirSync(agents_dir, { withFileTypes: true })
|
||||
@@ -13,8 +12,7 @@ function get_agent_names(agents_dir) {
|
||||
.map((entry) => entry.name.replace(/\.md$/, ''));
|
||||
}
|
||||
|
||||
/** @param {string} skills_dir */
|
||||
function get_skill_names(skills_dir) {
|
||||
function get_skill_names(skills_dir: string) {
|
||||
if (!fs.existsSync(skills_dir)) return [];
|
||||
return fs
|
||||
.readdirSync(skills_dir, { withFileTypes: true })
|
||||
@@ -31,13 +29,10 @@ const json_schema = toJsonSchema(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) {
|
||||
const enabled = /** @type {any} */ (json_schema).properties?.skills?.properties?.enabled;
|
||||
// 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(
|
||||
/** @type {(schema: Record<string, unknown>) => boolean} */ (
|
||||
(schema) => schema.type === 'array'
|
||||
),
|
||||
);
|
||||
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' }],
|
||||
@@ -53,7 +48,8 @@ const agents_dir = path.resolve('../../tools/agents');
|
||||
const agent_names = get_agent_names(agents_dir);
|
||||
|
||||
if (agent_names.length > 0) {
|
||||
const agents = /** @type {any} */ (json_schema).properties?.subagent?.properties?.agents;
|
||||
// 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' }],
|
||||
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowImportingTsExtensions": true,
|
||||
"jsx": "preserve",
|
||||
"jsxImportSource": "@opentui/solid",
|
||||
"types": ["@types/node"]
|
||||
},
|
||||
"include": ["index.js", "config.js", "agents.js", "tui.jsx", "scripts/*"],
|
||||
"include": ["index.ts", "config.ts", "agents.ts", "tui.tsx", "scripts/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
/** @jsxImportSource @opentui/solid */
|
||||
import type { TuiPlugin, TuiPluginModule } from '@opencode-ai/plugin/tui';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||
import { homedir } from 'node:os';
|
||||
import { dirname, join } from 'node:path';
|
||||
import * as v from 'valibot';
|
||||
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 */
|
||||
import { config_schema, type McpConfig } from './config.ts';
|
||||
|
||||
const plugin_id = 'svelte.configure';
|
||||
const skill_names = ['svelte-code-writer', 'svelte-core-bestpractices'];
|
||||
const skill_names = ['svelte-code-writer', 'svelte-core-bestpractices'] as const;
|
||||
const agent_name = 'svelte-file-editor';
|
||||
|
||||
/** @param {TuiPluginApi} api */
|
||||
function project_root(api) {
|
||||
type Scope = 'project' | 'global';
|
||||
type Config = Partial<McpConfig>;
|
||||
|
||||
function project_root(api: Parameters<TuiPlugin>[0]) {
|
||||
const worktree = api.state.path.worktree;
|
||||
return worktree && worktree !== '/' ? worktree : api.state.path.directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TuiPluginApi} api
|
||||
* @param {Scope} scope
|
||||
*/
|
||||
function config_path(api, scope) {
|
||||
function config_path(api: Parameters<TuiPlugin>[0], scope: Scope) {
|
||||
if (scope === 'project') return join(project_root(api), '.opencode', 'svelte.json');
|
||||
return join(
|
||||
process.env.OPENCODE_CONFIG_DIR ?? join(homedir(), '.config', 'opencode'),
|
||||
@@ -35,40 +27,26 @@ function config_path(api, scope) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {Promise<Config>}
|
||||
*/
|
||||
async function read_config(path) {
|
||||
async function read_config(path: string): Promise<Config> {
|
||||
if (!existsSync(path)) return {};
|
||||
/** @type {unknown} */
|
||||
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
||||
const parsed: unknown = JSON.parse(await readFile(path, 'utf8'));
|
||||
const result = v.safeParse(config_schema, parsed);
|
||||
if (!result.success)
|
||||
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.
|
||||
return /** @type {Config} */ (parsed);
|
||||
return parsed as Config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @param {Config} config
|
||||
*/
|
||||
async function save_config(path, config) {
|
||||
async function save_config(path: string, config: Config) {
|
||||
await mkdir(dirname(path), { recursive: true });
|
||||
await writeFile(path, `${JSON.stringify(config, null, '\t')}\n`, 'utf8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {unknown} value
|
||||
* @param {string} [fallback]
|
||||
*/
|
||||
function display(value, fallback = 'default') {
|
||||
function display(value: unknown, fallback = 'default') {
|
||||
return value === undefined ? fallback : String(value);
|
||||
}
|
||||
|
||||
/** @type {TuiPlugin} */
|
||||
const tui = async (api) => {
|
||||
const tui: TuiPlugin = async (api) => {
|
||||
function open_scope() {
|
||||
if (!api.state.path.directory) {
|
||||
api.ui.toast({
|
||||
@@ -79,7 +57,7 @@ const tui = async (api) => {
|
||||
}
|
||||
|
||||
api.ui.dialog.replace(() => (
|
||||
<api.ui.DialogSelect
|
||||
<api.ui.DialogSelect<Scope>
|
||||
title="Configure Svelte plugin"
|
||||
options={[
|
||||
{
|
||||
@@ -93,16 +71,14 @@ const tui = async (api) => {
|
||||
description: 'Write svelte.json in the OpenCode config directory',
|
||||
},
|
||||
]}
|
||||
onSelect={(option) => void open_config(/** @type {Scope} */ (option.value))}
|
||||
onSelect={(option) => void open_config(option.value)}
|
||||
/>
|
||||
));
|
||||
}
|
||||
|
||||
/** @param {Scope} scope */
|
||||
async function open_config(scope) {
|
||||
async function open_config(scope: Scope) {
|
||||
const path = config_path(api, scope);
|
||||
/** @type {Config} */
|
||||
let config;
|
||||
let config: Config;
|
||||
try {
|
||||
config = await read_config(path);
|
||||
} catch (error) {
|
||||
@@ -114,8 +90,7 @@ const tui = async (api) => {
|
||||
return;
|
||||
}
|
||||
const original_config = structuredClone(config);
|
||||
/** @type {string | undefined} */
|
||||
let current_option;
|
||||
let current_option: string | undefined;
|
||||
|
||||
async function persist(show_toast = true) {
|
||||
try {
|
||||
@@ -127,11 +102,7 @@ const tui = async (api) => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {'temperature' | 'top_p' | 'maxSteps'} key
|
||||
* @param {string} label
|
||||
*/
|
||||
function prompt_agent_number(key, label) {
|
||||
function prompt_agent_number(key: 'temperature' | 'top_p' | 'maxSteps', label: string) {
|
||||
const agent = config.subagent?.agents?.[agent_name];
|
||||
api.ui.dialog.replace(() => (
|
||||
<api.ui.DialogPrompt
|
||||
@@ -158,7 +129,7 @@ const tui = async (api) => {
|
||||
function open_agent() {
|
||||
const agent = config.subagent?.agents?.[agent_name];
|
||||
api.ui.dialog.replace(() => (
|
||||
<api.ui.DialogSelect
|
||||
<api.ui.DialogSelect<string>
|
||||
title={`Configure ${agent_name}`}
|
||||
options={[
|
||||
{ title: 'Model', value: 'model', description: display(agent?.model) },
|
||||
@@ -173,12 +144,11 @@ const tui = async (api) => {
|
||||
]}
|
||||
onSelect={(option) => {
|
||||
if (option.value === 'back') return open_menu();
|
||||
if (
|
||||
option.value === 'temperature' ||
|
||||
option.value === 'top_p' ||
|
||||
option.value === 'maxSteps'
|
||||
)
|
||||
return prompt_agent_number(option.value, option.title);
|
||||
if (option.value !== 'model')
|
||||
return prompt_agent_number(
|
||||
option.value as 'temperature' | 'top_p' | 'maxSteps',
|
||||
option.title,
|
||||
);
|
||||
api.ui.dialog.replace(() => (
|
||||
<api.ui.DialogPrompt
|
||||
title={`${agent_name}: model`}
|
||||
@@ -208,16 +178,14 @@ const tui = async (api) => {
|
||||
Array.isArray(skills) ? skills : skills === false ? [] : skill_names,
|
||||
);
|
||||
const all_skills_selected = skill_names.every((name) => selected_skills.has(name));
|
||||
/** @param {boolean | undefined} value */
|
||||
function checked(value) {
|
||||
function checked(value: boolean | undefined) {
|
||||
return value !== false ? '[x]' : '[ ]';
|
||||
}
|
||||
/** @param {'remote' | 'local'} value */
|
||||
function radio(value) {
|
||||
function radio(value: 'remote' | 'local') {
|
||||
return (config.mcp?.type ?? 'remote') === value ? '(*)' : '( )';
|
||||
}
|
||||
api.ui.dialog.replace(() => (
|
||||
<api.ui.DialogSelect
|
||||
<api.ui.DialogSelect<string>
|
||||
title={`Svelte plugin (${scope})`}
|
||||
{...(current_option === undefined ? {} : { current: current_option })}
|
||||
skipFilter
|
||||
@@ -317,7 +285,7 @@ const tui = async (api) => {
|
||||
});
|
||||
};
|
||||
|
||||
export default /** @satisfies {TuiPluginModule & { id: string }} */ ({
|
||||
export default {
|
||||
id: plugin_id,
|
||||
tui,
|
||||
});
|
||||
} satisfies TuiPluginModule & { id: string };
|
||||
63
pnpm-lock.yaml
generated
63
pnpm-lock.yaml
generated
@@ -107,12 +107,12 @@ catalogs:
|
||||
specifier: ^1.19.3
|
||||
version: 1.19.3
|
||||
tooling:
|
||||
'@changesets/changelog-github':
|
||||
specifier: 1.0.0-next.6
|
||||
version: 1.0.0-next.6
|
||||
'@changesets/cli':
|
||||
specifier: ^2.29.7
|
||||
version: 2.29.8
|
||||
'@svitejs/changesets-changelog-github-compact':
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0
|
||||
'@types/estree':
|
||||
specifier: ^1.0.8
|
||||
version: 1.0.8
|
||||
@@ -166,9 +166,6 @@ importers:
|
||||
|
||||
.:
|
||||
devDependencies:
|
||||
'@changesets/changelog-github':
|
||||
specifier: catalog:tooling
|
||||
version: 1.0.0-next.6
|
||||
'@changesets/cli':
|
||||
specifier: catalog:tooling
|
||||
version: 2.29.8(@types/node@24.10.9)
|
||||
@@ -184,6 +181,9 @@ importers:
|
||||
'@sveltejs/adapter-vercel':
|
||||
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)
|
||||
'@svitejs/changesets-changelog-github-compact':
|
||||
specifier: catalog:tooling
|
||||
version: 1.2.0
|
||||
eslint:
|
||||
specifier: catalog:lint
|
||||
version: 9.39.2
|
||||
@@ -605,10 +605,6 @@ packages:
|
||||
'@changesets/changelog-git@0.2.1':
|
||||
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':
|
||||
resolution: {integrity: sha512-1weuGZpP63YWUYjay/E84qqwcnt5yJMM0tep10Up7Q5cS/DGe2IZ0Uj3HNMxGhCINZuR7aO9WBMdKnPit5ZDPA==}
|
||||
hasBin: true
|
||||
@@ -622,9 +618,8 @@ packages:
|
||||
'@changesets/get-dependents-graph@2.1.3':
|
||||
resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==}
|
||||
|
||||
'@changesets/get-github-info@1.0.0-next.4':
|
||||
resolution: {integrity: sha512-Bosh+XOoFvLMzAj301tg6phbrEggBtvEccrnceEvYsKSM7PjcIa32Fy22SU5g+501HZywkdwcAlybdWF+e/zzw==}
|
||||
engines: {node: ^22.11 || ^24 || >=26}
|
||||
'@changesets/get-github-info@0.6.0':
|
||||
resolution: {integrity: sha512-v/TSnFVXI8vzX9/w3DU2Ol+UlTZcu3m0kXTjTT4KlAdwSvwutcByYwyYn9hwerPWfPkT2JfpoX0KgvCEi8Q/SA==}
|
||||
|
||||
'@changesets/get-release-plan@4.0.14':
|
||||
resolution: {integrity: sha512-yjZMHpUHgl4Xl5gRlolVuxDkm4HgSJqT93Ri1Uz8kGrQb+5iJ8dkXJ20M2j/Y4iV5QzS2c5SeTxVSKX+2eMI0g==}
|
||||
@@ -656,10 +651,6 @@ packages:
|
||||
'@changesets/types@6.1.0':
|
||||
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':
|
||||
resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==}
|
||||
|
||||
@@ -2062,6 +2053,10 @@ packages:
|
||||
svelte: ^5.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':
|
||||
resolution: {integrity: sha512-9P2wrVYPngemNK0UvPb/opC722/jfd09QxXmme1TRp/wPsl98vpSk/MXt24BCMqBRv4Dvs0xxJH4KHDcjXW52Q==}
|
||||
peerDependencies:
|
||||
@@ -2616,8 +2611,8 @@ packages:
|
||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
dataloader@2.2.3:
|
||||
resolution: {integrity: sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==}
|
||||
dataloader@1.4.0:
|
||||
resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==}
|
||||
|
||||
debug@3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
@@ -2703,6 +2698,10 @@ packages:
|
||||
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
dotenv@16.6.1:
|
||||
resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
dotenv@17.2.3:
|
||||
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -3141,7 +3140,6 @@ packages:
|
||||
glob@9.3.5:
|
||||
resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
|
||||
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:
|
||||
resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==}
|
||||
@@ -4991,11 +4989,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@changesets/apply-release-plan': 7.0.14
|
||||
@@ -5050,9 +5043,12 @@ snapshots:
|
||||
picocolors: 1.1.1
|
||||
semver: 7.7.3
|
||||
|
||||
'@changesets/get-github-info@1.0.0-next.4':
|
||||
'@changesets/get-github-info@0.6.0':
|
||||
dependencies:
|
||||
dataloader: 2.2.3
|
||||
dataloader: 1.4.0
|
||||
node-fetch: 2.7.0
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
'@changesets/get-release-plan@4.0.14':
|
||||
dependencies:
|
||||
@@ -5108,8 +5104,6 @@ snapshots:
|
||||
|
||||
'@changesets/types@6.1.0': {}
|
||||
|
||||
'@changesets/types@7.0.0-next.7': {}
|
||||
|
||||
'@changesets/write@0.4.0':
|
||||
dependencies:
|
||||
'@changesets/types': 6.1.0
|
||||
@@ -6286,6 +6280,13 @@ snapshots:
|
||||
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))':
|
||||
dependencies:
|
||||
'@standard-schema/spec': 1.1.0
|
||||
@@ -6867,7 +6868,7 @@ snapshots:
|
||||
es-errors: 1.3.0
|
||||
is-data-view: 1.0.2
|
||||
|
||||
dataloader@2.2.3: {}
|
||||
dataloader@1.4.0: {}
|
||||
|
||||
debug@3.2.7:
|
||||
dependencies:
|
||||
@@ -6928,6 +6929,8 @@ snapshots:
|
||||
dependencies:
|
||||
esutils: 2.0.3
|
||||
|
||||
dotenv@16.6.1: {}
|
||||
|
||||
dotenv@17.2.3: {}
|
||||
|
||||
dts-resolver@2.1.3: {}
|
||||
|
||||
@@ -42,8 +42,8 @@ catalogs:
|
||||
'@tmcp/transport-stdio': ^0.4.2
|
||||
tmcp: ^1.19.3
|
||||
tooling:
|
||||
'@changesets/changelog-github': 1.0.0-next.6
|
||||
'@changesets/cli': ^2.29.7
|
||||
'@svitejs/changesets-changelog-github-compact': ^1.2.0
|
||||
'@types/estree': ^1.0.8
|
||||
'@types/node': ^24.3.1
|
||||
'@valibot/to-json-schema': ^1.5.0
|
||||
|
||||
@@ -68,7 +68,7 @@ function parse_agent_md(content: string, file_path: string): AgentData | null {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate agents.js module from tools/agents/*.md files
|
||||
* Generate agents.ts module from tools/agents/*.md files
|
||||
*/
|
||||
async function sync_agents() {
|
||||
const agents_dir = path.join(TOOLS_DIR, 'agents');
|
||||
@@ -96,14 +96,14 @@ async function sync_agents() {
|
||||
),
|
||||
null,
|
||||
'\t',
|
||||
)};`,
|
||||
)} as const;`,
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
const dest = path.join(OPENCODE_PKG_DIR, 'agents.js');
|
||||
const dest = path.join(OPENCODE_PKG_DIR, 'agents.ts');
|
||||
await fs.writeFile(dest, output);
|
||||
|
||||
console.log(`Generated agents.js with ${agents.length} agent(s)`);
|
||||
console.log(`Generated agents.ts with ${agents.length} agent(s)`);
|
||||
}
|
||||
|
||||
await sync_skills();
|
||||
|
||||
Reference in New Issue
Block a user