opencode-dynamic-skills 1.1.0 → 1.2.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 +46 -18
- package/README.zh-CN.md +41 -18
- package/dist/api.d.ts +5 -4
- package/dist/commands/SlashCommand.d.ts +1 -0
- package/dist/config.d.ts +21 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +658 -499
- package/dist/lib/SkillFs.d.ts +1 -0
- package/dist/services/Notifier.d.ts +13 -0
- package/dist/services/Notifier.test.d.ts +1 -0
- package/dist/tools/SkillRecommender.d.ts +25 -8
- package/dist/types.d.ts +17 -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,31 @@ 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
|
+
},
|
|
127
146
|
}
|
|
128
147
|
```
|
|
129
148
|
|
|
@@ -131,10 +150,18 @@ Fields:
|
|
|
131
150
|
|
|
132
151
|
- `debug`
|
|
133
152
|
- `basePaths`
|
|
134
|
-
- `promptRenderer`
|
|
135
|
-
- `modelRenderers`
|
|
136
153
|
- `slashCommandName`
|
|
137
154
|
- `enableSkillAliases`
|
|
155
|
+
- `reservedSlashCommands`
|
|
156
|
+
- `notifications`
|
|
157
|
+
- `skillRecommend`
|
|
158
|
+
|
|
159
|
+
Injected skill content now always uses a single XML renderer. The previous custom renderer selection feature was removed.
|
|
160
|
+
|
|
161
|
+
`skillRecommend.strategy` supports:
|
|
162
|
+
|
|
163
|
+
- `heuristic` (default): use the built-in ranker
|
|
164
|
+
- `model`: call an internal OpenCode session with the configured `provider/model` string
|
|
138
165
|
|
|
139
166
|
## Skill discovery
|
|
140
167
|
|
|
@@ -172,6 +199,7 @@ Rules:
|
|
|
172
199
|
- `name` must match the directory name
|
|
173
200
|
- `name` must satisfy OpenCode naming rules
|
|
174
201
|
- `description` is required
|
|
202
|
+
- non-`SKILL.md` files under the skill directory are indexed and exposed as an available file manifest
|
|
175
203
|
|
|
176
204
|
## Development
|
|
177
205
|
|
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>;
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
-
import type { PluginConfig } from './types';
|
|
2
|
+
import type { NotificationConfig, PluginConfig, SkillRecommendConfig } 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_PLUGIN_JSONC_FILENAME = "opencode-dynamic-skills.config.jsonc";
|
|
7
|
+
export declare const MANAGED_PLUGIN_JSON_FILENAME = "opencode-dynamic-skills.config.json";
|
|
8
|
+
type PartialPluginConfig = Partial<Omit<PluginConfig, 'skillRecommend' | 'notifications'>> & {
|
|
9
|
+
skillRecommend?: Partial<SkillRecommendConfig>;
|
|
10
|
+
notifications?: Partial<NotificationConfig>;
|
|
11
|
+
};
|
|
3
12
|
/**
|
|
4
13
|
* Gets OpenCode-compatible config paths for the current platform.
|
|
5
14
|
*
|
|
@@ -44,4 +53,15 @@ export declare function resolveBasePath(basePath: string, projectDirectory: stri
|
|
|
44
53
|
*/
|
|
45
54
|
export declare function normalizeBasePaths(basePaths: string[], projectDirectory: string): string[];
|
|
46
55
|
export declare function getProjectSkillBasePaths(directory: string, worktree?: string): string[];
|
|
56
|
+
export declare function createDefaultSkillRecommendConfig(): SkillRecommendConfig;
|
|
57
|
+
export declare function createDefaultNotificationConfig(): NotificationConfig;
|
|
58
|
+
export declare function createDefaultPluginConfig(): PluginConfig;
|
|
59
|
+
export declare function stripJsonComments(input: string): string;
|
|
60
|
+
export declare function removeTrailingJsonCommas(input: string): string;
|
|
61
|
+
export declare function parseJsonc<T>(input: string): T;
|
|
62
|
+
export declare function getManagedPluginConfigPaths(configDirectory?: string): string[];
|
|
63
|
+
export declare function renderManagedPluginConfigJsonc(config?: PluginConfig): string;
|
|
64
|
+
export declare function ensureManagedPluginConfigFile(configDirectory?: string): Promise<string>;
|
|
65
|
+
export declare function loadManagedPluginConfig(configDirectory?: string): Promise<PartialPluginConfig>;
|
|
47
66
|
export declare function getPluginConfig(ctx: PluginInput): Promise<PluginConfig>;
|
|
67
|
+
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
|
*/
|