opencode-dynamic-skills 1.0.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/LICENSE +21 -0
- package/README.md +180 -0
- package/README.zh-CN.md +180 -0
- package/dist/api.d.ts +96 -0
- package/dist/commands/SlashCommand.d.ts +26 -0
- package/dist/commands/SlashCommand.test.d.ts +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.test.d.ts +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +23805 -0
- package/dist/lib/Identifiers.d.ts +17 -0
- package/dist/lib/Indentifiers.test.d.ts +1 -0
- package/dist/lib/OpenCodeChat.d.ts +5 -0
- package/dist/lib/OpenCodeChat.test.d.ts +1 -0
- package/dist/lib/ReadyStateMachine.d.ts +36 -0
- package/dist/lib/SkillFs.d.ts +30 -0
- package/dist/lib/createPromptRenderer.d.ts +52 -0
- package/dist/lib/createPromptRenderer.test.d.ts +9 -0
- package/dist/lib/getModelFormat.d.ts +35 -0
- package/dist/lib/renderers/JsonPromptRenderer.d.ts +8 -0
- package/dist/lib/renderers/JsonPromptRenderer.test.d.ts +10 -0
- package/dist/lib/renderers/MdPromptRenderer.d.ts +18 -0
- package/dist/lib/renderers/MdPromptRenderer.test.d.ts +11 -0
- package/dist/lib/renderers/XmlPromptRenderer.d.ts +9 -0
- package/dist/lib/renderers/XmlPromptRenderer.test.d.ts +11 -0
- package/dist/lib/renderers/resourceMapToArray.d.ts +2 -0
- package/dist/lib/xml.d.ts +1 -0
- package/dist/mocks.d.ts +32 -0
- package/dist/mocks.skillfs.d.ts +1 -0
- package/dist/services/MessageModelIdAccountant.d.ts +22 -0
- package/dist/services/SkillRegistry.d.ts +9 -0
- package/dist/services/SkillRegistry.test.d.ts +1 -0
- package/dist/services/SkillResourceResolver.d.ts +20 -0
- package/dist/services/SkillResourceResolver.test.d.ts +1 -0
- package/dist/services/SkillSearcher.d.ts +77 -0
- package/dist/services/SkillSearcher.functions.test.d.ts +1 -0
- package/dist/services/SkillSearcher.test.d.ts +1 -0
- package/dist/services/logger.d.ts +2 -0
- package/dist/tools/SkillFinder.d.ts +46 -0
- package/dist/tools/SkillRecommender.d.ts +25 -0
- package/dist/tools/SkillRecommender.test.d.ts +1 -0
- package/dist/tools/SkillResourceReader.d.ts +43 -0
- package/dist/tools/SkillUser.d.ts +5 -0
- package/dist/types.d.ts +211 -0
- package/package.json +56 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for OpenCode Dynamic Skills Plugin
|
|
3
|
+
*/
|
|
4
|
+
import { ReadyStateMachine } from './lib/ReadyStateMachine';
|
|
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.
|
|
20
|
+
*/
|
|
21
|
+
type SkillInjectionResult = {
|
|
22
|
+
skill_name: string;
|
|
23
|
+
resource_path: string;
|
|
24
|
+
resource_mimetype: string;
|
|
25
|
+
content: string;
|
|
26
|
+
};
|
|
27
|
+
type SkillSearchResultInjection = {
|
|
28
|
+
mode?: 'search' | 'recommend';
|
|
29
|
+
query: string | string[];
|
|
30
|
+
skills: Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
}>;
|
|
34
|
+
summary: {
|
|
35
|
+
total: number;
|
|
36
|
+
matches: number;
|
|
37
|
+
feedback: string;
|
|
38
|
+
};
|
|
39
|
+
recommendations?: Array<{
|
|
40
|
+
name: string;
|
|
41
|
+
description: string;
|
|
42
|
+
score: number;
|
|
43
|
+
reason: string;
|
|
44
|
+
}>;
|
|
45
|
+
guidance?: string;
|
|
46
|
+
debug?: SkillRegistryDebugInfo;
|
|
47
|
+
};
|
|
48
|
+
type Args = {
|
|
49
|
+
data: Skill;
|
|
50
|
+
type: 'Skill';
|
|
51
|
+
} | {
|
|
52
|
+
data: SkillInjectionResult;
|
|
53
|
+
type: 'SkillResource';
|
|
54
|
+
} | {
|
|
55
|
+
data: SkillSearchResultInjection;
|
|
56
|
+
type: 'SkillSearchResults';
|
|
57
|
+
};
|
|
58
|
+
export interface PromptRenderer {
|
|
59
|
+
/**
|
|
60
|
+
* Render an object to a string using the preferred format
|
|
61
|
+
*
|
|
62
|
+
* @param data The object to render (typically skill metadata or search results)
|
|
63
|
+
* @param rootElement Optional element name (used for XML rendering as root tag)
|
|
64
|
+
* @returns Formatted string ready for prompt injection
|
|
65
|
+
*/
|
|
66
|
+
render(args: Args): string;
|
|
67
|
+
/**
|
|
68
|
+
* The format identifier for this renderer
|
|
69
|
+
* Used for logging, debugging, and format selection
|
|
70
|
+
*/
|
|
71
|
+
readonly format: 'json' | 'xml' | 'md';
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Skill resource map type for indexing skill resources
|
|
75
|
+
*
|
|
76
|
+
* A Map of relative paths to resource metadata. Used to securely resolve
|
|
77
|
+
* and access skill resources without allowing path traversal attacks.
|
|
78
|
+
*
|
|
79
|
+
* Key: relative path to the resource (e.g., "scripts/build.sh", "references/README.md")
|
|
80
|
+
* Value: resource metadata
|
|
81
|
+
* - absolutePath: absolute filesystem path (pre-validated during skill initialization)
|
|
82
|
+
* - mimeType: detected MIME type for proper content handling
|
|
83
|
+
*
|
|
84
|
+
* Example:
|
|
85
|
+
* Map {
|
|
86
|
+
* "scripts/build.sh" => { absolutePath: "/skills/cli/scripts/build.sh", mimeType: "application/x-sh" },
|
|
87
|
+
* "references/api.md" => { absolutePath: "/skills/cli/references/api.md", mimeType: "text/markdown" }
|
|
88
|
+
* }
|
|
89
|
+
*/
|
|
90
|
+
export type SkillResource = {
|
|
91
|
+
relativePath: string;
|
|
92
|
+
absolutePath: string;
|
|
93
|
+
mimeType: string;
|
|
94
|
+
};
|
|
95
|
+
export type SkillResourceMap = Map<string, Omit<SkillResource, 'relativePath'>>;
|
|
96
|
+
declare const ResourceTypes: readonly ["script", "asset", "reference"];
|
|
97
|
+
type ResourceType = (typeof ResourceTypes)[number];
|
|
98
|
+
/**
|
|
99
|
+
* Asserts that the provided type is a valid ResourceType
|
|
100
|
+
*/
|
|
101
|
+
export declare const assertIsValidResourceType: (type: string) => asserts type is ResourceType;
|
|
102
|
+
export type MapValue<T> = T extends Map<unknown, infer V> ? V : never;
|
|
103
|
+
export type MapKey<T> = T extends Map<infer K, unknown> ? K : never;
|
|
104
|
+
/**
|
|
105
|
+
* Skill definition parsed from SKILL.md
|
|
106
|
+
*
|
|
107
|
+
* Represents a complete skill including metadata and indexed resources.
|
|
108
|
+
* Resources are pre-indexed at skill initialization to enable:
|
|
109
|
+
* - Safe path traversal prevention (all paths are pre-validated)
|
|
110
|
+
* - Fast lookup by relative path
|
|
111
|
+
* - MIME type detection for proper content handling
|
|
112
|
+
*/
|
|
113
|
+
export type Skill = {
|
|
114
|
+
name: string;
|
|
115
|
+
fullPath: string;
|
|
116
|
+
toolName: string;
|
|
117
|
+
description: string;
|
|
118
|
+
compatibility?: string;
|
|
119
|
+
allowedTools?: string[];
|
|
120
|
+
metadata?: Record<string, string>;
|
|
121
|
+
license?: string;
|
|
122
|
+
content: string;
|
|
123
|
+
path: string;
|
|
124
|
+
scripts: SkillResourceMap;
|
|
125
|
+
references: SkillResourceMap;
|
|
126
|
+
assets: SkillResourceMap;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Text segment from parsed search query
|
|
130
|
+
*/
|
|
131
|
+
export type TextSegment = {
|
|
132
|
+
text: string;
|
|
133
|
+
negated: boolean;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Parsed query structure from search-string
|
|
137
|
+
*/
|
|
138
|
+
export type ParsedSkillQuery = {
|
|
139
|
+
include: string[];
|
|
140
|
+
exclude: string[];
|
|
141
|
+
originalQuery: string[];
|
|
142
|
+
hasExclusions: boolean;
|
|
143
|
+
termCount: number;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Search result with ranking and feedback
|
|
147
|
+
*/
|
|
148
|
+
export type SkillSearchResult = {
|
|
149
|
+
matches: Skill[];
|
|
150
|
+
totalMatches: number;
|
|
151
|
+
totalSkills: number;
|
|
152
|
+
feedback: string;
|
|
153
|
+
query: ParsedSkillQuery;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Ranking metrics for a skill match
|
|
157
|
+
*/
|
|
158
|
+
export type SkillRank = {
|
|
159
|
+
skill: Skill;
|
|
160
|
+
nameMatches: number;
|
|
161
|
+
descMatches: number;
|
|
162
|
+
totalScore: number;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Plugin configuration
|
|
166
|
+
*/
|
|
167
|
+
export type PluginConfig = {
|
|
168
|
+
debug: boolean;
|
|
169
|
+
basePaths: string[];
|
|
170
|
+
promptRenderer: 'json' | 'xml' | 'md';
|
|
171
|
+
modelRenderers?: Record<string, 'json' | 'xml' | 'md'>;
|
|
172
|
+
slashCommandName: string;
|
|
173
|
+
enableSkillAliases: boolean;
|
|
174
|
+
};
|
|
175
|
+
export type LogType = 'log' | 'debug' | 'error' | 'warn';
|
|
176
|
+
export type PluginLogger = Record<LogType, (...message: unknown[]) => void>;
|
|
177
|
+
/**
|
|
178
|
+
* Skill searcher function type
|
|
179
|
+
*/
|
|
180
|
+
export type SkillSearcher = (_query: string | string[]) => SkillSearchResult;
|
|
181
|
+
/**
|
|
182
|
+
* Skill registry controller interface
|
|
183
|
+
*/
|
|
184
|
+
export type SkillRegistryController = {
|
|
185
|
+
ready: ReadyStateMachine;
|
|
186
|
+
skills: Skill[];
|
|
187
|
+
ids: string[];
|
|
188
|
+
clear: () => void;
|
|
189
|
+
delete: (_key: string) => void;
|
|
190
|
+
has: (_key: string) => boolean;
|
|
191
|
+
get: (_key: string) => Skill | undefined;
|
|
192
|
+
set: (_key: string, _skill: Skill) => void;
|
|
193
|
+
};
|
|
194
|
+
export type SkillRegistryDebugInfo = {
|
|
195
|
+
discovered: number;
|
|
196
|
+
parsed: number;
|
|
197
|
+
rejected: number;
|
|
198
|
+
errors: string[];
|
|
199
|
+
};
|
|
200
|
+
export type SkillRegistry = {
|
|
201
|
+
initialise: () => Promise<void>;
|
|
202
|
+
config: PluginConfig;
|
|
203
|
+
register: (...skillPaths: string[]) => Promise<SkillRegistryDebugInfo>;
|
|
204
|
+
controller: SkillRegistryController;
|
|
205
|
+
isSkillPath: (_path: string) => boolean;
|
|
206
|
+
getToolnameFromSkillPath: (_path: string) => string | null;
|
|
207
|
+
search: SkillSearcher;
|
|
208
|
+
debug?: SkillRegistryDebugInfo;
|
|
209
|
+
logger: PluginLogger;
|
|
210
|
+
};
|
|
211
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-dynamic-skills",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "OpenCode plugin for dynamic skill loading, slash skill commands, and skill-root-relative resources",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Wu-H-Y/opencode-dynamic-skills"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "dist/index.js",
|
|
15
|
+
"module": "dist/index.js",
|
|
16
|
+
"types": "dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"provenance": true
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "bun build ./src/index.ts --outdir dist --target bun && tsc --noEmit false --emitDeclarationOnly --declaration --declarationDir dist",
|
|
29
|
+
"test": "bun test",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"lint": "oxlint .",
|
|
32
|
+
"lint:fix": "oxlint --fix .",
|
|
33
|
+
"format": "oxfmt .",
|
|
34
|
+
"format:check": "oxfmt --check ."
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@opencode-ai/plugin": "1.2.26",
|
|
38
|
+
"bunfig": "^0.15.6",
|
|
39
|
+
"dedent": "^1.7.2",
|
|
40
|
+
"gray-matter": "^4.0.3",
|
|
41
|
+
"mime": "^4.1.0",
|
|
42
|
+
"ramda": "^0.32.0",
|
|
43
|
+
"search-string": "^4.1.0",
|
|
44
|
+
"zod": "^4.3.6"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/bun": "^1.3.10",
|
|
48
|
+
"@types/node": "^25.5.0",
|
|
49
|
+
"@types/ramda": "^0.31.1",
|
|
50
|
+
"memfs": "^4.56.11",
|
|
51
|
+
"oxfmt": "^0.40.0",
|
|
52
|
+
"oxlint": "^1.55.0",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"vitest": "^4.1.0"
|
|
55
|
+
}
|
|
56
|
+
}
|