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 CHANGED
@@ -1,20 +1,17 @@
1
1
  # OpenCode Dynamic Skills
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/opencode-dynamic-skills?color=cb3837&logo=npm)](https://www.npmjs.com/package/opencode-dynamic-skills)
4
+ [![license](https://img.shields.io/npm/l/opencode-dynamic-skills)](./LICENSE)
5
+ [![bun](https://img.shields.io/badge/runtime-Bun-f9f1e1?logo=bun)](https://bun.sh/)
6
+ [![OpenCode](https://img.shields.io/badge/plugin-OpenCode-111827)](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
- ```json
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 内文件引用统一基于 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
- ```json
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
- * - PromptRenderer (for format selection and rendering)
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
- * - createPromptRenderer(): synchronous, immediate (format selection at runtime)
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 (needed for model-aware format selection)
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>;
@@ -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,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
- * - Supports multiple prompt formats (XML, JSON, Markdown) with model-aware selection
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 format selection: model-aware via modelRenderers config, default XML
24
+ * - Prompt rendering is fixed to XML for simpler, stable behavior
25
25
  *
26
26
  * @see https://github.com/anthropics/skills
27
27
  */