opencode-dynamic-skills 1.0.2 → 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.
@@ -18,6 +18,7 @@ export declare const readSkillFile: (path: string) => Promise<string>;
18
18
  * @returns Array of absolute file paths
19
19
  */
20
20
  export declare const listSkillFiles: (skillPath: string, subdirectory: string) => string[];
21
+ export declare const listAllSkillFiles: (skillPath: string) => string[];
21
22
  export declare const findSkillPaths: (basePath: string) => Promise<string[]>;
22
23
  export declare const doesPathExist: (path: string) => boolean;
23
24
  /**
@@ -0,0 +1,6 @@
1
+ import type { Skill } from '../types';
2
+ export declare function formatLoadedSkill(args: {
3
+ skill: Skill;
4
+ invocationName?: string;
5
+ userMessage?: string;
6
+ }): string;
@@ -0,0 +1,13 @@
1
+ import type { NotificationConfig, PluginLogger } from '../types';
2
+ type NotificationRunner = (command: string, args: string[]) => Promise<unknown>;
3
+ export declare function createNotifier(args: {
4
+ config: NotificationConfig;
5
+ logger: PluginLogger;
6
+ shell?: NotificationRunner;
7
+ platform?: NodeJS.Platform;
8
+ }): {
9
+ skillLoaded(skillNames: string[]): Promise<void>;
10
+ resourceLoaded(skillName: string, relativePath: string): Promise<void>;
11
+ error(title: string, message: string): Promise<void>;
12
+ };
13
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { type ToolDefinition } from '@opencode-ai/plugin';
2
+ import type { SkillRegistry } from '../types';
3
+ export declare function createSkillTool(registry: SkillRegistry): ToolDefinition;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,26 @@
1
- import type { SkillRegistry } from '../types';
2
- export declare function createSkillRecommender(provider: SkillRegistry): (args: {
1
+ import type { PluginInput } from '@opencode-ai/plugin';
2
+ import type { SkillRecommendConfig, SkillRegistry } from '../types';
3
+ type RecommendationResult = {
4
+ name: string;
5
+ description: string;
6
+ score: number;
7
+ reason: string;
8
+ };
9
+ type RecommenderOptions = {
10
+ client?: PluginInput['client'];
11
+ config: SkillRecommendConfig;
12
+ };
13
+ type ModelRecommendation = {
14
+ name: string;
15
+ reason?: string;
16
+ };
17
+ type ParsedModelSelection = {
18
+ providerID: string;
19
+ modelID: string;
20
+ };
21
+ export declare function parseModelRecommendations(text: string): ModelRecommendation[];
22
+ export declare function parseConfiguredModel(model: string): ParsedModelSelection;
23
+ export declare function createSkillRecommender(provider: SkillRegistry, options: RecommenderOptions): (args: {
3
24
  task: string;
4
25
  limit?: number;
5
26
  }) => Promise<{
@@ -9,12 +30,7 @@ export declare function createSkillRecommender(provider: SkillRegistry): (args:
9
30
  name: string;
10
31
  description: string;
11
32
  }[];
12
- recommendations: {
13
- name: string;
14
- description: string;
15
- score: number;
16
- reason: string;
17
- }[];
33
+ recommendations: RecommendationResult[];
18
34
  guidance: string;
19
35
  summary: {
20
36
  total: number;
@@ -23,3 +39,4 @@ export declare function createSkillRecommender(provider: SkillRegistry): (args:
23
39
  };
24
40
  debug: import("../types").SkillRegistryDebugInfo | undefined;
25
41
  }>;
42
+ export {};
package/dist/types.d.ts CHANGED
@@ -3,20 +3,7 @@
3
3
  */
4
4
  import { ReadyStateMachine } from './lib/ReadyStateMachine';
5
5
  /**
6
- * PromptRenderer Interface - Provider Pattern for Prompt Injection Formatting
7
- *
8
- * WHY: Different LLM models have different strengths and preferences for structured data:
9
- * - Claude models: trained extensively on XML, prefer structured XML injection
10
- * - GPT models: strong JSON parsing, prefer JSON-formatted data
11
- * - Other models: may benefit from markdown readability for better context
12
- *
13
- * The provider pattern allows selecting the appropriate renderer at runtime based on:
14
- * - Model preference (configured in modelRenderers)
15
- * - Global default (promptRenderer)
16
- * - Model detection via client.session.message()
17
- *
18
- * This abstraction decouples rendering format from tool execution logic,
19
- * enabling easy format additions without changing plugin code.
6
+ * PromptRenderer Interface for injected XML skill content.
20
7
  */
21
8
  type SkillInjectionResult = {
22
9
  skill_name: string;
@@ -65,10 +52,9 @@ export interface PromptRenderer {
65
52
  */
66
53
  render(args: Args): string;
67
54
  /**
68
- * The format identifier for this renderer
69
- * Used for logging, debugging, and format selection
55
+ * The format identifier for this renderer.
70
56
  */
71
- readonly format: 'json' | 'xml' | 'md';
57
+ readonly format: 'xml';
72
58
  }
73
59
  /**
74
60
  * Skill resource map type for indexing skill resources
@@ -121,6 +107,7 @@ export type Skill = {
121
107
  license?: string;
122
108
  content: string;
123
109
  path: string;
110
+ files: SkillResourceMap;
124
111
  scripts: SkillResourceMap;
125
112
  references: SkillResourceMap;
126
113
  assets: SkillResourceMap;
@@ -167,10 +154,21 @@ export type SkillRank = {
167
154
  export type PluginConfig = {
168
155
  debug: boolean;
169
156
  basePaths: string[];
170
- promptRenderer: 'json' | 'xml' | 'md';
171
- modelRenderers?: Record<string, 'json' | 'xml' | 'md'>;
172
157
  slashCommandName: string;
173
158
  enableSkillAliases: boolean;
159
+ reservedSlashCommands: string[];
160
+ notifications: NotificationConfig;
161
+ skillRecommend: SkillRecommendConfig;
162
+ };
163
+ export type NotificationConfig = {
164
+ enabled: boolean;
165
+ success: boolean;
166
+ errors: boolean;
167
+ };
168
+ export type SkillRecommendConfig = {
169
+ strategy: 'heuristic' | 'model';
170
+ model: string;
171
+ systemPrompt: string;
174
172
  };
175
173
  export type LogType = 'log' | 'debug' | 'error' | 'warn';
176
174
  export type PluginLogger = Record<LogType, (...message: unknown[]) => void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-dynamic-skills",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "OpenCode plugin for dynamic skill loading, slash skill commands, and skill-root-relative resources",
5
5
  "homepage": "https://github.com/Wu-H-Y/opencode-dynamic-skills#readme",
6
6
  "bugs": {
@@ -1,52 +0,0 @@
1
- /**
2
- * Prompt Renderer Factory
3
- *
4
- * WHY: Factory pattern centralizes renderer instantiation and makes it easy to:
5
- * - Add new renderer types in the future
6
- * - Test with different renderers
7
- * - Handle invalid formats gracefully
8
- */
9
- /**
10
- * Create a prompt renderer for the specified format
11
- *
12
- * @param format The desired format: 'json' | 'xml' | 'md'
13
- * @returns A PromptRenderer instance for the specified format
14
- * @throws Error if format is not recognized
15
- */
16
- export declare function createPromptRenderer(): {
17
- getFormatter: (format: "json" | "xml" | "md") => (args: {
18
- data: import("../types").Skill;
19
- type: "Skill";
20
- } | {
21
- data: {
22
- skill_name: string;
23
- resource_path: string;
24
- resource_mimetype: string;
25
- content: string;
26
- };
27
- type: "SkillResource";
28
- } | {
29
- data: {
30
- mode?: "search" | "recommend";
31
- query: string | string[];
32
- skills: Array<{
33
- name: string;
34
- description: string;
35
- }>;
36
- summary: {
37
- total: number;
38
- matches: number;
39
- feedback: string;
40
- };
41
- recommendations?: Array<{
42
- name: string;
43
- description: string;
44
- score: number;
45
- reason: string;
46
- }>;
47
- guidance?: string;
48
- debug?: import("../types").SkillRegistryDebugInfo;
49
- };
50
- type: "SkillSearchResults";
51
- }) => string;
52
- };
@@ -1,9 +0,0 @@
1
- /**
2
- * createPromptRenderer Factory Tests
3
- *
4
- * Test coverage:
5
- * - Correct renderer instantiation for each format
6
- * - Invalid format error handling
7
- * - Format identifier verification
8
- */
9
- export {};
@@ -1,35 +0,0 @@
1
- /**
2
- * Model Format Resolver - Select renderer based on active LLM model
3
- *
4
- * WHY: Different LLM models have different preferences and strengths:
5
- * - Claude models: optimized for XML, prefer structured XML injection
6
- * - GPT models: strong JSON parsing, prefer JSON-formatted data
7
- * - Other models: may benefit from markdown readability
8
- *
9
- * This function detects the active model and selects the configured
10
- * format preference for that model, falling back to progressively more
11
- * generic model patterns.
12
- *
13
- * HOW IT WORKS:
14
- * 1. Query the current session via client.session.message()
15
- * 2. Extract the modelID from the response (e.g., "anthropic-claude-3-5-sonnet")
16
- * 3. Try matching in order:
17
- * - Full model ID (e.g., "anthropic-claude-3-5-sonnet")
18
- * - Generic model pattern (e.g., "claude-3-5-sonnet")
19
- * 4. If no match, fall back to promptRenderer default
20
- */
21
- import type { PluginConfig } from '../types';
22
- /**
23
- * Resolve the appropriate prompt format for the current model
24
- *
25
- * @param args An object containing:
26
- * - modelId?: The identifier of the active model (e.g., "claude-3-5-sonnet")
27
- * - providerId?: The identifier of the model provider (e.g., "anthropic")
28
- * - config: The plugin configuration (has promptRenderer and modelRenderers)
29
- * @returns The format to use: 'json' | 'xml' | 'md'
30
- */
31
- export declare function getModelFormat(args: {
32
- modelId?: string;
33
- providerId?: string;
34
- config: PluginConfig;
35
- }): 'json' | 'xml' | 'md';
@@ -1,8 +0,0 @@
1
- /**
2
- * JsonPromptRenderer - Format objects as JSON
3
- *
4
- * WHY: Some LLM models (especially GPT family) have strong JSON parsing
5
- * and prefer structured JSON data over XML for reliability and clarity.
6
- */
7
- import type { PromptRenderer } from '../../types';
8
- export declare const createJsonPromptRenderer: () => PromptRenderer;
@@ -1,10 +0,0 @@
1
- /**
2
- * JsonPromptRenderer Tests
3
- *
4
- * Test coverage for real use cases:
5
- * - Rendering Skill objects for prompt injection
6
- * - Rendering SkillResource objects (file content)
7
- * - Rendering SkillSearchResults objects (search results)
8
- * - Proper JSON formatting with indentation
9
- */
10
- export {};
@@ -1,18 +0,0 @@
1
- /**
2
- * MdPromptRenderer - Format objects as human-readable Markdown
3
- *
4
- * WHY: Markdown provides human-readable formatting that works well for:
5
- * - Models that benefit from visual structure and readability
6
- * - Debugging and development (easier to read in logs)
7
- * - Accessibility and presentation
8
- *
9
- * STRUCTURE:
10
- * - Top-level keys → H3 headings (### key)
11
- * - Nested objects → H4 headings (#### key) with increased indentation
12
- * - Leaf nodes → nested bullet list items with emphasis: - **key**: *value*
13
- * - Arrays → nested bullets under parent key
14
- * - Special characters → HTML-escaped (&lt;, &gt;, &amp;)
15
- * - Skill content → appended after --- separator with ### Content heading
16
- */
17
- import type { PromptRenderer } from '../../types';
18
- export declare const createMdPromptRenderer: () => PromptRenderer;
@@ -1,11 +0,0 @@
1
- /**
2
- * MdPromptRenderer Tests
3
- *
4
- * Test coverage for real use cases:
5
- * - Rendering Skill objects with metadata, references, scripts, assets
6
- * - Rendering SkillResource objects (file content)
7
- * - Rendering SkillSearchResults objects
8
- * - HTML character escaping for security
9
- * - Special values handling (null, undefined)
10
- */
11
- export {};
@@ -1,22 +0,0 @@
1
- declare function createMessageModelIdAccountant(): {
2
- reset: () => void;
3
- track: (info: {
4
- sessionID: string;
5
- messageID: string;
6
- modelID: string;
7
- providerID: string;
8
- }) => void;
9
- untrackMessage: (args: {
10
- messageID: string;
11
- sessionID: string;
12
- }) => void;
13
- untrackSession: (sessionID: string) => void;
14
- getModelInfo: (args: {
15
- messageID: string;
16
- sessionID: string;
17
- }) => {
18
- modelID: string;
19
- providerID: string;
20
- } | undefined;
21
- };
22
- export { createMessageModelIdAccountant };