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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +180 -0
  3. package/README.zh-CN.md +180 -0
  4. package/dist/api.d.ts +96 -0
  5. package/dist/commands/SlashCommand.d.ts +26 -0
  6. package/dist/commands/SlashCommand.test.d.ts +1 -0
  7. package/dist/config.d.ts +47 -0
  8. package/dist/config.test.d.ts +1 -0
  9. package/dist/index.d.ts +29 -0
  10. package/dist/index.js +23805 -0
  11. package/dist/lib/Identifiers.d.ts +17 -0
  12. package/dist/lib/Indentifiers.test.d.ts +1 -0
  13. package/dist/lib/OpenCodeChat.d.ts +5 -0
  14. package/dist/lib/OpenCodeChat.test.d.ts +1 -0
  15. package/dist/lib/ReadyStateMachine.d.ts +36 -0
  16. package/dist/lib/SkillFs.d.ts +30 -0
  17. package/dist/lib/createPromptRenderer.d.ts +52 -0
  18. package/dist/lib/createPromptRenderer.test.d.ts +9 -0
  19. package/dist/lib/getModelFormat.d.ts +35 -0
  20. package/dist/lib/renderers/JsonPromptRenderer.d.ts +8 -0
  21. package/dist/lib/renderers/JsonPromptRenderer.test.d.ts +10 -0
  22. package/dist/lib/renderers/MdPromptRenderer.d.ts +18 -0
  23. package/dist/lib/renderers/MdPromptRenderer.test.d.ts +11 -0
  24. package/dist/lib/renderers/XmlPromptRenderer.d.ts +9 -0
  25. package/dist/lib/renderers/XmlPromptRenderer.test.d.ts +11 -0
  26. package/dist/lib/renderers/resourceMapToArray.d.ts +2 -0
  27. package/dist/lib/xml.d.ts +1 -0
  28. package/dist/mocks.d.ts +32 -0
  29. package/dist/mocks.skillfs.d.ts +1 -0
  30. package/dist/services/MessageModelIdAccountant.d.ts +22 -0
  31. package/dist/services/SkillRegistry.d.ts +9 -0
  32. package/dist/services/SkillRegistry.test.d.ts +1 -0
  33. package/dist/services/SkillResourceResolver.d.ts +20 -0
  34. package/dist/services/SkillResourceResolver.test.d.ts +1 -0
  35. package/dist/services/SkillSearcher.d.ts +77 -0
  36. package/dist/services/SkillSearcher.functions.test.d.ts +1 -0
  37. package/dist/services/SkillSearcher.test.d.ts +1 -0
  38. package/dist/services/logger.d.ts +2 -0
  39. package/dist/tools/SkillFinder.d.ts +46 -0
  40. package/dist/tools/SkillRecommender.d.ts +25 -0
  41. package/dist/tools/SkillRecommender.test.d.ts +1 -0
  42. package/dist/tools/SkillResourceReader.d.ts +43 -0
  43. package/dist/tools/SkillUser.d.ts +5 -0
  44. package/dist/types.d.ts +211 -0
  45. package/package.json +56 -0
@@ -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
+ }