opencode-dynamic-skills 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -18
- package/README.zh-CN.md +41 -18
- package/dist/api.d.ts +5 -4
- package/dist/commands/MirroredSkillCommand.d.ts +15 -0
- package/dist/commands/MirroredSkillCommand.test.d.ts +1 -0
- package/dist/commands/SlashCommand.d.ts +2 -1
- package/dist/config.d.ts +24 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1014 -560
- package/dist/lib/SkillFs.d.ts +1 -0
- package/dist/lib/formatLoadedSkill.d.ts +1 -1
- package/dist/lib/formatLoadedSkill.test.d.ts +1 -0
- package/dist/services/Notifier.d.ts +13 -0
- package/dist/services/Notifier.test.d.ts +1 -0
- package/dist/services/TuiCommandMirror.d.ts +15 -0
- package/dist/services/TuiCommandMirror.test.d.ts +1 -0
- package/dist/tools/SkillRecommender.d.ts +25 -8
- package/dist/types.d.ts +22 -19
- package/package.json +1 -1
- package/dist/lib/createPromptRenderer.d.ts +0 -52
- package/dist/lib/createPromptRenderer.test.d.ts +0 -9
- package/dist/lib/getModelFormat.d.ts +0 -35
- package/dist/lib/renderers/JsonPromptRenderer.d.ts +0 -8
- package/dist/lib/renderers/JsonPromptRenderer.test.d.ts +0 -10
- package/dist/lib/renderers/MdPromptRenderer.d.ts +0 -18
- package/dist/lib/renderers/MdPromptRenderer.test.d.ts +0 -11
- package/dist/services/MessageModelIdAccountant.d.ts +0 -22
package/README.md
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
# OpenCode Dynamic Skills
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/opencode-dynamic-skills)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](https://bun.sh/)
|
|
6
|
+
[](https://opencode.ai/)
|
|
7
|
+
|
|
3
8
|
[中文文档](./README.zh-CN.md)
|
|
4
9
|
|
|
5
10
|
OpenCode plugin focused on three things:
|
|
6
11
|
|
|
7
12
|
1. Dynamic skill loading
|
|
8
13
|
2. Slash-style skill usage
|
|
9
|
-
3. Skill-root-relative file references
|
|
10
|
-
|
|
11
|
-
## Status
|
|
12
|
-
|
|
13
|
-
This project is a reboot of the archived `opencode-skillful` codebase.
|
|
14
|
-
|
|
15
|
-
- Package: `opencode-dynamic-skills`
|
|
16
|
-
- Version: `1.0.0`
|
|
17
|
-
- License: MIT
|
|
14
|
+
3. Skill-root-relative file references and file manifests
|
|
18
15
|
|
|
19
16
|
## Attribution
|
|
20
17
|
|
|
@@ -83,6 +80,15 @@ This does not mean OpenCode will show dynamic picker suggestions for those alias
|
|
|
83
80
|
|
|
84
81
|
### Skill-root-relative resources
|
|
85
82
|
|
|
83
|
+
When a skill is loaded, the plugin injects:
|
|
84
|
+
|
|
85
|
+
- the `SKILL.md` body
|
|
86
|
+
- the skill root path
|
|
87
|
+
- a complete root-relative file manifest for the skill directory, excluding `SKILL.md`
|
|
88
|
+
|
|
89
|
+
It does **not** inject every file's content by default.
|
|
90
|
+
Actual file contents stay lazy and are read on demand through `skill_resource`.
|
|
91
|
+
|
|
86
92
|
`skill_resource` now resolves paths from the skill root, for example:
|
|
87
93
|
|
|
88
94
|
```txt
|
|
@@ -112,18 +118,35 @@ Register the plugin in `opencode.json`:
|
|
|
112
118
|
|
|
113
119
|
## Configuration
|
|
114
120
|
|
|
121
|
+
On startup the plugin ensures a complete commented JSONC config exists at:
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
~/.config/opencode/opencode-dynamic-skills.config.jsonc
|
|
125
|
+
```
|
|
126
|
+
|
|
115
127
|
Example:
|
|
116
128
|
|
|
117
|
-
```
|
|
129
|
+
```jsonc
|
|
118
130
|
{
|
|
131
|
+
// Enable verbose plugin logs.
|
|
119
132
|
"debug": false,
|
|
120
|
-
"promptRenderer": "xml",
|
|
121
|
-
"modelRenderers": {
|
|
122
|
-
"claude-3-5-sonnet": "xml",
|
|
123
|
-
"gpt-4": "json"
|
|
124
|
-
},
|
|
125
133
|
"slashCommandName": "skill",
|
|
126
|
-
"enableSkillAliases": true
|
|
134
|
+
"enableSkillAliases": true,
|
|
135
|
+
"reservedSlashCommands": ["help", "model", "skills"],
|
|
136
|
+
"notifications": {
|
|
137
|
+
"enabled": false,
|
|
138
|
+
"success": true,
|
|
139
|
+
"errors": true,
|
|
140
|
+
},
|
|
141
|
+
"skillRecommend": {
|
|
142
|
+
"strategy": "heuristic",
|
|
143
|
+
"model": "openai/gpt-5.2",
|
|
144
|
+
"systemPrompt": "You are selecting the most relevant dynamic skills for a user request. Return strict JSON only with this shape: {\"recommendations\":[{\"name\":\"skill_tool_name\",\"reason\":\"why it matches\"}]}. Only recommend skills from the provided catalog. Prefer the smallest set of high-confidence matches.",
|
|
145
|
+
},
|
|
146
|
+
"tuiCommandMirror": {
|
|
147
|
+
"enabled": true,
|
|
148
|
+
"directory": "~/.config/opencode/commands",
|
|
149
|
+
},
|
|
127
150
|
}
|
|
128
151
|
```
|
|
129
152
|
|
|
@@ -131,10 +154,21 @@ Fields:
|
|
|
131
154
|
|
|
132
155
|
- `debug`
|
|
133
156
|
- `basePaths`
|
|
134
|
-
- `promptRenderer`
|
|
135
|
-
- `modelRenderers`
|
|
136
157
|
- `slashCommandName`
|
|
137
158
|
- `enableSkillAliases`
|
|
159
|
+
- `reservedSlashCommands`
|
|
160
|
+
- `notifications`
|
|
161
|
+
- `skillRecommend`
|
|
162
|
+
- `tuiCommandMirror`
|
|
163
|
+
|
|
164
|
+
`tuiCommandMirror` is enabled by default. The plugin mirrors dynamic skills into proxy command files so TUI slash autocomplete can surface `/<skill-name>` after an OpenCode restart.
|
|
165
|
+
|
|
166
|
+
Injected skill content now always uses a single XML renderer. The previous custom renderer selection feature was removed.
|
|
167
|
+
|
|
168
|
+
`skillRecommend.strategy` supports:
|
|
169
|
+
|
|
170
|
+
- `heuristic` (default): use the built-in ranker
|
|
171
|
+
- `model`: call an internal OpenCode session with the configured `provider/model` string
|
|
138
172
|
|
|
139
173
|
## Skill discovery
|
|
140
174
|
|
|
@@ -172,6 +206,7 @@ Rules:
|
|
|
172
206
|
- `name` must match the directory name
|
|
173
207
|
- `name` must satisfy OpenCode naming rules
|
|
174
208
|
- `description` is required
|
|
209
|
+
- non-`SKILL.md` files under the skill directory are indexed and exposed as an available file manifest
|
|
175
210
|
|
|
176
211
|
## Development
|
|
177
212
|
|
package/README.zh-CN.md
CHANGED
|
@@ -6,15 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
1. 动态加载 skill
|
|
8
8
|
2. 用 slash 方式使用 skill
|
|
9
|
-
3. 让 skill
|
|
10
|
-
|
|
11
|
-
## 当前状态
|
|
12
|
-
|
|
13
|
-
这是对已归档 `opencode-skillful` 仓库的重启版本。
|
|
14
|
-
|
|
15
|
-
- 包名:`opencode-dynamic-skills`
|
|
16
|
-
- 版本:`1.0.0`
|
|
17
|
-
- 协议:MIT
|
|
9
|
+
3. 让 skill 内文件引用与文件清单统一基于 skill 根目录
|
|
18
10
|
|
|
19
11
|
## 来源说明
|
|
20
12
|
|
|
@@ -83,6 +75,15 @@
|
|
|
83
75
|
|
|
84
76
|
### Skill 根目录相对资源
|
|
85
77
|
|
|
78
|
+
当一个 skill 被加载时,插件会注入:
|
|
79
|
+
|
|
80
|
+
- `SKILL.md` 正文
|
|
81
|
+
- skill 根目录路径
|
|
82
|
+
- 一份完整的 skill 根目录相对文件清单(不包含 `SKILL.md`)
|
|
83
|
+
|
|
84
|
+
它**不会**默认把所有文件内容都注入进上下文。
|
|
85
|
+
真正的文件内容仍然通过 `skill_resource` 按需读取。
|
|
86
|
+
|
|
86
87
|
`skill_resource` 现在按 skill 根目录解析路径,例如:
|
|
87
88
|
|
|
88
89
|
```txt
|
|
@@ -112,18 +113,31 @@ templates/pr.md
|
|
|
112
113
|
|
|
113
114
|
## 配置
|
|
114
115
|
|
|
116
|
+
插件启动时会确保在下面位置存在一份带英文注释的完整 JSONC 配置:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
~/.config/opencode/opencode-dynamic-skills.config.jsonc
|
|
120
|
+
```
|
|
121
|
+
|
|
115
122
|
示例:
|
|
116
123
|
|
|
117
|
-
```
|
|
124
|
+
```jsonc
|
|
118
125
|
{
|
|
126
|
+
// Enable verbose plugin logs.
|
|
119
127
|
"debug": false,
|
|
120
|
-
"promptRenderer": "xml",
|
|
121
|
-
"modelRenderers": {
|
|
122
|
-
"claude-3-5-sonnet": "xml",
|
|
123
|
-
"gpt-4": "json"
|
|
124
|
-
},
|
|
125
128
|
"slashCommandName": "skill",
|
|
126
|
-
"enableSkillAliases": true
|
|
129
|
+
"enableSkillAliases": true,
|
|
130
|
+
"reservedSlashCommands": ["help", "model", "skills"],
|
|
131
|
+
"notifications": {
|
|
132
|
+
"enabled": false,
|
|
133
|
+
"success": true,
|
|
134
|
+
"errors": true,
|
|
135
|
+
},
|
|
136
|
+
"skillRecommend": {
|
|
137
|
+
"strategy": "heuristic",
|
|
138
|
+
"model": "openai/gpt-5.2",
|
|
139
|
+
"systemPrompt": "You are selecting the most relevant dynamic skills for a user request. Return strict JSON only with this shape: {\"recommendations\":[{\"name\":\"skill_tool_name\",\"reason\":\"why it matches\"}]}. Only recommend skills from the provided catalog. Prefer the smallest set of high-confidence matches.",
|
|
140
|
+
},
|
|
127
141
|
}
|
|
128
142
|
```
|
|
129
143
|
|
|
@@ -131,10 +145,18 @@ templates/pr.md
|
|
|
131
145
|
|
|
132
146
|
- `debug`
|
|
133
147
|
- `basePaths`
|
|
134
|
-
- `promptRenderer`
|
|
135
|
-
- `modelRenderers`
|
|
136
148
|
- `slashCommandName`
|
|
137
149
|
- `enableSkillAliases`
|
|
150
|
+
- `reservedSlashCommands`
|
|
151
|
+
- `notifications`
|
|
152
|
+
- `skillRecommend`
|
|
153
|
+
|
|
154
|
+
当前注入的 skill 内容已固定使用单一 XML 渲染器,之前可自定义渲染格式的功能已移除。
|
|
155
|
+
|
|
156
|
+
`skillRecommend.strategy` 支持:
|
|
157
|
+
|
|
158
|
+
- `heuristic`(默认):使用内置规则排序
|
|
159
|
+
- `model`:使用配置的 `provider/model` 字符串发起一次内部 OpenCode session 调用
|
|
138
160
|
|
|
139
161
|
## Skill 发现路径
|
|
140
162
|
|
|
@@ -172,6 +194,7 @@ compatibility: opencode
|
|
|
172
194
|
- `name` 必须和目录名一致
|
|
173
195
|
- `name` 必须符合 OpenCode 命名规则
|
|
174
196
|
- `description` 必填
|
|
197
|
+
- skill 目录下除 `SKILL.md` 外的文件会被索引,并作为可用文件清单暴露给模型
|
|
175
198
|
|
|
176
199
|
## 开发
|
|
177
200
|
|
package/dist/api.d.ts
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
* - Logger (for debug output)
|
|
10
10
|
* - SkillRegistry (for discovery and parsing)
|
|
11
11
|
* - Tool creators (functions that create skill_find, skill_use, skill_resource)
|
|
12
|
-
* -
|
|
12
|
+
* - Prompt rendering helpers
|
|
13
13
|
*
|
|
14
14
|
* INITIALIZATION TIMING (CRITICAL):
|
|
15
15
|
* - createLogger(): synchronous, immediate
|
|
16
16
|
* - createSkillRegistry(): synchronous factory call (returns a SkillRegistry object)
|
|
17
|
-
* -
|
|
17
|
+
* - XML prompt rendering is fixed and selected by the caller
|
|
18
18
|
* - registry.initialise(): NOT called here, caller must do this separately
|
|
19
19
|
*
|
|
20
20
|
* WHY NOT CALL initialise(): The caller (index.ts) needs to await initialise()
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* RETURN VALUE: Object with:
|
|
24
24
|
* - registry: SkillRegistry instance (must call .initialise() before use)
|
|
25
25
|
* - logger: PluginLogger for debug output
|
|
26
|
-
* - config: PluginConfig
|
|
26
|
+
* - config: PluginConfig
|
|
27
27
|
* - findSkills: Tool creator function for skill search
|
|
28
28
|
* - readResource: Tool creator function for resource reading
|
|
29
29
|
* - loadSkill: Tool creator function for skill loading
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
* // Note: registry is created but NOT yet initialized
|
|
35
35
|
* // Must be done by caller: await registry.initialise()
|
|
36
36
|
*/
|
|
37
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
37
38
|
import { createLogger } from './services/logger';
|
|
38
39
|
import { createSkillRegistry } from './services/SkillRegistry';
|
|
39
40
|
import { createSkillFinder } from './tools/SkillFinder';
|
|
@@ -52,4 +53,4 @@ export type SkillsApi = {
|
|
|
52
53
|
loadSkill: ReturnType<typeof createSkillLoader>;
|
|
53
54
|
skillTool: ReturnType<typeof createSkillTool>;
|
|
54
55
|
};
|
|
55
|
-
export declare const createApi: (config: PluginConfig) => Promise<SkillsApi>;
|
|
56
|
+
export declare const createApi: (config: PluginConfig, client?: PluginInput["client"]) => Promise<SkillsApi>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SkillRegistry } from '../types';
|
|
2
|
+
type HookPart = {
|
|
3
|
+
type: string;
|
|
4
|
+
text?: string;
|
|
5
|
+
} & Record<string, unknown>;
|
|
6
|
+
export declare function rewriteMirroredSkillCommandParts(args: {
|
|
7
|
+
commandName: string;
|
|
8
|
+
commandArguments: string;
|
|
9
|
+
mirroredCommands: Set<string>;
|
|
10
|
+
registry: SkillRegistry;
|
|
11
|
+
output: {
|
|
12
|
+
parts: HookPart[];
|
|
13
|
+
};
|
|
14
|
+
}): Promise<boolean>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -12,7 +12,7 @@ export declare function renderSlashSkillPrompt(args: {
|
|
|
12
12
|
invocationName: string;
|
|
13
13
|
skill: Skill;
|
|
14
14
|
userPrompt: string;
|
|
15
|
-
}): string
|
|
15
|
+
}): Promise<string>;
|
|
16
16
|
export declare function renderRecommendSlashPrompt(task: string): string;
|
|
17
17
|
export declare function rewriteRecommendSlashCommandText(text: string): Promise<string | null>;
|
|
18
18
|
export declare function rewriteSlashCommandText(args: {
|
|
@@ -20,5 +20,6 @@ export declare function rewriteSlashCommandText(args: {
|
|
|
20
20
|
registry: SkillRegistry;
|
|
21
21
|
slashCommandName: string;
|
|
22
22
|
enableSkillAliases: boolean;
|
|
23
|
+
reservedSlashCommands?: string[];
|
|
23
24
|
}): Promise<string | null>;
|
|
24
25
|
export {};
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
-
import type { PluginConfig } from './types';
|
|
2
|
+
import type { NotificationConfig, PluginConfig, SkillRecommendConfig, TuiCommandMirrorConfig } from './types';
|
|
3
|
+
export declare const DEFAULT_RESERVED_SLASH_COMMANDS: readonly ["agent", "agents", "compact", "connect", "details", "editor", "exit", "export", "fork", "help", "init", "mcp", "model", "models", "new", "open", "redo", "sessions", "share", "skills", "terminal", "themes", "thinking", "undo", "unshare"];
|
|
4
|
+
export declare const DEFAULT_SKILL_RECOMMEND_SYSTEM_PROMPT: string;
|
|
5
|
+
export declare const MANAGED_PLUGIN_CONFIG_DIRECTORY: string;
|
|
6
|
+
export declare const MANAGED_TUI_COMMANDS_DIRECTORY: string;
|
|
7
|
+
export declare const MANAGED_PLUGIN_JSONC_FILENAME = "opencode-dynamic-skills.config.jsonc";
|
|
8
|
+
export declare const MANAGED_PLUGIN_JSON_FILENAME = "opencode-dynamic-skills.config.json";
|
|
9
|
+
type PartialPluginConfig = Partial<Omit<PluginConfig, 'skillRecommend' | 'notifications'>> & {
|
|
10
|
+
skillRecommend?: Partial<SkillRecommendConfig>;
|
|
11
|
+
notifications?: Partial<NotificationConfig>;
|
|
12
|
+
tuiCommandMirror?: Partial<TuiCommandMirrorConfig>;
|
|
13
|
+
};
|
|
3
14
|
/**
|
|
4
15
|
* Gets OpenCode-compatible config paths for the current platform.
|
|
5
16
|
*
|
|
@@ -44,4 +55,16 @@ export declare function resolveBasePath(basePath: string, projectDirectory: stri
|
|
|
44
55
|
*/
|
|
45
56
|
export declare function normalizeBasePaths(basePaths: string[], projectDirectory: string): string[];
|
|
46
57
|
export declare function getProjectSkillBasePaths(directory: string, worktree?: string): string[];
|
|
58
|
+
export declare function createDefaultSkillRecommendConfig(): SkillRecommendConfig;
|
|
59
|
+
export declare function createDefaultNotificationConfig(): NotificationConfig;
|
|
60
|
+
export declare function createDefaultTuiCommandMirrorConfig(): TuiCommandMirrorConfig;
|
|
61
|
+
export declare function createDefaultPluginConfig(): PluginConfig;
|
|
62
|
+
export declare function stripJsonComments(input: string): string;
|
|
63
|
+
export declare function removeTrailingJsonCommas(input: string): string;
|
|
64
|
+
export declare function parseJsonc<T>(input: string): T;
|
|
65
|
+
export declare function getManagedPluginConfigPaths(configDirectory?: string): string[];
|
|
66
|
+
export declare function renderManagedPluginConfigJsonc(config?: PluginConfig): string;
|
|
67
|
+
export declare function ensureManagedPluginConfigFile(configDirectory?: string): Promise<string>;
|
|
68
|
+
export declare function loadManagedPluginConfig(configDirectory?: string): Promise<PartialPluginConfig>;
|
|
47
69
|
export declare function getPluginConfig(ctx: PluginInput): Promise<PluginConfig>;
|
|
70
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - find_skills(): Search for skills by free-text query
|
|
12
12
|
* - Delivers skill content via silent message insertion (noReply pattern)
|
|
13
13
|
* - Supports nested skills with proper naming
|
|
14
|
-
* -
|
|
14
|
+
* - Uses a single XML prompt format for injected skill content
|
|
15
15
|
*
|
|
16
16
|
* Design Decisions:
|
|
17
17
|
* - Consolidates 50+ individual skill tools into 2 unified tools (cleaner namespace)
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* - Message insertion pattern ensures skill content persists (user messages not purged)
|
|
22
22
|
* - Base directory context enables relative path resolution
|
|
23
23
|
* - Skills require restart to reload (acceptable trade-off)
|
|
24
|
-
* - Prompt
|
|
24
|
+
* - Prompt rendering is fixed to XML for simpler, stable behavior
|
|
25
25
|
*
|
|
26
26
|
* @see https://github.com/anthropics/skills
|
|
27
27
|
*/
|