opencode-plugin-preload-skills 1.3.0 → 1.5.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 +57 -1
- package/dist/index.cjs +94 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +94 -25
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ A powerful plugin for [OpenCode](https://opencode.ai) that intelligently loads s
|
|
|
23
23
|
| **Conditional Loading** | Load only if dependency exists |
|
|
24
24
|
| **Token Budget** | Cap total skill tokens to protect context |
|
|
25
25
|
| **Summaries Mode** | Load compact summaries instead of full content |
|
|
26
|
+
| **System Prompt Injection** | Inject skills into system prompt instead of messages |
|
|
26
27
|
| **Usage Analytics** | Track which skills are actually used |
|
|
27
28
|
|
|
28
29
|
> **⚠️ Warning:** Preloaded skills consume context window tokens. Use `maxTokens` to set a budget and `useSummaries` for large skills.
|
|
@@ -86,6 +87,11 @@ A powerful plugin for [OpenCode](https://opencode.ai) that intelligently loads s
|
|
|
86
87
|
{ "skill": "react", "if": { "packageHasDependency": "react" } },
|
|
87
88
|
{ "skill": "prisma", "if": { "fileExists": "prisma/schema.prisma" } }
|
|
88
89
|
],
|
|
90
|
+
"skillSettings": {
|
|
91
|
+
"large-skill": { "useSummary": true },
|
|
92
|
+
"critical-skill": { "useSummary": false }
|
|
93
|
+
},
|
|
94
|
+
"injectionMethod": "chatMessage",
|
|
89
95
|
"maxTokens": 10000,
|
|
90
96
|
"useSummaries": false,
|
|
91
97
|
"analytics": false,
|
|
@@ -105,8 +111,10 @@ A powerful plugin for [OpenCode](https://opencode.ai) that intelligently loads s
|
|
|
105
111
|
| `contentTriggers` | `Record<string, string[]>` | `{}` | Map keywords to skills |
|
|
106
112
|
| `groups` | `Record<string, string[]>` | `{}` | Define skill bundles |
|
|
107
113
|
| `conditionalSkills` | `ConditionalSkill[]` | `[]` | Load if condition met |
|
|
114
|
+
| `skillSettings` | `Record<string, SkillSettings>` | `{}` | Per-skill settings |
|
|
115
|
+
| `injectionMethod` | `"chatMessage" \| "systemPrompt"` | `"chatMessage"` | Where to inject skills |
|
|
108
116
|
| `maxTokens` | `number` | `undefined` | Max tokens for all skills |
|
|
109
|
-
| `useSummaries` | `boolean` | `false` | Use skill summaries |
|
|
117
|
+
| `useSummaries` | `boolean` | `false` | Use skill summaries (global) |
|
|
110
118
|
| `analytics` | `boolean` | `false` | Track skill usage |
|
|
111
119
|
| `persistAfterCompaction` | `boolean` | `true` | Keep skills after compaction |
|
|
112
120
|
| `debug` | `boolean` | `false` | Enable debug logs |
|
|
@@ -252,6 +260,54 @@ Enable with:
|
|
|
252
260
|
|
|
253
261
|
If no `summary` field, auto-generates from first paragraph.
|
|
254
262
|
|
|
263
|
+
### Per-Skill Settings
|
|
264
|
+
|
|
265
|
+
Override global settings for specific skills:
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"useSummaries": false,
|
|
270
|
+
"skillSettings": {
|
|
271
|
+
"large-reference": { "useSummary": true },
|
|
272
|
+
"critical-instructions": { "useSummary": false }
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Available settings:**
|
|
278
|
+
- `useSummary` — Override global `useSummaries` for this skill
|
|
279
|
+
|
|
280
|
+
**Priority:** `skillSettings` > `useSummaries` (global)
|
|
281
|
+
|
|
282
|
+
This lets you use full content for critical skills while summarizing large reference materials.
|
|
283
|
+
|
|
284
|
+
### Injection Method
|
|
285
|
+
|
|
286
|
+
Choose where skills are injected:
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"injectionMethod": "systemPrompt"
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Methods:**
|
|
295
|
+
|
|
296
|
+
| Method | Description | Use Case |
|
|
297
|
+
|--------|-------------|----------|
|
|
298
|
+
| `chatMessage` (default) | Injects skills into user messages | One-time injection, visible in conversation |
|
|
299
|
+
| `systemPrompt` | Injects into system prompt via `experimental.chat.system.transform` hook | Persistent across all LLM calls, invisible to user |
|
|
300
|
+
|
|
301
|
+
**System prompt injection benefits:**
|
|
302
|
+
- Skills persist automatically (no need for `persistAfterCompaction`)
|
|
303
|
+
- Cleaner conversation history (skills not visible in messages)
|
|
304
|
+
- Skills included in every LLM call automatically
|
|
305
|
+
|
|
306
|
+
**Chat message injection benefits:**
|
|
307
|
+
- Skills visible in conversation for debugging
|
|
308
|
+
- Works with all OpenCode versions
|
|
309
|
+
- More control over when skills appear
|
|
310
|
+
|
|
255
311
|
### Usage Analytics
|
|
256
312
|
|
|
257
313
|
Track which skills are loaded and how often:
|
package/dist/index.cjs
CHANGED
|
@@ -126,12 +126,17 @@ function loadSkills(skillNames, projectDir) {
|
|
|
126
126
|
}
|
|
127
127
|
return skills;
|
|
128
128
|
}
|
|
129
|
-
function formatSkillsForInjection(skills,
|
|
129
|
+
function formatSkillsForInjection(skills, options = false) {
|
|
130
130
|
if (!Array.isArray(skills) || skills.length === 0) {
|
|
131
131
|
return "";
|
|
132
132
|
}
|
|
133
|
+
const opts = typeof options === "boolean" ? { useSummaries: options } : options;
|
|
134
|
+
const globalUseSummaries = opts.useSummaries ?? false;
|
|
135
|
+
const skillSettings = opts.skillSettings ?? {};
|
|
133
136
|
const parts = skills.map((skill) => {
|
|
134
|
-
const
|
|
137
|
+
const perSkillSetting = skillSettings[skill.name]?.useSummary;
|
|
138
|
+
const shouldUseSummary = perSkillSetting ?? globalUseSummaries;
|
|
139
|
+
const content = shouldUseSummary && skill.summary ? skill.summary : skill.content;
|
|
135
140
|
return `<preloaded-skill name="${skill.name}">
|
|
136
141
|
${content}
|
|
137
142
|
</preloaded-skill>`;
|
|
@@ -169,6 +174,8 @@ var DEFAULT_CONFIG = {
|
|
|
169
174
|
contentTriggers: {},
|
|
170
175
|
groups: {},
|
|
171
176
|
conditionalSkills: [],
|
|
177
|
+
skillSettings: {},
|
|
178
|
+
injectionMethod: "chatMessage",
|
|
172
179
|
maxTokens: void 0,
|
|
173
180
|
useSummaries: false,
|
|
174
181
|
analytics: false,
|
|
@@ -204,6 +211,22 @@ function parseConditionalSkills(raw) {
|
|
|
204
211
|
(item) => typeof item === "object" && item !== null && typeof item.skill === "string" && typeof item.if === "object"
|
|
205
212
|
);
|
|
206
213
|
}
|
|
214
|
+
function parseSkillSettings(raw) {
|
|
215
|
+
if (!raw || typeof raw !== "object") return {};
|
|
216
|
+
const result = {};
|
|
217
|
+
for (const [skillName, settings] of Object.entries(raw)) {
|
|
218
|
+
if (typeof settings === "object" && settings !== null) {
|
|
219
|
+
const parsed = {};
|
|
220
|
+
if ("useSummary" in settings && typeof settings.useSummary === "boolean") {
|
|
221
|
+
parsed.useSummary = settings.useSummary;
|
|
222
|
+
}
|
|
223
|
+
if (Object.keys(parsed).length > 0) {
|
|
224
|
+
result[skillName] = parsed;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
207
230
|
function loadConfigFile(projectDir) {
|
|
208
231
|
const configPath = findConfigFile(projectDir);
|
|
209
232
|
if (!configPath) {
|
|
@@ -220,11 +243,13 @@ function loadConfigFile(projectDir) {
|
|
|
220
243
|
contentTriggers: parseStringArrayRecord(parsed.contentTriggers),
|
|
221
244
|
groups: parseStringArrayRecord(parsed.groups),
|
|
222
245
|
conditionalSkills: parseConditionalSkills(parsed.conditionalSkills),
|
|
246
|
+
skillSettings: parseSkillSettings(parsed.skillSettings),
|
|
223
247
|
maxTokens: typeof parsed.maxTokens === "number" ? parsed.maxTokens : void 0,
|
|
224
248
|
useSummaries: typeof parsed.useSummaries === "boolean" ? parsed.useSummaries : void 0,
|
|
225
249
|
analytics: typeof parsed.analytics === "boolean" ? parsed.analytics : void 0,
|
|
226
250
|
persistAfterCompaction: typeof parsed.persistAfterCompaction === "boolean" ? parsed.persistAfterCompaction : void 0,
|
|
227
|
-
debug: typeof parsed.debug === "boolean" ? parsed.debug : void 0
|
|
251
|
+
debug: typeof parsed.debug === "boolean" ? parsed.debug : void 0,
|
|
252
|
+
injectionMethod: parsed.injectionMethod === "systemPrompt" || parsed.injectionMethod === "chatMessage" ? parsed.injectionMethod : void 0
|
|
228
253
|
};
|
|
229
254
|
} catch {
|
|
230
255
|
return {};
|
|
@@ -308,6 +333,7 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
308
333
|
lastLoaded: now
|
|
309
334
|
});
|
|
310
335
|
}
|
|
336
|
+
saveAnalytics();
|
|
311
337
|
};
|
|
312
338
|
const saveAnalytics = () => {
|
|
313
339
|
if (!config.analytics) return;
|
|
@@ -376,7 +402,7 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
376
402
|
initialTokensUsed = result.tokensUsed;
|
|
377
403
|
initialFormattedContent = formatSkillsForInjection(
|
|
378
404
|
initialSkills,
|
|
379
|
-
config.useSummaries
|
|
405
|
+
{ useSummaries: config.useSummaries, skillSettings: config.skillSettings }
|
|
380
406
|
);
|
|
381
407
|
const loadedNames = initialSkills.map((s) => s.name);
|
|
382
408
|
const missingNames = allInitialSkillNames.filter(
|
|
@@ -426,7 +452,45 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
426
452
|
});
|
|
427
453
|
}
|
|
428
454
|
};
|
|
455
|
+
const useSystemPromptInjection = config.injectionMethod === "systemPrompt";
|
|
429
456
|
return {
|
|
457
|
+
"experimental.chat.system.transform": useSystemPromptInjection ? async (input, output) => {
|
|
458
|
+
if (!input.sessionID) return;
|
|
459
|
+
const state = getSessionState(input.sessionID);
|
|
460
|
+
const skillsToInject = [];
|
|
461
|
+
if (initialSkills.length > 0) {
|
|
462
|
+
skillsToInject.push(...initialSkills);
|
|
463
|
+
}
|
|
464
|
+
for (const name of state.loadedSkills) {
|
|
465
|
+
const skill = skillCache.get(name);
|
|
466
|
+
if (skill && !skillsToInject.find((s) => s.name === name)) {
|
|
467
|
+
skillsToInject.push(skill);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const pending = pendingSkillInjections.get(input.sessionID);
|
|
471
|
+
if (pending && pending.length > 0) {
|
|
472
|
+
for (const skill of pending) {
|
|
473
|
+
if (!skillsToInject.find((s) => s.name === skill.name)) {
|
|
474
|
+
skillsToInject.push(skill);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
pendingSkillInjections.delete(input.sessionID);
|
|
478
|
+
}
|
|
479
|
+
if (skillsToInject.length > 0) {
|
|
480
|
+
const formatted = formatSkillsForInjection(skillsToInject, {
|
|
481
|
+
useSummaries: config.useSummaries,
|
|
482
|
+
skillSettings: config.skillSettings
|
|
483
|
+
});
|
|
484
|
+
output.system.push(formatted);
|
|
485
|
+
if (!state.initialSkillsInjected && initialSkills.length > 0) {
|
|
486
|
+
state.initialSkillsInjected = true;
|
|
487
|
+
log("info", "Injected skills into system prompt", {
|
|
488
|
+
sessionID: input.sessionID,
|
|
489
|
+
skills: skillsToInject.map((s) => s.name)
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
} : void 0,
|
|
430
494
|
"chat.message": async (input, output) => {
|
|
431
495
|
if (!input.sessionID) return;
|
|
432
496
|
const state = getSessionState(input.sessionID);
|
|
@@ -455,33 +519,38 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
455
519
|
}
|
|
456
520
|
}
|
|
457
521
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
skills: initialSkills.map((s) => s.name)
|
|
465
|
-
});
|
|
466
|
-
}
|
|
467
|
-
const pending = pendingSkillInjections.get(input.sessionID);
|
|
468
|
-
if (pending && pending.length > 0) {
|
|
469
|
-
const formatted = formatSkillsForInjection(pending, config.useSummaries);
|
|
470
|
-
if (formatted) {
|
|
471
|
-
contentToInject.push(formatted);
|
|
472
|
-
log("info", "Injected triggered skills", {
|
|
522
|
+
if (!useSystemPromptInjection) {
|
|
523
|
+
const contentToInject = [];
|
|
524
|
+
if (!state.initialSkillsInjected && initialFormattedContent) {
|
|
525
|
+
contentToInject.push(initialFormattedContent);
|
|
526
|
+
state.initialSkillsInjected = true;
|
|
527
|
+
log("info", "Injected initial preloaded skills", {
|
|
473
528
|
sessionID: input.sessionID,
|
|
474
|
-
skills:
|
|
529
|
+
skills: initialSkills.map((s) => s.name)
|
|
475
530
|
});
|
|
476
531
|
}
|
|
477
|
-
pendingSkillInjections.
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
532
|
+
const pending = pendingSkillInjections.get(input.sessionID);
|
|
533
|
+
if (pending && pending.length > 0) {
|
|
534
|
+
const formatted = formatSkillsForInjection(pending, {
|
|
535
|
+
useSummaries: config.useSummaries,
|
|
536
|
+
skillSettings: config.skillSettings
|
|
537
|
+
});
|
|
538
|
+
if (formatted) {
|
|
539
|
+
contentToInject.push(formatted);
|
|
540
|
+
log("info", "Injected triggered skills", {
|
|
541
|
+
sessionID: input.sessionID,
|
|
542
|
+
skills: pending.map((s) => s.name)
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
pendingSkillInjections.delete(input.sessionID);
|
|
546
|
+
}
|
|
547
|
+
if (contentToInject.length > 0) {
|
|
548
|
+
firstTextPart.text = `${contentToInject.join("\n\n")}
|
|
481
549
|
|
|
482
550
|
---
|
|
483
551
|
|
|
484
552
|
${firstTextPart.text}`;
|
|
553
|
+
}
|
|
485
554
|
}
|
|
486
555
|
},
|
|
487
556
|
"tool.execute.after": async (input, _output) => {
|
|
@@ -518,7 +587,7 @@ ${firstTextPart.text}`;
|
|
|
518
587
|
if (allLoadedSkills.length === 0) return;
|
|
519
588
|
const formatted = formatSkillsForInjection(
|
|
520
589
|
allLoadedSkills,
|
|
521
|
-
config.useSummaries
|
|
590
|
+
{ useSummaries: config.useSummaries, skillSettings: config.skillSettings }
|
|
522
591
|
);
|
|
523
592
|
output.context.push(
|
|
524
593
|
`## Preloaded Skills
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/skill-loader.ts","../src/index.ts"],"names":["join","existsSync","readFileSync","homedir","dirname","mkdirSync","writeFileSync","extname"],"mappings":"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","file":"index.cjs","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n\nexport function matchGlobPattern(filePath: string, pattern: string): boolean {\n let regexPattern = pattern\n .replace(/\\*\\*\\//g, \"\\x00DOUBLESTARSLASH\\x00\")\n .replace(/\\*\\*/g, \"\\x00DOUBLESTAR\\x00\")\n .replace(/\\*/g, \"\\x00SINGLESTAR\\x00\")\n .replace(/\\?/g, \"\\x00QUESTION\\x00\")\n \n regexPattern = regexPattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n \n regexPattern = regexPattern\n .replace(/\\x00DOUBLESTARSLASH\\x00/g, \"(?:[^/]+/)*\")\n .replace(/\\x00DOUBLESTAR\\x00/g, \".*\")\n .replace(/\\x00SINGLESTAR\\x00/g, \"[^/]*\")\n .replace(/\\x00QUESTION\\x00/g, \"[^/]\")\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(filePath)\n}\n\nexport function matchesAnyPattern(\n filePath: string,\n patterns: string[]\n): boolean {\n return patterns.some((pattern) => matchGlobPattern(filePath, pattern))\n}\n\nexport function checkCondition(\n condition: { fileExists?: string; packageHasDependency?: string; envVar?: string },\n projectDir: string\n): boolean {\n if (condition.fileExists) {\n const fullPath = join(projectDir, condition.fileExists)\n if (!existsSync(fullPath)) return false\n }\n\n if (condition.packageHasDependency) {\n const packageJsonPath = join(projectDir, \"package.json\")\n if (!existsSync(packageJsonPath)) return false\n\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"))\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n }\n if (!deps[condition.packageHasDependency]) return false\n } catch {\n return false\n }\n }\n\n if (condition.envVar) {\n if (!process.env[condition.envVar]) return false\n }\n\n return true\n}\n\nexport function extractKeywords(text: string): string[] {\n const words = text.toLowerCase().match(/\\b[a-z]{3,}\\b/g) ?? []\n return [...new Set(words)]\n}\n\nexport function textContainsKeyword(text: string, keywords: string[]): boolean {\n const lowerText = text.toLowerCase()\n return keywords.some((kw) => lowerText.includes(kw.toLowerCase()))\n}\n","import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { ParsedSkill } from \"./types.js\"\nimport { estimateTokens } from \"./utils.js\"\n\nconst SKILL_FILENAME = \"SKILL.md\"\n\nconst SKILL_SEARCH_PATHS = [\n (dir: string) => join(dir, \".opencode\", \"skills\"),\n (dir: string) => join(dir, \".claude\", \"skills\"),\n () => join(homedir(), \".config\", \"opencode\", \"skills\"),\n () => join(homedir(), \".claude\", \"skills\"),\n]\n\nfunction findSkillFile(skillName: string, projectDir: string): string | null {\n for (const getPath of SKILL_SEARCH_PATHS) {\n const skillDir = getPath(projectDir)\n const skillPath = join(skillDir, skillName, SKILL_FILENAME)\n\n if (existsSync(skillPath)) {\n return skillPath\n }\n }\n return null\n}\n\ninterface FrontmatterData {\n name?: string\n description?: string\n summary?: string\n}\n\nfunction parseFrontmatter(content: string): FrontmatterData {\n const frontmatterMatch = content.match(/^---\\s*\\n([\\s\\S]*?)\\n---/)\n if (!frontmatterMatch?.[1]) {\n return {}\n }\n\n const frontmatter = frontmatterMatch[1]\n const result: FrontmatterData = {}\n\n const nameMatch = frontmatter.match(/^name:\\s*(.+)$/m)\n if (nameMatch?.[1]) {\n result.name = nameMatch[1].trim()\n }\n\n const descMatch = frontmatter.match(/^description:\\s*(.+)$/m)\n if (descMatch?.[1]) {\n result.description = descMatch[1].trim()\n }\n\n const summaryMatch = frontmatter.match(/^summary:\\s*(.+)$/m)\n if (summaryMatch?.[1]) {\n result.summary = summaryMatch[1].trim()\n }\n\n return result\n}\n\nfunction extractAutoSummary(content: string, maxLength: number = 500): string {\n const withoutFrontmatter = content.replace(/^---\\s*\\n[\\s\\S]*?\\n---\\s*\\n?/, \"\")\n \n const firstSection = withoutFrontmatter.split(/\\n##\\s/)[0] ?? \"\"\n const cleaned = firstSection\n .replace(/^#\\s+.+\\n?/, \"\")\n .replace(/\\n+/g, \" \")\n .trim()\n\n if (cleaned.length <= maxLength) return cleaned\n return cleaned.slice(0, maxLength).replace(/\\s+\\S*$/, \"\") + \"...\"\n}\n\nexport function loadSkill(skillName: string, projectDir: string): ParsedSkill | null {\n const filePath = findSkillFile(skillName, projectDir)\n\n if (!filePath) {\n return null\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\")\n const { name, description, summary } = parseFrontmatter(content)\n\n return {\n name: name ?? skillName,\n description: description ?? \"\",\n summary: summary ?? extractAutoSummary(content),\n content,\n filePath,\n tokenCount: estimateTokens(content),\n }\n } catch {\n return null\n }\n}\n\nexport function loadSkills(skillNames: string[], projectDir: string): ParsedSkill[] {\n if (!Array.isArray(skillNames)) {\n return []\n }\n\n const skills: ParsedSkill[] = []\n\n for (const name of skillNames) {\n const skill = loadSkill(name, projectDir)\n if (skill) {\n skills.push(skill)\n }\n }\n\n return skills\n}\n\nexport function formatSkillsForInjection(\n skills: ParsedSkill[],\n useSummaries: boolean = false\n): string {\n if (!Array.isArray(skills) || skills.length === 0) {\n return \"\"\n }\n\n const parts = skills.map((skill) => {\n const content = useSummaries && skill.summary ? skill.summary : skill.content\n return `<preloaded-skill name=\"${skill.name}\">\\n${content}\\n</preloaded-skill>`\n })\n\n return `<preloaded-skills>\nThe following skills have been automatically loaded for this session:\n\n${parts.join(\"\\n\\n\")}\n</preloaded-skills>`\n}\n\nexport function calculateTotalTokens(skills: ParsedSkill[]): number {\n return skills.reduce((sum, skill) => sum + skill.tokenCount, 0)\n}\n\nexport function filterSkillsByTokenBudget(\n skills: ParsedSkill[],\n maxTokens: number\n): ParsedSkill[] {\n const result: ParsedSkill[] = []\n let totalTokens = 0\n\n for (const skill of skills) {\n if (totalTokens + skill.tokenCount <= maxTokens) {\n result.push(skill)\n totalTokens += skill.tokenCount\n }\n }\n\n return result\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\"\nimport { join, extname, dirname } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { Plugin, PluginInput } from \"@opencode-ai/plugin\"\nimport type { Event, UserMessage, Part } from \"@opencode-ai/sdk\"\nimport type {\n PreloadSkillsConfig,\n ParsedSkill,\n SessionState,\n ConditionalSkill,\n SkillUsageStats,\n AnalyticsData,\n} from \"./types.js\"\nimport {\n loadSkills,\n formatSkillsForInjection,\n filterSkillsByTokenBudget,\n calculateTotalTokens,\n} from \"./skill-loader.js\"\nimport {\n checkCondition,\n matchGlobPattern,\n textContainsKeyword,\n} from \"./utils.js\"\n\nexport type { PreloadSkillsConfig, ParsedSkill }\nexport { loadSkills, formatSkillsForInjection }\n\nconst CONFIG_FILENAME = \"preload-skills.json\"\nconst ANALYTICS_FILENAME = \"preload-skills-analytics.json\"\nconst FILE_TOOLS = [\"read\", \"edit\", \"write\", \"glob\", \"grep\"]\n\nconst DEFAULT_CONFIG: PreloadSkillsConfig = {\n skills: [],\n fileTypeSkills: {},\n agentSkills: {},\n pathPatterns: {},\n contentTriggers: {},\n groups: {},\n conditionalSkills: [],\n maxTokens: undefined,\n useSummaries: false,\n analytics: false,\n persistAfterCompaction: true,\n debug: false,\n}\n\nfunction findConfigFile(projectDir: string): string | null {\n const locations = [\n join(projectDir, \".opencode\", CONFIG_FILENAME),\n join(projectDir, CONFIG_FILENAME),\n join(homedir(), \".config\", \"opencode\", CONFIG_FILENAME),\n ]\n\n for (const path of locations) {\n if (existsSync(path)) {\n return path\n }\n }\n return null\n}\n\nfunction parseStringArrayRecord(raw: unknown): Record<string, string[]> {\n if (!raw || typeof raw !== \"object\") return {}\n\n const result: Record<string, string[]> = {}\n for (const [key, value] of Object.entries(raw)) {\n if (Array.isArray(value)) {\n result[key] = value.filter((v) => typeof v === \"string\")\n }\n }\n return result\n}\n\nfunction parseConditionalSkills(raw: unknown): ConditionalSkill[] {\n if (!Array.isArray(raw)) return []\n\n return raw.filter(\n (item): item is ConditionalSkill =>\n typeof item === \"object\" &&\n item !== null &&\n typeof item.skill === \"string\" &&\n typeof item.if === \"object\"\n )\n}\n\nfunction loadConfigFile(projectDir: string): Partial<PreloadSkillsConfig> {\n const configPath = findConfigFile(projectDir)\n if (!configPath) {\n return {}\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\")\n const parsed = JSON.parse(content) as Record<string, unknown>\n\n return {\n skills: Array.isArray(parsed.skills) ? parsed.skills : [],\n fileTypeSkills: parseStringArrayRecord(parsed.fileTypeSkills),\n agentSkills: parseStringArrayRecord(parsed.agentSkills),\n pathPatterns: parseStringArrayRecord(parsed.pathPatterns),\n contentTriggers: parseStringArrayRecord(parsed.contentTriggers),\n groups: parseStringArrayRecord(parsed.groups),\n conditionalSkills: parseConditionalSkills(parsed.conditionalSkills),\n maxTokens:\n typeof parsed.maxTokens === \"number\" ? parsed.maxTokens : undefined,\n useSummaries:\n typeof parsed.useSummaries === \"boolean\"\n ? parsed.useSummaries\n : undefined,\n analytics:\n typeof parsed.analytics === \"boolean\" ? parsed.analytics : undefined,\n persistAfterCompaction:\n typeof parsed.persistAfterCompaction === \"boolean\"\n ? parsed.persistAfterCompaction\n : undefined,\n debug: typeof parsed.debug === \"boolean\" ? parsed.debug : undefined,\n }\n } catch {\n return {}\n }\n}\n\nfunction getFilePathFromArgs(args: Record<string, unknown>): string | null {\n if (typeof args.filePath === \"string\") return args.filePath\n if (typeof args.path === \"string\") return args.path\n if (typeof args.file === \"string\") return args.file\n return null\n}\n\nfunction getSkillsForExtension(\n ext: string,\n fileTypeSkills: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(fileTypeSkills)) {\n const extensions = pattern.split(\",\").map((e) => e.trim().toLowerCase())\n if (extensions.includes(ext.toLowerCase())) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction getSkillsForPath(\n filePath: string,\n pathPatterns: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(pathPatterns)) {\n if (matchGlobPattern(filePath, pattern)) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction resolveSkillGroups(\n skillNames: string[],\n groups: Record<string, string[]>\n): string[] {\n const resolved: string[] = []\n\n for (const name of skillNames) {\n if (name.startsWith(\"@\") && groups[name.slice(1)]) {\n resolved.push(...groups[name.slice(1)]!)\n } else {\n resolved.push(name)\n }\n }\n\n return [...new Set(resolved)]\n}\n\nexport const PreloadSkillsPlugin: Plugin = async (ctx: PluginInput) => {\n const sessionStates = new Map<string, SessionState>()\n const analyticsData = new Map<string, AnalyticsData>()\n\n const fileConfig = loadConfigFile(ctx.directory)\n const config: PreloadSkillsConfig = {\n ...DEFAULT_CONFIG,\n ...fileConfig,\n }\n\n const log = (\n level: \"debug\" | \"info\" | \"warn\" | \"error\",\n message: string,\n extra?: Record<string, unknown>\n ) => {\n if (level === \"debug\" && !config.debug) return\n\n ctx.client.app.log({\n body: {\n service: \"preload-skills\",\n level,\n message,\n extra,\n },\n })\n }\n\n const trackSkillUsage = (\n sessionID: string,\n skillName: string,\n triggerType: SkillUsageStats[\"triggerType\"]\n ) => {\n if (!config.analytics) return\n\n if (!analyticsData.has(sessionID)) {\n analyticsData.set(sessionID, {\n sessionId: sessionID,\n skillUsage: new Map(),\n })\n }\n\n const data = analyticsData.get(sessionID)!\n const now = Date.now()\n\n if (data.skillUsage.has(skillName)) {\n const stats = data.skillUsage.get(skillName)!\n stats.loadCount++\n stats.lastLoaded = now\n } else {\n data.skillUsage.set(skillName, {\n skillName,\n loadCount: 1,\n triggerType,\n firstLoaded: now,\n lastLoaded: now,\n })\n }\n }\n\n const saveAnalytics = () => {\n if (!config.analytics) return\n\n try {\n const analyticsPath = join(ctx.directory, \".opencode\", ANALYTICS_FILENAME)\n const dir = dirname(analyticsPath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n\n const serializable: Record<string, unknown> = {}\n for (const [sessionId, data] of analyticsData) {\n serializable[sessionId] = {\n sessionId: data.sessionId,\n skillUsage: Object.fromEntries(data.skillUsage),\n }\n }\n\n writeFileSync(analyticsPath, JSON.stringify(serializable, null, 2))\n } catch {\n log(\"warn\", \"Failed to save analytics\")\n }\n }\n\n const skillCache = new Map<string, ParsedSkill>()\n\n const loadSkillsWithBudget = (\n skillNames: string[],\n currentTokens: number,\n triggerType: SkillUsageStats[\"triggerType\"],\n sessionID: string\n ): { skills: ParsedSkill[]; tokensUsed: number } => {\n const resolved = resolveSkillGroups(skillNames, config.groups ?? {})\n let skills = loadSkills(resolved, ctx.directory)\n\n for (const skill of skills) {\n skillCache.set(skill.name, skill)\n }\n\n if (config.maxTokens) {\n const remainingBudget = config.maxTokens - currentTokens\n skills = filterSkillsByTokenBudget(skills, remainingBudget)\n }\n\n for (const skill of skills) {\n trackSkillUsage(sessionID, skill.name, triggerType)\n }\n\n return {\n skills,\n tokensUsed: calculateTotalTokens(skills),\n }\n }\n\n const resolveConditionalSkills = (): string[] => {\n if (!config.conditionalSkills?.length) return []\n\n const resolved: string[] = []\n for (const { skill, if: condition } of config.conditionalSkills) {\n if (checkCondition(condition, ctx.directory)) {\n resolved.push(skill)\n }\n }\n\n return resolved\n }\n\n let initialSkills: ParsedSkill[] = []\n let initialFormattedContent = \"\"\n let initialTokensUsed = 0\n\n const allInitialSkillNames = [\n ...config.skills,\n ...resolveConditionalSkills(),\n ]\n\n if (allInitialSkillNames.length > 0) {\n const result = loadSkillsWithBudget(\n allInitialSkillNames,\n 0,\n \"initial\",\n \"__init__\"\n )\n initialSkills = result.skills\n initialTokensUsed = result.tokensUsed\n initialFormattedContent = formatSkillsForInjection(\n initialSkills,\n config.useSummaries\n )\n\n const loadedNames = initialSkills.map((s) => s.name)\n const missingNames = allInitialSkillNames.filter(\n (s) => !loadedNames.includes(s) && !s.startsWith(\"@\")\n )\n\n log(\"info\", `Loaded ${initialSkills.length} initial skills`, {\n loaded: loadedNames,\n tokens: initialTokensUsed,\n missing: missingNames.length > 0 ? missingNames : undefined,\n })\n }\n\n const hasTriggeredSkills =\n Object.keys(config.fileTypeSkills ?? {}).length > 0 ||\n Object.keys(config.agentSkills ?? {}).length > 0 ||\n Object.keys(config.pathPatterns ?? {}).length > 0 ||\n Object.keys(config.contentTriggers ?? {}).length > 0\n\n if (allInitialSkillNames.length === 0 && !hasTriggeredSkills) {\n log(\"warn\", \"No skills configured. Create .opencode/preload-skills.json\")\n }\n\n const getSessionState = (sessionID: string): SessionState => {\n if (!sessionStates.has(sessionID)) {\n sessionStates.set(sessionID, {\n initialSkillsInjected: false,\n loadedSkills: new Set(initialSkills.map((s) => s.name)),\n totalTokensUsed: initialTokensUsed,\n })\n }\n return sessionStates.get(sessionID)!\n }\n\n const pendingSkillInjections = new Map<string, ParsedSkill[]>()\n\n const queueSkillsForInjection = (\n sessionID: string,\n skillNames: string[],\n triggerType: SkillUsageStats[\"triggerType\"],\n state: SessionState\n ) => {\n const newSkillNames = skillNames.filter((name) => !state.loadedSkills.has(name))\n if (newSkillNames.length === 0) return\n\n const result = loadSkillsWithBudget(\n newSkillNames,\n state.totalTokensUsed,\n triggerType,\n sessionID\n )\n\n if (result.skills.length > 0) {\n for (const skill of result.skills) {\n state.loadedSkills.add(skill.name)\n }\n state.totalTokensUsed += result.tokensUsed\n\n const existing = pendingSkillInjections.get(sessionID) ?? []\n pendingSkillInjections.set(sessionID, [...existing, ...result.skills])\n\n log(\"debug\", `Queued ${triggerType} skills for injection`, {\n sessionID,\n skills: result.skills.map((s) => s.name),\n tokens: result.tokensUsed,\n })\n }\n }\n\n return {\n \"chat.message\": async (\n input: {\n sessionID: string\n agent?: string\n model?: { providerID: string; modelID: string }\n messageID?: string\n variant?: string\n },\n output: { message: UserMessage; parts: Part[] }\n ): Promise<void> => {\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n const firstTextPart = output.parts.find((p) => p.type === \"text\")\n if (!firstTextPart || !(\"text\" in firstTextPart)) return\n\n const messageText = firstTextPart.text\n\n if (input.agent && config.agentSkills?.[input.agent]) {\n queueSkillsForInjection(\n input.sessionID,\n config.agentSkills[input.agent]!,\n \"agent\",\n state\n )\n }\n\n if (config.contentTriggers) {\n for (const [keyword, skillNames] of Object.entries(\n config.contentTriggers\n )) {\n if (textContainsKeyword(messageText, [keyword])) {\n queueSkillsForInjection(\n input.sessionID,\n skillNames,\n \"content\",\n state\n )\n }\n }\n }\n\n const contentToInject: string[] = []\n\n if (!state.initialSkillsInjected && initialFormattedContent) {\n contentToInject.push(initialFormattedContent)\n state.initialSkillsInjected = true\n log(\"info\", \"Injected initial preloaded skills\", {\n sessionID: input.sessionID,\n skills: initialSkills.map((s) => s.name),\n })\n }\n\n const pending = pendingSkillInjections.get(input.sessionID)\n if (pending && pending.length > 0) {\n const formatted = formatSkillsForInjection(pending, config.useSummaries)\n if (formatted) {\n contentToInject.push(formatted)\n log(\"info\", \"Injected triggered skills\", {\n sessionID: input.sessionID,\n skills: pending.map((s) => s.name),\n })\n }\n pendingSkillInjections.delete(input.sessionID)\n }\n\n if (contentToInject.length > 0) {\n firstTextPart.text = `${contentToInject.join(\"\\n\\n\")}\\n\\n---\\n\\n${firstTextPart.text}`\n }\n },\n\n \"tool.execute.after\": async (\n input: {\n tool: string\n sessionID: string\n callID: string\n },\n _output: {\n title: string\n output: string\n metadata: unknown\n }\n ): Promise<void> => {\n if (!FILE_TOOLS.includes(input.tool)) return\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n\n const toolArgs = (_output.metadata as { args?: Record<string, unknown> })\n ?.args\n if (!toolArgs) return\n\n const filePath = getFilePathFromArgs(toolArgs)\n if (!filePath) return\n\n const ext = extname(filePath)\n if (ext && config.fileTypeSkills) {\n const extSkills = getSkillsForExtension(ext, config.fileTypeSkills)\n if (extSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, extSkills, \"fileType\", state)\n }\n }\n\n if (config.pathPatterns) {\n const pathSkills = getSkillsForPath(filePath, config.pathPatterns)\n if (pathSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, pathSkills, \"path\", state)\n }\n }\n },\n\n \"experimental.session.compacting\": async (\n input: { sessionID: string },\n output: { context: string[]; prompt?: string }\n ): Promise<void> => {\n if (!config.persistAfterCompaction) return\n\n const state = sessionStates.get(input.sessionID)\n if (!state || state.loadedSkills.size === 0) return\n\n const allLoadedSkills: ParsedSkill[] = []\n for (const name of state.loadedSkills) {\n const skill = skillCache.get(name)\n if (skill) allLoadedSkills.push(skill)\n }\n\n if (allLoadedSkills.length === 0) return\n\n const formatted = formatSkillsForInjection(\n allLoadedSkills,\n config.useSummaries\n )\n output.context.push(\n `## Preloaded Skills\\n\\nThe following skills were loaded during this session and should persist:\\n\\n${formatted}`\n )\n\n state.initialSkillsInjected = false\n\n log(\"info\", \"Added all loaded skills to compaction context\", {\n sessionID: input.sessionID,\n skillCount: allLoadedSkills.length,\n })\n\n saveAnalytics()\n },\n\n event: async ({ event }: { event: Event }): Promise<void> => {\n if (\n event.type === \"session.deleted\" &&\n \"sessionID\" in event.properties\n ) {\n const sessionID = event.properties.sessionID as string\n sessionStates.delete(sessionID)\n pendingSkillInjections.delete(sessionID)\n analyticsData.delete(sessionID)\n log(\"debug\", \"Cleaned up session state\", { sessionID })\n saveAnalytics()\n }\n },\n }\n}\n\nexport default PreloadSkillsPlugin\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/skill-loader.ts","../src/index.ts"],"names":["join","existsSync","readFileSync","homedir","dirname","mkdirSync","writeFileSync","extname"],"mappings":"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","file":"index.cjs","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n\nexport function matchGlobPattern(filePath: string, pattern: string): boolean {\n let regexPattern = pattern\n .replace(/\\*\\*\\//g, \"\\x00DOUBLESTARSLASH\\x00\")\n .replace(/\\*\\*/g, \"\\x00DOUBLESTAR\\x00\")\n .replace(/\\*/g, \"\\x00SINGLESTAR\\x00\")\n .replace(/\\?/g, \"\\x00QUESTION\\x00\")\n \n regexPattern = regexPattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n \n regexPattern = regexPattern\n .replace(/\\x00DOUBLESTARSLASH\\x00/g, \"(?:[^/]+/)*\")\n .replace(/\\x00DOUBLESTAR\\x00/g, \".*\")\n .replace(/\\x00SINGLESTAR\\x00/g, \"[^/]*\")\n .replace(/\\x00QUESTION\\x00/g, \"[^/]\")\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(filePath)\n}\n\nexport function matchesAnyPattern(\n filePath: string,\n patterns: string[]\n): boolean {\n return patterns.some((pattern) => matchGlobPattern(filePath, pattern))\n}\n\nexport function checkCondition(\n condition: { fileExists?: string; packageHasDependency?: string; envVar?: string },\n projectDir: string\n): boolean {\n if (condition.fileExists) {\n const fullPath = join(projectDir, condition.fileExists)\n if (!existsSync(fullPath)) return false\n }\n\n if (condition.packageHasDependency) {\n const packageJsonPath = join(projectDir, \"package.json\")\n if (!existsSync(packageJsonPath)) return false\n\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"))\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n }\n if (!deps[condition.packageHasDependency]) return false\n } catch {\n return false\n }\n }\n\n if (condition.envVar) {\n if (!process.env[condition.envVar]) return false\n }\n\n return true\n}\n\nexport function extractKeywords(text: string): string[] {\n const words = text.toLowerCase().match(/\\b[a-z]{3,}\\b/g) ?? []\n return [...new Set(words)]\n}\n\nexport function textContainsKeyword(text: string, keywords: string[]): boolean {\n const lowerText = text.toLowerCase()\n return keywords.some((kw) => lowerText.includes(kw.toLowerCase()))\n}\n","import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { ParsedSkill, SkillSettings } from \"./types.js\"\nimport { estimateTokens } from \"./utils.js\"\n\nconst SKILL_FILENAME = \"SKILL.md\"\n\nconst SKILL_SEARCH_PATHS = [\n (dir: string) => join(dir, \".opencode\", \"skills\"),\n (dir: string) => join(dir, \".claude\", \"skills\"),\n () => join(homedir(), \".config\", \"opencode\", \"skills\"),\n () => join(homedir(), \".claude\", \"skills\"),\n]\n\nfunction findSkillFile(skillName: string, projectDir: string): string | null {\n for (const getPath of SKILL_SEARCH_PATHS) {\n const skillDir = getPath(projectDir)\n const skillPath = join(skillDir, skillName, SKILL_FILENAME)\n\n if (existsSync(skillPath)) {\n return skillPath\n }\n }\n return null\n}\n\ninterface FrontmatterData {\n name?: string\n description?: string\n summary?: string\n}\n\nfunction parseFrontmatter(content: string): FrontmatterData {\n const frontmatterMatch = content.match(/^---\\s*\\n([\\s\\S]*?)\\n---/)\n if (!frontmatterMatch?.[1]) {\n return {}\n }\n\n const frontmatter = frontmatterMatch[1]\n const result: FrontmatterData = {}\n\n const nameMatch = frontmatter.match(/^name:\\s*(.+)$/m)\n if (nameMatch?.[1]) {\n result.name = nameMatch[1].trim()\n }\n\n const descMatch = frontmatter.match(/^description:\\s*(.+)$/m)\n if (descMatch?.[1]) {\n result.description = descMatch[1].trim()\n }\n\n const summaryMatch = frontmatter.match(/^summary:\\s*(.+)$/m)\n if (summaryMatch?.[1]) {\n result.summary = summaryMatch[1].trim()\n }\n\n return result\n}\n\nfunction extractAutoSummary(content: string, maxLength: number = 500): string {\n const withoutFrontmatter = content.replace(/^---\\s*\\n[\\s\\S]*?\\n---\\s*\\n?/, \"\")\n \n const firstSection = withoutFrontmatter.split(/\\n##\\s/)[0] ?? \"\"\n const cleaned = firstSection\n .replace(/^#\\s+.+\\n?/, \"\")\n .replace(/\\n+/g, \" \")\n .trim()\n\n if (cleaned.length <= maxLength) return cleaned\n return cleaned.slice(0, maxLength).replace(/\\s+\\S*$/, \"\") + \"...\"\n}\n\nexport function loadSkill(skillName: string, projectDir: string): ParsedSkill | null {\n const filePath = findSkillFile(skillName, projectDir)\n\n if (!filePath) {\n return null\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\")\n const { name, description, summary } = parseFrontmatter(content)\n\n return {\n name: name ?? skillName,\n description: description ?? \"\",\n summary: summary ?? extractAutoSummary(content),\n content,\n filePath,\n tokenCount: estimateTokens(content),\n }\n } catch {\n return null\n }\n}\n\nexport function loadSkills(skillNames: string[], projectDir: string): ParsedSkill[] {\n if (!Array.isArray(skillNames)) {\n return []\n }\n\n const skills: ParsedSkill[] = []\n\n for (const name of skillNames) {\n const skill = loadSkill(name, projectDir)\n if (skill) {\n skills.push(skill)\n }\n }\n\n return skills\n}\n\nexport interface FormatOptions {\n useSummaries?: boolean\n skillSettings?: Record<string, SkillSettings>\n}\n\nexport function formatSkillsForInjection(\n skills: ParsedSkill[],\n options: boolean | FormatOptions = false\n): string {\n if (!Array.isArray(skills) || skills.length === 0) {\n return \"\"\n }\n\n const opts: FormatOptions = typeof options === \"boolean\" \n ? { useSummaries: options } \n : options\n \n const globalUseSummaries = opts.useSummaries ?? false\n const skillSettings = opts.skillSettings ?? {}\n\n const parts = skills.map((skill) => {\n const perSkillSetting = skillSettings[skill.name]?.useSummary\n const shouldUseSummary = perSkillSetting ?? globalUseSummaries\n const content = shouldUseSummary && skill.summary ? skill.summary : skill.content\n return `<preloaded-skill name=\"${skill.name}\">\\n${content}\\n</preloaded-skill>`\n })\n\n return `<preloaded-skills>\nThe following skills have been automatically loaded for this session:\n\n${parts.join(\"\\n\\n\")}\n</preloaded-skills>`\n}\n\nexport function calculateTotalTokens(skills: ParsedSkill[]): number {\n return skills.reduce((sum, skill) => sum + skill.tokenCount, 0)\n}\n\nexport function filterSkillsByTokenBudget(\n skills: ParsedSkill[],\n maxTokens: number\n): ParsedSkill[] {\n const result: ParsedSkill[] = []\n let totalTokens = 0\n\n for (const skill of skills) {\n if (totalTokens + skill.tokenCount <= maxTokens) {\n result.push(skill)\n totalTokens += skill.tokenCount\n }\n }\n\n return result\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\"\nimport { join, extname, dirname } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { Plugin, PluginInput } from \"@opencode-ai/plugin\"\nimport type { Event, UserMessage, Part, Model } from \"@opencode-ai/sdk\"\nimport type {\n PreloadSkillsConfig,\n ParsedSkill,\n SessionState,\n ConditionalSkill,\n SkillSettings,\n SkillUsageStats,\n AnalyticsData,\n InjectionMethod,\n} from \"./types.js\"\nimport {\n loadSkills,\n formatSkillsForInjection,\n filterSkillsByTokenBudget,\n calculateTotalTokens,\n} from \"./skill-loader.js\"\nimport {\n checkCondition,\n matchGlobPattern,\n textContainsKeyword,\n} from \"./utils.js\"\n\nexport type { PreloadSkillsConfig, ParsedSkill }\nexport { loadSkills, formatSkillsForInjection }\n\nconst CONFIG_FILENAME = \"preload-skills.json\"\nconst ANALYTICS_FILENAME = \"preload-skills-analytics.json\"\nconst FILE_TOOLS = [\"read\", \"edit\", \"write\", \"glob\", \"grep\"]\n\nconst DEFAULT_CONFIG: PreloadSkillsConfig = {\n skills: [],\n fileTypeSkills: {},\n agentSkills: {},\n pathPatterns: {},\n contentTriggers: {},\n groups: {},\n conditionalSkills: [],\n skillSettings: {},\n injectionMethod: \"chatMessage\",\n maxTokens: undefined,\n useSummaries: false,\n analytics: false,\n persistAfterCompaction: true,\n debug: false,\n}\n\nfunction findConfigFile(projectDir: string): string | null {\n const locations = [\n join(projectDir, \".opencode\", CONFIG_FILENAME),\n join(projectDir, CONFIG_FILENAME),\n join(homedir(), \".config\", \"opencode\", CONFIG_FILENAME),\n ]\n\n for (const path of locations) {\n if (existsSync(path)) {\n return path\n }\n }\n return null\n}\n\nfunction parseStringArrayRecord(raw: unknown): Record<string, string[]> {\n if (!raw || typeof raw !== \"object\") return {}\n\n const result: Record<string, string[]> = {}\n for (const [key, value] of Object.entries(raw)) {\n if (Array.isArray(value)) {\n result[key] = value.filter((v) => typeof v === \"string\")\n }\n }\n return result\n}\n\nfunction parseConditionalSkills(raw: unknown): ConditionalSkill[] {\n if (!Array.isArray(raw)) return []\n\n return raw.filter(\n (item): item is ConditionalSkill =>\n typeof item === \"object\" &&\n item !== null &&\n typeof item.skill === \"string\" &&\n typeof item.if === \"object\"\n )\n}\n\nfunction parseSkillSettings(raw: unknown): Record<string, SkillSettings> {\n if (!raw || typeof raw !== \"object\") return {}\n\n const result: Record<string, SkillSettings> = {}\n for (const [skillName, settings] of Object.entries(raw)) {\n if (typeof settings === \"object\" && settings !== null) {\n const parsed: SkillSettings = {}\n if (\"useSummary\" in settings && typeof settings.useSummary === \"boolean\") {\n parsed.useSummary = settings.useSummary\n }\n if (Object.keys(parsed).length > 0) {\n result[skillName] = parsed\n }\n }\n }\n return result\n}\n\nfunction loadConfigFile(projectDir: string): Partial<PreloadSkillsConfig> {\n const configPath = findConfigFile(projectDir)\n if (!configPath) {\n return {}\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\")\n const parsed = JSON.parse(content) as Record<string, unknown>\n\n return {\n skills: Array.isArray(parsed.skills) ? parsed.skills : [],\n fileTypeSkills: parseStringArrayRecord(parsed.fileTypeSkills),\n agentSkills: parseStringArrayRecord(parsed.agentSkills),\n pathPatterns: parseStringArrayRecord(parsed.pathPatterns),\n contentTriggers: parseStringArrayRecord(parsed.contentTriggers),\n groups: parseStringArrayRecord(parsed.groups),\n conditionalSkills: parseConditionalSkills(parsed.conditionalSkills),\n skillSettings: parseSkillSettings(parsed.skillSettings),\n maxTokens:\n typeof parsed.maxTokens === \"number\" ? parsed.maxTokens : undefined,\n useSummaries:\n typeof parsed.useSummaries === \"boolean\"\n ? parsed.useSummaries\n : undefined,\n analytics:\n typeof parsed.analytics === \"boolean\" ? parsed.analytics : undefined,\n persistAfterCompaction:\n typeof parsed.persistAfterCompaction === \"boolean\"\n ? parsed.persistAfterCompaction\n : undefined,\n debug: typeof parsed.debug === \"boolean\" ? parsed.debug : undefined,\n injectionMethod:\n parsed.injectionMethod === \"systemPrompt\" ||\n parsed.injectionMethod === \"chatMessage\"\n ? (parsed.injectionMethod as InjectionMethod)\n : undefined,\n }\n } catch {\n return {}\n }\n}\n\nfunction getFilePathFromArgs(args: Record<string, unknown>): string | null {\n if (typeof args.filePath === \"string\") return args.filePath\n if (typeof args.path === \"string\") return args.path\n if (typeof args.file === \"string\") return args.file\n return null\n}\n\nfunction getSkillsForExtension(\n ext: string,\n fileTypeSkills: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(fileTypeSkills)) {\n const extensions = pattern.split(\",\").map((e) => e.trim().toLowerCase())\n if (extensions.includes(ext.toLowerCase())) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction getSkillsForPath(\n filePath: string,\n pathPatterns: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(pathPatterns)) {\n if (matchGlobPattern(filePath, pattern)) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction resolveSkillGroups(\n skillNames: string[],\n groups: Record<string, string[]>\n): string[] {\n const resolved: string[] = []\n\n for (const name of skillNames) {\n if (name.startsWith(\"@\") && groups[name.slice(1)]) {\n resolved.push(...groups[name.slice(1)]!)\n } else {\n resolved.push(name)\n }\n }\n\n return [...new Set(resolved)]\n}\n\nexport const PreloadSkillsPlugin: Plugin = async (ctx: PluginInput) => {\n const sessionStates = new Map<string, SessionState>()\n const analyticsData = new Map<string, AnalyticsData>()\n\n const fileConfig = loadConfigFile(ctx.directory)\n const config: PreloadSkillsConfig = {\n ...DEFAULT_CONFIG,\n ...fileConfig,\n }\n\n const log = (\n level: \"debug\" | \"info\" | \"warn\" | \"error\",\n message: string,\n extra?: Record<string, unknown>\n ) => {\n if (level === \"debug\" && !config.debug) return\n\n ctx.client.app.log({\n body: {\n service: \"preload-skills\",\n level,\n message,\n extra,\n },\n })\n }\n\n const trackSkillUsage = (\n sessionID: string,\n skillName: string,\n triggerType: SkillUsageStats[\"triggerType\"]\n ) => {\n if (!config.analytics) return\n\n if (!analyticsData.has(sessionID)) {\n analyticsData.set(sessionID, {\n sessionId: sessionID,\n skillUsage: new Map(),\n })\n }\n\n const data = analyticsData.get(sessionID)!\n const now = Date.now()\n\n if (data.skillUsage.has(skillName)) {\n const stats = data.skillUsage.get(skillName)!\n stats.loadCount++\n stats.lastLoaded = now\n } else {\n data.skillUsage.set(skillName, {\n skillName,\n loadCount: 1,\n triggerType,\n firstLoaded: now,\n lastLoaded: now,\n })\n }\n\n saveAnalytics()\n }\n\n const saveAnalytics = () => {\n if (!config.analytics) return\n\n try {\n const analyticsPath = join(ctx.directory, \".opencode\", ANALYTICS_FILENAME)\n const dir = dirname(analyticsPath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n\n const serializable: Record<string, unknown> = {}\n for (const [sessionId, data] of analyticsData) {\n serializable[sessionId] = {\n sessionId: data.sessionId,\n skillUsage: Object.fromEntries(data.skillUsage),\n }\n }\n\n writeFileSync(analyticsPath, JSON.stringify(serializable, null, 2))\n } catch {\n log(\"warn\", \"Failed to save analytics\")\n }\n }\n\n const skillCache = new Map<string, ParsedSkill>()\n\n const loadSkillsWithBudget = (\n skillNames: string[],\n currentTokens: number,\n triggerType: SkillUsageStats[\"triggerType\"],\n sessionID: string\n ): { skills: ParsedSkill[]; tokensUsed: number } => {\n const resolved = resolveSkillGroups(skillNames, config.groups ?? {})\n let skills = loadSkills(resolved, ctx.directory)\n\n for (const skill of skills) {\n skillCache.set(skill.name, skill)\n }\n\n if (config.maxTokens) {\n const remainingBudget = config.maxTokens - currentTokens\n skills = filterSkillsByTokenBudget(skills, remainingBudget)\n }\n\n for (const skill of skills) {\n trackSkillUsage(sessionID, skill.name, triggerType)\n }\n\n return {\n skills,\n tokensUsed: calculateTotalTokens(skills),\n }\n }\n\n const resolveConditionalSkills = (): string[] => {\n if (!config.conditionalSkills?.length) return []\n\n const resolved: string[] = []\n for (const { skill, if: condition } of config.conditionalSkills) {\n if (checkCondition(condition, ctx.directory)) {\n resolved.push(skill)\n }\n }\n\n return resolved\n }\n\n let initialSkills: ParsedSkill[] = []\n let initialFormattedContent = \"\"\n let initialTokensUsed = 0\n\n const allInitialSkillNames = [\n ...config.skills,\n ...resolveConditionalSkills(),\n ]\n\n if (allInitialSkillNames.length > 0) {\n const result = loadSkillsWithBudget(\n allInitialSkillNames,\n 0,\n \"initial\",\n \"__init__\"\n )\n initialSkills = result.skills\n initialTokensUsed = result.tokensUsed\n initialFormattedContent = formatSkillsForInjection(\n initialSkills,\n { useSummaries: config.useSummaries, skillSettings: config.skillSettings }\n )\n\n const loadedNames = initialSkills.map((s) => s.name)\n const missingNames = allInitialSkillNames.filter(\n (s) => !loadedNames.includes(s) && !s.startsWith(\"@\")\n )\n\n log(\"info\", `Loaded ${initialSkills.length} initial skills`, {\n loaded: loadedNames,\n tokens: initialTokensUsed,\n missing: missingNames.length > 0 ? missingNames : undefined,\n })\n }\n\n const hasTriggeredSkills =\n Object.keys(config.fileTypeSkills ?? {}).length > 0 ||\n Object.keys(config.agentSkills ?? {}).length > 0 ||\n Object.keys(config.pathPatterns ?? {}).length > 0 ||\n Object.keys(config.contentTriggers ?? {}).length > 0\n\n if (allInitialSkillNames.length === 0 && !hasTriggeredSkills) {\n log(\"warn\", \"No skills configured. Create .opencode/preload-skills.json\")\n }\n\n const getSessionState = (sessionID: string): SessionState => {\n if (!sessionStates.has(sessionID)) {\n sessionStates.set(sessionID, {\n initialSkillsInjected: false,\n loadedSkills: new Set(initialSkills.map((s) => s.name)),\n totalTokensUsed: initialTokensUsed,\n })\n }\n return sessionStates.get(sessionID)!\n }\n\n const pendingSkillInjections = new Map<string, ParsedSkill[]>()\n\n const queueSkillsForInjection = (\n sessionID: string,\n skillNames: string[],\n triggerType: SkillUsageStats[\"triggerType\"],\n state: SessionState\n ) => {\n const newSkillNames = skillNames.filter((name) => !state.loadedSkills.has(name))\n if (newSkillNames.length === 0) return\n\n const result = loadSkillsWithBudget(\n newSkillNames,\n state.totalTokensUsed,\n triggerType,\n sessionID\n )\n\n if (result.skills.length > 0) {\n for (const skill of result.skills) {\n state.loadedSkills.add(skill.name)\n }\n state.totalTokensUsed += result.tokensUsed\n\n const existing = pendingSkillInjections.get(sessionID) ?? []\n pendingSkillInjections.set(sessionID, [...existing, ...result.skills])\n\n log(\"debug\", `Queued ${triggerType} skills for injection`, {\n sessionID,\n skills: result.skills.map((s) => s.name),\n tokens: result.tokensUsed,\n })\n }\n }\n\n const useSystemPromptInjection = config.injectionMethod === \"systemPrompt\"\n\n return {\n \"experimental.chat.system.transform\": useSystemPromptInjection\n ? async (\n input: { sessionID?: string; model: Model },\n output: { system: string[] }\n ): Promise<void> => {\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n const skillsToInject: ParsedSkill[] = []\n\n if (initialSkills.length > 0) {\n skillsToInject.push(...initialSkills)\n }\n\n for (const name of state.loadedSkills) {\n const skill = skillCache.get(name)\n if (skill && !skillsToInject.find((s) => s.name === name)) {\n skillsToInject.push(skill)\n }\n }\n\n const pending = pendingSkillInjections.get(input.sessionID)\n if (pending && pending.length > 0) {\n for (const skill of pending) {\n if (!skillsToInject.find((s) => s.name === skill.name)) {\n skillsToInject.push(skill)\n }\n }\n pendingSkillInjections.delete(input.sessionID)\n }\n\n if (skillsToInject.length > 0) {\n const formatted = formatSkillsForInjection(skillsToInject, {\n useSummaries: config.useSummaries,\n skillSettings: config.skillSettings,\n })\n output.system.push(formatted)\n\n if (!state.initialSkillsInjected && initialSkills.length > 0) {\n state.initialSkillsInjected = true\n log(\"info\", \"Injected skills into system prompt\", {\n sessionID: input.sessionID,\n skills: skillsToInject.map((s) => s.name),\n })\n }\n }\n }\n : undefined,\n\n \"chat.message\": async (\n input: {\n sessionID: string\n agent?: string\n model?: { providerID: string; modelID: string }\n messageID?: string\n variant?: string\n },\n output: { message: UserMessage; parts: Part[] }\n ): Promise<void> => {\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n const firstTextPart = output.parts.find((p) => p.type === \"text\")\n if (!firstTextPart || !(\"text\" in firstTextPart)) return\n\n const messageText = firstTextPart.text\n\n if (input.agent && config.agentSkills?.[input.agent]) {\n queueSkillsForInjection(\n input.sessionID,\n config.agentSkills[input.agent]!,\n \"agent\",\n state\n )\n }\n\n if (config.contentTriggers) {\n for (const [keyword, skillNames] of Object.entries(\n config.contentTriggers\n )) {\n if (textContainsKeyword(messageText, [keyword])) {\n queueSkillsForInjection(\n input.sessionID,\n skillNames,\n \"content\",\n state\n )\n }\n }\n }\n\n if (!useSystemPromptInjection) {\n const contentToInject: string[] = []\n\n if (!state.initialSkillsInjected && initialFormattedContent) {\n contentToInject.push(initialFormattedContent)\n state.initialSkillsInjected = true\n log(\"info\", \"Injected initial preloaded skills\", {\n sessionID: input.sessionID,\n skills: initialSkills.map((s) => s.name),\n })\n }\n\n const pending = pendingSkillInjections.get(input.sessionID)\n if (pending && pending.length > 0) {\n const formatted = formatSkillsForInjection(pending, {\n useSummaries: config.useSummaries,\n skillSettings: config.skillSettings,\n })\n if (formatted) {\n contentToInject.push(formatted)\n log(\"info\", \"Injected triggered skills\", {\n sessionID: input.sessionID,\n skills: pending.map((s) => s.name),\n })\n }\n pendingSkillInjections.delete(input.sessionID)\n }\n\n if (contentToInject.length > 0) {\n firstTextPart.text = `${contentToInject.join(\"\\n\\n\")}\\n\\n---\\n\\n${firstTextPart.text}`\n }\n }\n },\n\n \"tool.execute.after\": async (\n input: {\n tool: string\n sessionID: string\n callID: string\n },\n _output: {\n title: string\n output: string\n metadata: unknown\n }\n ): Promise<void> => {\n if (!FILE_TOOLS.includes(input.tool)) return\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n\n const toolArgs = (_output.metadata as { args?: Record<string, unknown> })\n ?.args\n if (!toolArgs) return\n\n const filePath = getFilePathFromArgs(toolArgs)\n if (!filePath) return\n\n const ext = extname(filePath)\n if (ext && config.fileTypeSkills) {\n const extSkills = getSkillsForExtension(ext, config.fileTypeSkills)\n if (extSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, extSkills, \"fileType\", state)\n }\n }\n\n if (config.pathPatterns) {\n const pathSkills = getSkillsForPath(filePath, config.pathPatterns)\n if (pathSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, pathSkills, \"path\", state)\n }\n }\n },\n\n \"experimental.session.compacting\": async (\n input: { sessionID: string },\n output: { context: string[]; prompt?: string }\n ): Promise<void> => {\n if (!config.persistAfterCompaction) return\n\n const state = sessionStates.get(input.sessionID)\n if (!state || state.loadedSkills.size === 0) return\n\n const allLoadedSkills: ParsedSkill[] = []\n for (const name of state.loadedSkills) {\n const skill = skillCache.get(name)\n if (skill) allLoadedSkills.push(skill)\n }\n\n if (allLoadedSkills.length === 0) return\n\n const formatted = formatSkillsForInjection(\n allLoadedSkills,\n { useSummaries: config.useSummaries, skillSettings: config.skillSettings }\n )\n output.context.push(\n `## Preloaded Skills\\n\\nThe following skills were loaded during this session and should persist:\\n\\n${formatted}`\n )\n\n state.initialSkillsInjected = false\n\n log(\"info\", \"Added all loaded skills to compaction context\", {\n sessionID: input.sessionID,\n skillCount: allLoadedSkills.length,\n })\n\n saveAnalytics()\n },\n\n event: async ({ event }: { event: Event }): Promise<void> => {\n if (\n event.type === \"session.deleted\" &&\n \"sessionID\" in event.properties\n ) {\n const sessionID = event.properties.sessionID as string\n sessionStates.delete(sessionID)\n pendingSkillInjections.delete(sessionID)\n analyticsData.delete(sessionID)\n log(\"debug\", \"Cleaned up session state\", { sessionID })\n saveAnalytics()\n }\n },\n }\n}\n\nexport default PreloadSkillsPlugin\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Plugin } from '@opencode-ai/plugin';
|
|
2
2
|
|
|
3
|
+
interface SkillSettings {
|
|
4
|
+
useSummary?: boolean;
|
|
5
|
+
}
|
|
6
|
+
type InjectionMethod = "systemPrompt" | "chatMessage";
|
|
3
7
|
interface PreloadSkillsConfig {
|
|
4
8
|
skills: string[];
|
|
5
9
|
fileTypeSkills?: Record<string, string[]>;
|
|
@@ -8,6 +12,8 @@ interface PreloadSkillsConfig {
|
|
|
8
12
|
contentTriggers?: Record<string, string[]>;
|
|
9
13
|
groups?: Record<string, string[]>;
|
|
10
14
|
conditionalSkills?: ConditionalSkill[];
|
|
15
|
+
skillSettings?: Record<string, SkillSettings>;
|
|
16
|
+
injectionMethod?: InjectionMethod;
|
|
11
17
|
maxTokens?: number;
|
|
12
18
|
useSummaries?: boolean;
|
|
13
19
|
analytics?: boolean;
|
|
@@ -33,7 +39,11 @@ interface ParsedSkill {
|
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
declare function loadSkills(skillNames: string[], projectDir: string): ParsedSkill[];
|
|
36
|
-
|
|
42
|
+
interface FormatOptions {
|
|
43
|
+
useSummaries?: boolean;
|
|
44
|
+
skillSettings?: Record<string, SkillSettings>;
|
|
45
|
+
}
|
|
46
|
+
declare function formatSkillsForInjection(skills: ParsedSkill[], options?: boolean | FormatOptions): string;
|
|
37
47
|
|
|
38
48
|
declare const PreloadSkillsPlugin: Plugin;
|
|
39
49
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Plugin } from '@opencode-ai/plugin';
|
|
2
2
|
|
|
3
|
+
interface SkillSettings {
|
|
4
|
+
useSummary?: boolean;
|
|
5
|
+
}
|
|
6
|
+
type InjectionMethod = "systemPrompt" | "chatMessage";
|
|
3
7
|
interface PreloadSkillsConfig {
|
|
4
8
|
skills: string[];
|
|
5
9
|
fileTypeSkills?: Record<string, string[]>;
|
|
@@ -8,6 +12,8 @@ interface PreloadSkillsConfig {
|
|
|
8
12
|
contentTriggers?: Record<string, string[]>;
|
|
9
13
|
groups?: Record<string, string[]>;
|
|
10
14
|
conditionalSkills?: ConditionalSkill[];
|
|
15
|
+
skillSettings?: Record<string, SkillSettings>;
|
|
16
|
+
injectionMethod?: InjectionMethod;
|
|
11
17
|
maxTokens?: number;
|
|
12
18
|
useSummaries?: boolean;
|
|
13
19
|
analytics?: boolean;
|
|
@@ -33,7 +39,11 @@ interface ParsedSkill {
|
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
declare function loadSkills(skillNames: string[], projectDir: string): ParsedSkill[];
|
|
36
|
-
|
|
42
|
+
interface FormatOptions {
|
|
43
|
+
useSummaries?: boolean;
|
|
44
|
+
skillSettings?: Record<string, SkillSettings>;
|
|
45
|
+
}
|
|
46
|
+
declare function formatSkillsForInjection(skills: ParsedSkill[], options?: boolean | FormatOptions): string;
|
|
37
47
|
|
|
38
48
|
declare const PreloadSkillsPlugin: Plugin;
|
|
39
49
|
|
package/dist/index.js
CHANGED
|
@@ -122,12 +122,17 @@ function loadSkills(skillNames, projectDir) {
|
|
|
122
122
|
}
|
|
123
123
|
return skills;
|
|
124
124
|
}
|
|
125
|
-
function formatSkillsForInjection(skills,
|
|
125
|
+
function formatSkillsForInjection(skills, options = false) {
|
|
126
126
|
if (!Array.isArray(skills) || skills.length === 0) {
|
|
127
127
|
return "";
|
|
128
128
|
}
|
|
129
|
+
const opts = typeof options === "boolean" ? { useSummaries: options } : options;
|
|
130
|
+
const globalUseSummaries = opts.useSummaries ?? false;
|
|
131
|
+
const skillSettings = opts.skillSettings ?? {};
|
|
129
132
|
const parts = skills.map((skill) => {
|
|
130
|
-
const
|
|
133
|
+
const perSkillSetting = skillSettings[skill.name]?.useSummary;
|
|
134
|
+
const shouldUseSummary = perSkillSetting ?? globalUseSummaries;
|
|
135
|
+
const content = shouldUseSummary && skill.summary ? skill.summary : skill.content;
|
|
131
136
|
return `<preloaded-skill name="${skill.name}">
|
|
132
137
|
${content}
|
|
133
138
|
</preloaded-skill>`;
|
|
@@ -165,6 +170,8 @@ var DEFAULT_CONFIG = {
|
|
|
165
170
|
contentTriggers: {},
|
|
166
171
|
groups: {},
|
|
167
172
|
conditionalSkills: [],
|
|
173
|
+
skillSettings: {},
|
|
174
|
+
injectionMethod: "chatMessage",
|
|
168
175
|
maxTokens: void 0,
|
|
169
176
|
useSummaries: false,
|
|
170
177
|
analytics: false,
|
|
@@ -200,6 +207,22 @@ function parseConditionalSkills(raw) {
|
|
|
200
207
|
(item) => typeof item === "object" && item !== null && typeof item.skill === "string" && typeof item.if === "object"
|
|
201
208
|
);
|
|
202
209
|
}
|
|
210
|
+
function parseSkillSettings(raw) {
|
|
211
|
+
if (!raw || typeof raw !== "object") return {};
|
|
212
|
+
const result = {};
|
|
213
|
+
for (const [skillName, settings] of Object.entries(raw)) {
|
|
214
|
+
if (typeof settings === "object" && settings !== null) {
|
|
215
|
+
const parsed = {};
|
|
216
|
+
if ("useSummary" in settings && typeof settings.useSummary === "boolean") {
|
|
217
|
+
parsed.useSummary = settings.useSummary;
|
|
218
|
+
}
|
|
219
|
+
if (Object.keys(parsed).length > 0) {
|
|
220
|
+
result[skillName] = parsed;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
203
226
|
function loadConfigFile(projectDir) {
|
|
204
227
|
const configPath = findConfigFile(projectDir);
|
|
205
228
|
if (!configPath) {
|
|
@@ -216,11 +239,13 @@ function loadConfigFile(projectDir) {
|
|
|
216
239
|
contentTriggers: parseStringArrayRecord(parsed.contentTriggers),
|
|
217
240
|
groups: parseStringArrayRecord(parsed.groups),
|
|
218
241
|
conditionalSkills: parseConditionalSkills(parsed.conditionalSkills),
|
|
242
|
+
skillSettings: parseSkillSettings(parsed.skillSettings),
|
|
219
243
|
maxTokens: typeof parsed.maxTokens === "number" ? parsed.maxTokens : void 0,
|
|
220
244
|
useSummaries: typeof parsed.useSummaries === "boolean" ? parsed.useSummaries : void 0,
|
|
221
245
|
analytics: typeof parsed.analytics === "boolean" ? parsed.analytics : void 0,
|
|
222
246
|
persistAfterCompaction: typeof parsed.persistAfterCompaction === "boolean" ? parsed.persistAfterCompaction : void 0,
|
|
223
|
-
debug: typeof parsed.debug === "boolean" ? parsed.debug : void 0
|
|
247
|
+
debug: typeof parsed.debug === "boolean" ? parsed.debug : void 0,
|
|
248
|
+
injectionMethod: parsed.injectionMethod === "systemPrompt" || parsed.injectionMethod === "chatMessage" ? parsed.injectionMethod : void 0
|
|
224
249
|
};
|
|
225
250
|
} catch {
|
|
226
251
|
return {};
|
|
@@ -304,6 +329,7 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
304
329
|
lastLoaded: now
|
|
305
330
|
});
|
|
306
331
|
}
|
|
332
|
+
saveAnalytics();
|
|
307
333
|
};
|
|
308
334
|
const saveAnalytics = () => {
|
|
309
335
|
if (!config.analytics) return;
|
|
@@ -372,7 +398,7 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
372
398
|
initialTokensUsed = result.tokensUsed;
|
|
373
399
|
initialFormattedContent = formatSkillsForInjection(
|
|
374
400
|
initialSkills,
|
|
375
|
-
config.useSummaries
|
|
401
|
+
{ useSummaries: config.useSummaries, skillSettings: config.skillSettings }
|
|
376
402
|
);
|
|
377
403
|
const loadedNames = initialSkills.map((s) => s.name);
|
|
378
404
|
const missingNames = allInitialSkillNames.filter(
|
|
@@ -422,7 +448,45 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
422
448
|
});
|
|
423
449
|
}
|
|
424
450
|
};
|
|
451
|
+
const useSystemPromptInjection = config.injectionMethod === "systemPrompt";
|
|
425
452
|
return {
|
|
453
|
+
"experimental.chat.system.transform": useSystemPromptInjection ? async (input, output) => {
|
|
454
|
+
if (!input.sessionID) return;
|
|
455
|
+
const state = getSessionState(input.sessionID);
|
|
456
|
+
const skillsToInject = [];
|
|
457
|
+
if (initialSkills.length > 0) {
|
|
458
|
+
skillsToInject.push(...initialSkills);
|
|
459
|
+
}
|
|
460
|
+
for (const name of state.loadedSkills) {
|
|
461
|
+
const skill = skillCache.get(name);
|
|
462
|
+
if (skill && !skillsToInject.find((s) => s.name === name)) {
|
|
463
|
+
skillsToInject.push(skill);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
const pending = pendingSkillInjections.get(input.sessionID);
|
|
467
|
+
if (pending && pending.length > 0) {
|
|
468
|
+
for (const skill of pending) {
|
|
469
|
+
if (!skillsToInject.find((s) => s.name === skill.name)) {
|
|
470
|
+
skillsToInject.push(skill);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
pendingSkillInjections.delete(input.sessionID);
|
|
474
|
+
}
|
|
475
|
+
if (skillsToInject.length > 0) {
|
|
476
|
+
const formatted = formatSkillsForInjection(skillsToInject, {
|
|
477
|
+
useSummaries: config.useSummaries,
|
|
478
|
+
skillSettings: config.skillSettings
|
|
479
|
+
});
|
|
480
|
+
output.system.push(formatted);
|
|
481
|
+
if (!state.initialSkillsInjected && initialSkills.length > 0) {
|
|
482
|
+
state.initialSkillsInjected = true;
|
|
483
|
+
log("info", "Injected skills into system prompt", {
|
|
484
|
+
sessionID: input.sessionID,
|
|
485
|
+
skills: skillsToInject.map((s) => s.name)
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
} : void 0,
|
|
426
490
|
"chat.message": async (input, output) => {
|
|
427
491
|
if (!input.sessionID) return;
|
|
428
492
|
const state = getSessionState(input.sessionID);
|
|
@@ -451,33 +515,38 @@ var PreloadSkillsPlugin = async (ctx) => {
|
|
|
451
515
|
}
|
|
452
516
|
}
|
|
453
517
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
skills: initialSkills.map((s) => s.name)
|
|
461
|
-
});
|
|
462
|
-
}
|
|
463
|
-
const pending = pendingSkillInjections.get(input.sessionID);
|
|
464
|
-
if (pending && pending.length > 0) {
|
|
465
|
-
const formatted = formatSkillsForInjection(pending, config.useSummaries);
|
|
466
|
-
if (formatted) {
|
|
467
|
-
contentToInject.push(formatted);
|
|
468
|
-
log("info", "Injected triggered skills", {
|
|
518
|
+
if (!useSystemPromptInjection) {
|
|
519
|
+
const contentToInject = [];
|
|
520
|
+
if (!state.initialSkillsInjected && initialFormattedContent) {
|
|
521
|
+
contentToInject.push(initialFormattedContent);
|
|
522
|
+
state.initialSkillsInjected = true;
|
|
523
|
+
log("info", "Injected initial preloaded skills", {
|
|
469
524
|
sessionID: input.sessionID,
|
|
470
|
-
skills:
|
|
525
|
+
skills: initialSkills.map((s) => s.name)
|
|
471
526
|
});
|
|
472
527
|
}
|
|
473
|
-
pendingSkillInjections.
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
528
|
+
const pending = pendingSkillInjections.get(input.sessionID);
|
|
529
|
+
if (pending && pending.length > 0) {
|
|
530
|
+
const formatted = formatSkillsForInjection(pending, {
|
|
531
|
+
useSummaries: config.useSummaries,
|
|
532
|
+
skillSettings: config.skillSettings
|
|
533
|
+
});
|
|
534
|
+
if (formatted) {
|
|
535
|
+
contentToInject.push(formatted);
|
|
536
|
+
log("info", "Injected triggered skills", {
|
|
537
|
+
sessionID: input.sessionID,
|
|
538
|
+
skills: pending.map((s) => s.name)
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
pendingSkillInjections.delete(input.sessionID);
|
|
542
|
+
}
|
|
543
|
+
if (contentToInject.length > 0) {
|
|
544
|
+
firstTextPart.text = `${contentToInject.join("\n\n")}
|
|
477
545
|
|
|
478
546
|
---
|
|
479
547
|
|
|
480
548
|
${firstTextPart.text}`;
|
|
549
|
+
}
|
|
481
550
|
}
|
|
482
551
|
},
|
|
483
552
|
"tool.execute.after": async (input, _output) => {
|
|
@@ -514,7 +583,7 @@ ${firstTextPart.text}`;
|
|
|
514
583
|
if (allLoadedSkills.length === 0) return;
|
|
515
584
|
const formatted = formatSkillsForInjection(
|
|
516
585
|
allLoadedSkills,
|
|
517
|
-
config.useSummaries
|
|
586
|
+
{ useSummaries: config.useSummaries, skillSettings: config.skillSettings }
|
|
518
587
|
);
|
|
519
588
|
output.context.push(
|
|
520
589
|
`## Preloaded Skills
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/skill-loader.ts","../src/index.ts"],"names":["join","existsSync","readFileSync","homedir"],"mappings":"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","file":"index.js","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n\nexport function matchGlobPattern(filePath: string, pattern: string): boolean {\n let regexPattern = pattern\n .replace(/\\*\\*\\//g, \"\\x00DOUBLESTARSLASH\\x00\")\n .replace(/\\*\\*/g, \"\\x00DOUBLESTAR\\x00\")\n .replace(/\\*/g, \"\\x00SINGLESTAR\\x00\")\n .replace(/\\?/g, \"\\x00QUESTION\\x00\")\n \n regexPattern = regexPattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n \n regexPattern = regexPattern\n .replace(/\\x00DOUBLESTARSLASH\\x00/g, \"(?:[^/]+/)*\")\n .replace(/\\x00DOUBLESTAR\\x00/g, \".*\")\n .replace(/\\x00SINGLESTAR\\x00/g, \"[^/]*\")\n .replace(/\\x00QUESTION\\x00/g, \"[^/]\")\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(filePath)\n}\n\nexport function matchesAnyPattern(\n filePath: string,\n patterns: string[]\n): boolean {\n return patterns.some((pattern) => matchGlobPattern(filePath, pattern))\n}\n\nexport function checkCondition(\n condition: { fileExists?: string; packageHasDependency?: string; envVar?: string },\n projectDir: string\n): boolean {\n if (condition.fileExists) {\n const fullPath = join(projectDir, condition.fileExists)\n if (!existsSync(fullPath)) return false\n }\n\n if (condition.packageHasDependency) {\n const packageJsonPath = join(projectDir, \"package.json\")\n if (!existsSync(packageJsonPath)) return false\n\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"))\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n }\n if (!deps[condition.packageHasDependency]) return false\n } catch {\n return false\n }\n }\n\n if (condition.envVar) {\n if (!process.env[condition.envVar]) return false\n }\n\n return true\n}\n\nexport function extractKeywords(text: string): string[] {\n const words = text.toLowerCase().match(/\\b[a-z]{3,}\\b/g) ?? []\n return [...new Set(words)]\n}\n\nexport function textContainsKeyword(text: string, keywords: string[]): boolean {\n const lowerText = text.toLowerCase()\n return keywords.some((kw) => lowerText.includes(kw.toLowerCase()))\n}\n","import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { ParsedSkill } from \"./types.js\"\nimport { estimateTokens } from \"./utils.js\"\n\nconst SKILL_FILENAME = \"SKILL.md\"\n\nconst SKILL_SEARCH_PATHS = [\n (dir: string) => join(dir, \".opencode\", \"skills\"),\n (dir: string) => join(dir, \".claude\", \"skills\"),\n () => join(homedir(), \".config\", \"opencode\", \"skills\"),\n () => join(homedir(), \".claude\", \"skills\"),\n]\n\nfunction findSkillFile(skillName: string, projectDir: string): string | null {\n for (const getPath of SKILL_SEARCH_PATHS) {\n const skillDir = getPath(projectDir)\n const skillPath = join(skillDir, skillName, SKILL_FILENAME)\n\n if (existsSync(skillPath)) {\n return skillPath\n }\n }\n return null\n}\n\ninterface FrontmatterData {\n name?: string\n description?: string\n summary?: string\n}\n\nfunction parseFrontmatter(content: string): FrontmatterData {\n const frontmatterMatch = content.match(/^---\\s*\\n([\\s\\S]*?)\\n---/)\n if (!frontmatterMatch?.[1]) {\n return {}\n }\n\n const frontmatter = frontmatterMatch[1]\n const result: FrontmatterData = {}\n\n const nameMatch = frontmatter.match(/^name:\\s*(.+)$/m)\n if (nameMatch?.[1]) {\n result.name = nameMatch[1].trim()\n }\n\n const descMatch = frontmatter.match(/^description:\\s*(.+)$/m)\n if (descMatch?.[1]) {\n result.description = descMatch[1].trim()\n }\n\n const summaryMatch = frontmatter.match(/^summary:\\s*(.+)$/m)\n if (summaryMatch?.[1]) {\n result.summary = summaryMatch[1].trim()\n }\n\n return result\n}\n\nfunction extractAutoSummary(content: string, maxLength: number = 500): string {\n const withoutFrontmatter = content.replace(/^---\\s*\\n[\\s\\S]*?\\n---\\s*\\n?/, \"\")\n \n const firstSection = withoutFrontmatter.split(/\\n##\\s/)[0] ?? \"\"\n const cleaned = firstSection\n .replace(/^#\\s+.+\\n?/, \"\")\n .replace(/\\n+/g, \" \")\n .trim()\n\n if (cleaned.length <= maxLength) return cleaned\n return cleaned.slice(0, maxLength).replace(/\\s+\\S*$/, \"\") + \"...\"\n}\n\nexport function loadSkill(skillName: string, projectDir: string): ParsedSkill | null {\n const filePath = findSkillFile(skillName, projectDir)\n\n if (!filePath) {\n return null\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\")\n const { name, description, summary } = parseFrontmatter(content)\n\n return {\n name: name ?? skillName,\n description: description ?? \"\",\n summary: summary ?? extractAutoSummary(content),\n content,\n filePath,\n tokenCount: estimateTokens(content),\n }\n } catch {\n return null\n }\n}\n\nexport function loadSkills(skillNames: string[], projectDir: string): ParsedSkill[] {\n if (!Array.isArray(skillNames)) {\n return []\n }\n\n const skills: ParsedSkill[] = []\n\n for (const name of skillNames) {\n const skill = loadSkill(name, projectDir)\n if (skill) {\n skills.push(skill)\n }\n }\n\n return skills\n}\n\nexport function formatSkillsForInjection(\n skills: ParsedSkill[],\n useSummaries: boolean = false\n): string {\n if (!Array.isArray(skills) || skills.length === 0) {\n return \"\"\n }\n\n const parts = skills.map((skill) => {\n const content = useSummaries && skill.summary ? skill.summary : skill.content\n return `<preloaded-skill name=\"${skill.name}\">\\n${content}\\n</preloaded-skill>`\n })\n\n return `<preloaded-skills>\nThe following skills have been automatically loaded for this session:\n\n${parts.join(\"\\n\\n\")}\n</preloaded-skills>`\n}\n\nexport function calculateTotalTokens(skills: ParsedSkill[]): number {\n return skills.reduce((sum, skill) => sum + skill.tokenCount, 0)\n}\n\nexport function filterSkillsByTokenBudget(\n skills: ParsedSkill[],\n maxTokens: number\n): ParsedSkill[] {\n const result: ParsedSkill[] = []\n let totalTokens = 0\n\n for (const skill of skills) {\n if (totalTokens + skill.tokenCount <= maxTokens) {\n result.push(skill)\n totalTokens += skill.tokenCount\n }\n }\n\n return result\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\"\nimport { join, extname, dirname } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { Plugin, PluginInput } from \"@opencode-ai/plugin\"\nimport type { Event, UserMessage, Part } from \"@opencode-ai/sdk\"\nimport type {\n PreloadSkillsConfig,\n ParsedSkill,\n SessionState,\n ConditionalSkill,\n SkillUsageStats,\n AnalyticsData,\n} from \"./types.js\"\nimport {\n loadSkills,\n formatSkillsForInjection,\n filterSkillsByTokenBudget,\n calculateTotalTokens,\n} from \"./skill-loader.js\"\nimport {\n checkCondition,\n matchGlobPattern,\n textContainsKeyword,\n} from \"./utils.js\"\n\nexport type { PreloadSkillsConfig, ParsedSkill }\nexport { loadSkills, formatSkillsForInjection }\n\nconst CONFIG_FILENAME = \"preload-skills.json\"\nconst ANALYTICS_FILENAME = \"preload-skills-analytics.json\"\nconst FILE_TOOLS = [\"read\", \"edit\", \"write\", \"glob\", \"grep\"]\n\nconst DEFAULT_CONFIG: PreloadSkillsConfig = {\n skills: [],\n fileTypeSkills: {},\n agentSkills: {},\n pathPatterns: {},\n contentTriggers: {},\n groups: {},\n conditionalSkills: [],\n maxTokens: undefined,\n useSummaries: false,\n analytics: false,\n persistAfterCompaction: true,\n debug: false,\n}\n\nfunction findConfigFile(projectDir: string): string | null {\n const locations = [\n join(projectDir, \".opencode\", CONFIG_FILENAME),\n join(projectDir, CONFIG_FILENAME),\n join(homedir(), \".config\", \"opencode\", CONFIG_FILENAME),\n ]\n\n for (const path of locations) {\n if (existsSync(path)) {\n return path\n }\n }\n return null\n}\n\nfunction parseStringArrayRecord(raw: unknown): Record<string, string[]> {\n if (!raw || typeof raw !== \"object\") return {}\n\n const result: Record<string, string[]> = {}\n for (const [key, value] of Object.entries(raw)) {\n if (Array.isArray(value)) {\n result[key] = value.filter((v) => typeof v === \"string\")\n }\n }\n return result\n}\n\nfunction parseConditionalSkills(raw: unknown): ConditionalSkill[] {\n if (!Array.isArray(raw)) return []\n\n return raw.filter(\n (item): item is ConditionalSkill =>\n typeof item === \"object\" &&\n item !== null &&\n typeof item.skill === \"string\" &&\n typeof item.if === \"object\"\n )\n}\n\nfunction loadConfigFile(projectDir: string): Partial<PreloadSkillsConfig> {\n const configPath = findConfigFile(projectDir)\n if (!configPath) {\n return {}\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\")\n const parsed = JSON.parse(content) as Record<string, unknown>\n\n return {\n skills: Array.isArray(parsed.skills) ? parsed.skills : [],\n fileTypeSkills: parseStringArrayRecord(parsed.fileTypeSkills),\n agentSkills: parseStringArrayRecord(parsed.agentSkills),\n pathPatterns: parseStringArrayRecord(parsed.pathPatterns),\n contentTriggers: parseStringArrayRecord(parsed.contentTriggers),\n groups: parseStringArrayRecord(parsed.groups),\n conditionalSkills: parseConditionalSkills(parsed.conditionalSkills),\n maxTokens:\n typeof parsed.maxTokens === \"number\" ? parsed.maxTokens : undefined,\n useSummaries:\n typeof parsed.useSummaries === \"boolean\"\n ? parsed.useSummaries\n : undefined,\n analytics:\n typeof parsed.analytics === \"boolean\" ? parsed.analytics : undefined,\n persistAfterCompaction:\n typeof parsed.persistAfterCompaction === \"boolean\"\n ? parsed.persistAfterCompaction\n : undefined,\n debug: typeof parsed.debug === \"boolean\" ? parsed.debug : undefined,\n }\n } catch {\n return {}\n }\n}\n\nfunction getFilePathFromArgs(args: Record<string, unknown>): string | null {\n if (typeof args.filePath === \"string\") return args.filePath\n if (typeof args.path === \"string\") return args.path\n if (typeof args.file === \"string\") return args.file\n return null\n}\n\nfunction getSkillsForExtension(\n ext: string,\n fileTypeSkills: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(fileTypeSkills)) {\n const extensions = pattern.split(\",\").map((e) => e.trim().toLowerCase())\n if (extensions.includes(ext.toLowerCase())) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction getSkillsForPath(\n filePath: string,\n pathPatterns: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(pathPatterns)) {\n if (matchGlobPattern(filePath, pattern)) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction resolveSkillGroups(\n skillNames: string[],\n groups: Record<string, string[]>\n): string[] {\n const resolved: string[] = []\n\n for (const name of skillNames) {\n if (name.startsWith(\"@\") && groups[name.slice(1)]) {\n resolved.push(...groups[name.slice(1)]!)\n } else {\n resolved.push(name)\n }\n }\n\n return [...new Set(resolved)]\n}\n\nexport const PreloadSkillsPlugin: Plugin = async (ctx: PluginInput) => {\n const sessionStates = new Map<string, SessionState>()\n const analyticsData = new Map<string, AnalyticsData>()\n\n const fileConfig = loadConfigFile(ctx.directory)\n const config: PreloadSkillsConfig = {\n ...DEFAULT_CONFIG,\n ...fileConfig,\n }\n\n const log = (\n level: \"debug\" | \"info\" | \"warn\" | \"error\",\n message: string,\n extra?: Record<string, unknown>\n ) => {\n if (level === \"debug\" && !config.debug) return\n\n ctx.client.app.log({\n body: {\n service: \"preload-skills\",\n level,\n message,\n extra,\n },\n })\n }\n\n const trackSkillUsage = (\n sessionID: string,\n skillName: string,\n triggerType: SkillUsageStats[\"triggerType\"]\n ) => {\n if (!config.analytics) return\n\n if (!analyticsData.has(sessionID)) {\n analyticsData.set(sessionID, {\n sessionId: sessionID,\n skillUsage: new Map(),\n })\n }\n\n const data = analyticsData.get(sessionID)!\n const now = Date.now()\n\n if (data.skillUsage.has(skillName)) {\n const stats = data.skillUsage.get(skillName)!\n stats.loadCount++\n stats.lastLoaded = now\n } else {\n data.skillUsage.set(skillName, {\n skillName,\n loadCount: 1,\n triggerType,\n firstLoaded: now,\n lastLoaded: now,\n })\n }\n }\n\n const saveAnalytics = () => {\n if (!config.analytics) return\n\n try {\n const analyticsPath = join(ctx.directory, \".opencode\", ANALYTICS_FILENAME)\n const dir = dirname(analyticsPath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n\n const serializable: Record<string, unknown> = {}\n for (const [sessionId, data] of analyticsData) {\n serializable[sessionId] = {\n sessionId: data.sessionId,\n skillUsage: Object.fromEntries(data.skillUsage),\n }\n }\n\n writeFileSync(analyticsPath, JSON.stringify(serializable, null, 2))\n } catch {\n log(\"warn\", \"Failed to save analytics\")\n }\n }\n\n const skillCache = new Map<string, ParsedSkill>()\n\n const loadSkillsWithBudget = (\n skillNames: string[],\n currentTokens: number,\n triggerType: SkillUsageStats[\"triggerType\"],\n sessionID: string\n ): { skills: ParsedSkill[]; tokensUsed: number } => {\n const resolved = resolveSkillGroups(skillNames, config.groups ?? {})\n let skills = loadSkills(resolved, ctx.directory)\n\n for (const skill of skills) {\n skillCache.set(skill.name, skill)\n }\n\n if (config.maxTokens) {\n const remainingBudget = config.maxTokens - currentTokens\n skills = filterSkillsByTokenBudget(skills, remainingBudget)\n }\n\n for (const skill of skills) {\n trackSkillUsage(sessionID, skill.name, triggerType)\n }\n\n return {\n skills,\n tokensUsed: calculateTotalTokens(skills),\n }\n }\n\n const resolveConditionalSkills = (): string[] => {\n if (!config.conditionalSkills?.length) return []\n\n const resolved: string[] = []\n for (const { skill, if: condition } of config.conditionalSkills) {\n if (checkCondition(condition, ctx.directory)) {\n resolved.push(skill)\n }\n }\n\n return resolved\n }\n\n let initialSkills: ParsedSkill[] = []\n let initialFormattedContent = \"\"\n let initialTokensUsed = 0\n\n const allInitialSkillNames = [\n ...config.skills,\n ...resolveConditionalSkills(),\n ]\n\n if (allInitialSkillNames.length > 0) {\n const result = loadSkillsWithBudget(\n allInitialSkillNames,\n 0,\n \"initial\",\n \"__init__\"\n )\n initialSkills = result.skills\n initialTokensUsed = result.tokensUsed\n initialFormattedContent = formatSkillsForInjection(\n initialSkills,\n config.useSummaries\n )\n\n const loadedNames = initialSkills.map((s) => s.name)\n const missingNames = allInitialSkillNames.filter(\n (s) => !loadedNames.includes(s) && !s.startsWith(\"@\")\n )\n\n log(\"info\", `Loaded ${initialSkills.length} initial skills`, {\n loaded: loadedNames,\n tokens: initialTokensUsed,\n missing: missingNames.length > 0 ? missingNames : undefined,\n })\n }\n\n const hasTriggeredSkills =\n Object.keys(config.fileTypeSkills ?? {}).length > 0 ||\n Object.keys(config.agentSkills ?? {}).length > 0 ||\n Object.keys(config.pathPatterns ?? {}).length > 0 ||\n Object.keys(config.contentTriggers ?? {}).length > 0\n\n if (allInitialSkillNames.length === 0 && !hasTriggeredSkills) {\n log(\"warn\", \"No skills configured. Create .opencode/preload-skills.json\")\n }\n\n const getSessionState = (sessionID: string): SessionState => {\n if (!sessionStates.has(sessionID)) {\n sessionStates.set(sessionID, {\n initialSkillsInjected: false,\n loadedSkills: new Set(initialSkills.map((s) => s.name)),\n totalTokensUsed: initialTokensUsed,\n })\n }\n return sessionStates.get(sessionID)!\n }\n\n const pendingSkillInjections = new Map<string, ParsedSkill[]>()\n\n const queueSkillsForInjection = (\n sessionID: string,\n skillNames: string[],\n triggerType: SkillUsageStats[\"triggerType\"],\n state: SessionState\n ) => {\n const newSkillNames = skillNames.filter((name) => !state.loadedSkills.has(name))\n if (newSkillNames.length === 0) return\n\n const result = loadSkillsWithBudget(\n newSkillNames,\n state.totalTokensUsed,\n triggerType,\n sessionID\n )\n\n if (result.skills.length > 0) {\n for (const skill of result.skills) {\n state.loadedSkills.add(skill.name)\n }\n state.totalTokensUsed += result.tokensUsed\n\n const existing = pendingSkillInjections.get(sessionID) ?? []\n pendingSkillInjections.set(sessionID, [...existing, ...result.skills])\n\n log(\"debug\", `Queued ${triggerType} skills for injection`, {\n sessionID,\n skills: result.skills.map((s) => s.name),\n tokens: result.tokensUsed,\n })\n }\n }\n\n return {\n \"chat.message\": async (\n input: {\n sessionID: string\n agent?: string\n model?: { providerID: string; modelID: string }\n messageID?: string\n variant?: string\n },\n output: { message: UserMessage; parts: Part[] }\n ): Promise<void> => {\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n const firstTextPart = output.parts.find((p) => p.type === \"text\")\n if (!firstTextPart || !(\"text\" in firstTextPart)) return\n\n const messageText = firstTextPart.text\n\n if (input.agent && config.agentSkills?.[input.agent]) {\n queueSkillsForInjection(\n input.sessionID,\n config.agentSkills[input.agent]!,\n \"agent\",\n state\n )\n }\n\n if (config.contentTriggers) {\n for (const [keyword, skillNames] of Object.entries(\n config.contentTriggers\n )) {\n if (textContainsKeyword(messageText, [keyword])) {\n queueSkillsForInjection(\n input.sessionID,\n skillNames,\n \"content\",\n state\n )\n }\n }\n }\n\n const contentToInject: string[] = []\n\n if (!state.initialSkillsInjected && initialFormattedContent) {\n contentToInject.push(initialFormattedContent)\n state.initialSkillsInjected = true\n log(\"info\", \"Injected initial preloaded skills\", {\n sessionID: input.sessionID,\n skills: initialSkills.map((s) => s.name),\n })\n }\n\n const pending = pendingSkillInjections.get(input.sessionID)\n if (pending && pending.length > 0) {\n const formatted = formatSkillsForInjection(pending, config.useSummaries)\n if (formatted) {\n contentToInject.push(formatted)\n log(\"info\", \"Injected triggered skills\", {\n sessionID: input.sessionID,\n skills: pending.map((s) => s.name),\n })\n }\n pendingSkillInjections.delete(input.sessionID)\n }\n\n if (contentToInject.length > 0) {\n firstTextPart.text = `${contentToInject.join(\"\\n\\n\")}\\n\\n---\\n\\n${firstTextPart.text}`\n }\n },\n\n \"tool.execute.after\": async (\n input: {\n tool: string\n sessionID: string\n callID: string\n },\n _output: {\n title: string\n output: string\n metadata: unknown\n }\n ): Promise<void> => {\n if (!FILE_TOOLS.includes(input.tool)) return\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n\n const toolArgs = (_output.metadata as { args?: Record<string, unknown> })\n ?.args\n if (!toolArgs) return\n\n const filePath = getFilePathFromArgs(toolArgs)\n if (!filePath) return\n\n const ext = extname(filePath)\n if (ext && config.fileTypeSkills) {\n const extSkills = getSkillsForExtension(ext, config.fileTypeSkills)\n if (extSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, extSkills, \"fileType\", state)\n }\n }\n\n if (config.pathPatterns) {\n const pathSkills = getSkillsForPath(filePath, config.pathPatterns)\n if (pathSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, pathSkills, \"path\", state)\n }\n }\n },\n\n \"experimental.session.compacting\": async (\n input: { sessionID: string },\n output: { context: string[]; prompt?: string }\n ): Promise<void> => {\n if (!config.persistAfterCompaction) return\n\n const state = sessionStates.get(input.sessionID)\n if (!state || state.loadedSkills.size === 0) return\n\n const allLoadedSkills: ParsedSkill[] = []\n for (const name of state.loadedSkills) {\n const skill = skillCache.get(name)\n if (skill) allLoadedSkills.push(skill)\n }\n\n if (allLoadedSkills.length === 0) return\n\n const formatted = formatSkillsForInjection(\n allLoadedSkills,\n config.useSummaries\n )\n output.context.push(\n `## Preloaded Skills\\n\\nThe following skills were loaded during this session and should persist:\\n\\n${formatted}`\n )\n\n state.initialSkillsInjected = false\n\n log(\"info\", \"Added all loaded skills to compaction context\", {\n sessionID: input.sessionID,\n skillCount: allLoadedSkills.length,\n })\n\n saveAnalytics()\n },\n\n event: async ({ event }: { event: Event }): Promise<void> => {\n if (\n event.type === \"session.deleted\" &&\n \"sessionID\" in event.properties\n ) {\n const sessionID = event.properties.sessionID as string\n sessionStates.delete(sessionID)\n pendingSkillInjections.delete(sessionID)\n analyticsData.delete(sessionID)\n log(\"debug\", \"Cleaned up session state\", { sessionID })\n saveAnalytics()\n }\n },\n }\n}\n\nexport default PreloadSkillsPlugin\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/skill-loader.ts","../src/index.ts"],"names":["join","existsSync","readFileSync","homedir"],"mappings":"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","file":"index.js","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\n\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 4)\n}\n\nexport function matchGlobPattern(filePath: string, pattern: string): boolean {\n let regexPattern = pattern\n .replace(/\\*\\*\\//g, \"\\x00DOUBLESTARSLASH\\x00\")\n .replace(/\\*\\*/g, \"\\x00DOUBLESTAR\\x00\")\n .replace(/\\*/g, \"\\x00SINGLESTAR\\x00\")\n .replace(/\\?/g, \"\\x00QUESTION\\x00\")\n \n regexPattern = regexPattern.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n \n regexPattern = regexPattern\n .replace(/\\x00DOUBLESTARSLASH\\x00/g, \"(?:[^/]+/)*\")\n .replace(/\\x00DOUBLESTAR\\x00/g, \".*\")\n .replace(/\\x00SINGLESTAR\\x00/g, \"[^/]*\")\n .replace(/\\x00QUESTION\\x00/g, \"[^/]\")\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(filePath)\n}\n\nexport function matchesAnyPattern(\n filePath: string,\n patterns: string[]\n): boolean {\n return patterns.some((pattern) => matchGlobPattern(filePath, pattern))\n}\n\nexport function checkCondition(\n condition: { fileExists?: string; packageHasDependency?: string; envVar?: string },\n projectDir: string\n): boolean {\n if (condition.fileExists) {\n const fullPath = join(projectDir, condition.fileExists)\n if (!existsSync(fullPath)) return false\n }\n\n if (condition.packageHasDependency) {\n const packageJsonPath = join(projectDir, \"package.json\")\n if (!existsSync(packageJsonPath)) return false\n\n try {\n const packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"))\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n }\n if (!deps[condition.packageHasDependency]) return false\n } catch {\n return false\n }\n }\n\n if (condition.envVar) {\n if (!process.env[condition.envVar]) return false\n }\n\n return true\n}\n\nexport function extractKeywords(text: string): string[] {\n const words = text.toLowerCase().match(/\\b[a-z]{3,}\\b/g) ?? []\n return [...new Set(words)]\n}\n\nexport function textContainsKeyword(text: string, keywords: string[]): boolean {\n const lowerText = text.toLowerCase()\n return keywords.some((kw) => lowerText.includes(kw.toLowerCase()))\n}\n","import { existsSync, readFileSync } from \"node:fs\"\nimport { join } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { ParsedSkill, SkillSettings } from \"./types.js\"\nimport { estimateTokens } from \"./utils.js\"\n\nconst SKILL_FILENAME = \"SKILL.md\"\n\nconst SKILL_SEARCH_PATHS = [\n (dir: string) => join(dir, \".opencode\", \"skills\"),\n (dir: string) => join(dir, \".claude\", \"skills\"),\n () => join(homedir(), \".config\", \"opencode\", \"skills\"),\n () => join(homedir(), \".claude\", \"skills\"),\n]\n\nfunction findSkillFile(skillName: string, projectDir: string): string | null {\n for (const getPath of SKILL_SEARCH_PATHS) {\n const skillDir = getPath(projectDir)\n const skillPath = join(skillDir, skillName, SKILL_FILENAME)\n\n if (existsSync(skillPath)) {\n return skillPath\n }\n }\n return null\n}\n\ninterface FrontmatterData {\n name?: string\n description?: string\n summary?: string\n}\n\nfunction parseFrontmatter(content: string): FrontmatterData {\n const frontmatterMatch = content.match(/^---\\s*\\n([\\s\\S]*?)\\n---/)\n if (!frontmatterMatch?.[1]) {\n return {}\n }\n\n const frontmatter = frontmatterMatch[1]\n const result: FrontmatterData = {}\n\n const nameMatch = frontmatter.match(/^name:\\s*(.+)$/m)\n if (nameMatch?.[1]) {\n result.name = nameMatch[1].trim()\n }\n\n const descMatch = frontmatter.match(/^description:\\s*(.+)$/m)\n if (descMatch?.[1]) {\n result.description = descMatch[1].trim()\n }\n\n const summaryMatch = frontmatter.match(/^summary:\\s*(.+)$/m)\n if (summaryMatch?.[1]) {\n result.summary = summaryMatch[1].trim()\n }\n\n return result\n}\n\nfunction extractAutoSummary(content: string, maxLength: number = 500): string {\n const withoutFrontmatter = content.replace(/^---\\s*\\n[\\s\\S]*?\\n---\\s*\\n?/, \"\")\n \n const firstSection = withoutFrontmatter.split(/\\n##\\s/)[0] ?? \"\"\n const cleaned = firstSection\n .replace(/^#\\s+.+\\n?/, \"\")\n .replace(/\\n+/g, \" \")\n .trim()\n\n if (cleaned.length <= maxLength) return cleaned\n return cleaned.slice(0, maxLength).replace(/\\s+\\S*$/, \"\") + \"...\"\n}\n\nexport function loadSkill(skillName: string, projectDir: string): ParsedSkill | null {\n const filePath = findSkillFile(skillName, projectDir)\n\n if (!filePath) {\n return null\n }\n\n try {\n const content = readFileSync(filePath, \"utf-8\")\n const { name, description, summary } = parseFrontmatter(content)\n\n return {\n name: name ?? skillName,\n description: description ?? \"\",\n summary: summary ?? extractAutoSummary(content),\n content,\n filePath,\n tokenCount: estimateTokens(content),\n }\n } catch {\n return null\n }\n}\n\nexport function loadSkills(skillNames: string[], projectDir: string): ParsedSkill[] {\n if (!Array.isArray(skillNames)) {\n return []\n }\n\n const skills: ParsedSkill[] = []\n\n for (const name of skillNames) {\n const skill = loadSkill(name, projectDir)\n if (skill) {\n skills.push(skill)\n }\n }\n\n return skills\n}\n\nexport interface FormatOptions {\n useSummaries?: boolean\n skillSettings?: Record<string, SkillSettings>\n}\n\nexport function formatSkillsForInjection(\n skills: ParsedSkill[],\n options: boolean | FormatOptions = false\n): string {\n if (!Array.isArray(skills) || skills.length === 0) {\n return \"\"\n }\n\n const opts: FormatOptions = typeof options === \"boolean\" \n ? { useSummaries: options } \n : options\n \n const globalUseSummaries = opts.useSummaries ?? false\n const skillSettings = opts.skillSettings ?? {}\n\n const parts = skills.map((skill) => {\n const perSkillSetting = skillSettings[skill.name]?.useSummary\n const shouldUseSummary = perSkillSetting ?? globalUseSummaries\n const content = shouldUseSummary && skill.summary ? skill.summary : skill.content\n return `<preloaded-skill name=\"${skill.name}\">\\n${content}\\n</preloaded-skill>`\n })\n\n return `<preloaded-skills>\nThe following skills have been automatically loaded for this session:\n\n${parts.join(\"\\n\\n\")}\n</preloaded-skills>`\n}\n\nexport function calculateTotalTokens(skills: ParsedSkill[]): number {\n return skills.reduce((sum, skill) => sum + skill.tokenCount, 0)\n}\n\nexport function filterSkillsByTokenBudget(\n skills: ParsedSkill[],\n maxTokens: number\n): ParsedSkill[] {\n const result: ParsedSkill[] = []\n let totalTokens = 0\n\n for (const skill of skills) {\n if (totalTokens + skill.tokenCount <= maxTokens) {\n result.push(skill)\n totalTokens += skill.tokenCount\n }\n }\n\n return result\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\"\nimport { join, extname, dirname } from \"node:path\"\nimport { homedir } from \"node:os\"\nimport type { Plugin, PluginInput } from \"@opencode-ai/plugin\"\nimport type { Event, UserMessage, Part, Model } from \"@opencode-ai/sdk\"\nimport type {\n PreloadSkillsConfig,\n ParsedSkill,\n SessionState,\n ConditionalSkill,\n SkillSettings,\n SkillUsageStats,\n AnalyticsData,\n InjectionMethod,\n} from \"./types.js\"\nimport {\n loadSkills,\n formatSkillsForInjection,\n filterSkillsByTokenBudget,\n calculateTotalTokens,\n} from \"./skill-loader.js\"\nimport {\n checkCondition,\n matchGlobPattern,\n textContainsKeyword,\n} from \"./utils.js\"\n\nexport type { PreloadSkillsConfig, ParsedSkill }\nexport { loadSkills, formatSkillsForInjection }\n\nconst CONFIG_FILENAME = \"preload-skills.json\"\nconst ANALYTICS_FILENAME = \"preload-skills-analytics.json\"\nconst FILE_TOOLS = [\"read\", \"edit\", \"write\", \"glob\", \"grep\"]\n\nconst DEFAULT_CONFIG: PreloadSkillsConfig = {\n skills: [],\n fileTypeSkills: {},\n agentSkills: {},\n pathPatterns: {},\n contentTriggers: {},\n groups: {},\n conditionalSkills: [],\n skillSettings: {},\n injectionMethod: \"chatMessage\",\n maxTokens: undefined,\n useSummaries: false,\n analytics: false,\n persistAfterCompaction: true,\n debug: false,\n}\n\nfunction findConfigFile(projectDir: string): string | null {\n const locations = [\n join(projectDir, \".opencode\", CONFIG_FILENAME),\n join(projectDir, CONFIG_FILENAME),\n join(homedir(), \".config\", \"opencode\", CONFIG_FILENAME),\n ]\n\n for (const path of locations) {\n if (existsSync(path)) {\n return path\n }\n }\n return null\n}\n\nfunction parseStringArrayRecord(raw: unknown): Record<string, string[]> {\n if (!raw || typeof raw !== \"object\") return {}\n\n const result: Record<string, string[]> = {}\n for (const [key, value] of Object.entries(raw)) {\n if (Array.isArray(value)) {\n result[key] = value.filter((v) => typeof v === \"string\")\n }\n }\n return result\n}\n\nfunction parseConditionalSkills(raw: unknown): ConditionalSkill[] {\n if (!Array.isArray(raw)) return []\n\n return raw.filter(\n (item): item is ConditionalSkill =>\n typeof item === \"object\" &&\n item !== null &&\n typeof item.skill === \"string\" &&\n typeof item.if === \"object\"\n )\n}\n\nfunction parseSkillSettings(raw: unknown): Record<string, SkillSettings> {\n if (!raw || typeof raw !== \"object\") return {}\n\n const result: Record<string, SkillSettings> = {}\n for (const [skillName, settings] of Object.entries(raw)) {\n if (typeof settings === \"object\" && settings !== null) {\n const parsed: SkillSettings = {}\n if (\"useSummary\" in settings && typeof settings.useSummary === \"boolean\") {\n parsed.useSummary = settings.useSummary\n }\n if (Object.keys(parsed).length > 0) {\n result[skillName] = parsed\n }\n }\n }\n return result\n}\n\nfunction loadConfigFile(projectDir: string): Partial<PreloadSkillsConfig> {\n const configPath = findConfigFile(projectDir)\n if (!configPath) {\n return {}\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\")\n const parsed = JSON.parse(content) as Record<string, unknown>\n\n return {\n skills: Array.isArray(parsed.skills) ? parsed.skills : [],\n fileTypeSkills: parseStringArrayRecord(parsed.fileTypeSkills),\n agentSkills: parseStringArrayRecord(parsed.agentSkills),\n pathPatterns: parseStringArrayRecord(parsed.pathPatterns),\n contentTriggers: parseStringArrayRecord(parsed.contentTriggers),\n groups: parseStringArrayRecord(parsed.groups),\n conditionalSkills: parseConditionalSkills(parsed.conditionalSkills),\n skillSettings: parseSkillSettings(parsed.skillSettings),\n maxTokens:\n typeof parsed.maxTokens === \"number\" ? parsed.maxTokens : undefined,\n useSummaries:\n typeof parsed.useSummaries === \"boolean\"\n ? parsed.useSummaries\n : undefined,\n analytics:\n typeof parsed.analytics === \"boolean\" ? parsed.analytics : undefined,\n persistAfterCompaction:\n typeof parsed.persistAfterCompaction === \"boolean\"\n ? parsed.persistAfterCompaction\n : undefined,\n debug: typeof parsed.debug === \"boolean\" ? parsed.debug : undefined,\n injectionMethod:\n parsed.injectionMethod === \"systemPrompt\" ||\n parsed.injectionMethod === \"chatMessage\"\n ? (parsed.injectionMethod as InjectionMethod)\n : undefined,\n }\n } catch {\n return {}\n }\n}\n\nfunction getFilePathFromArgs(args: Record<string, unknown>): string | null {\n if (typeof args.filePath === \"string\") return args.filePath\n if (typeof args.path === \"string\") return args.path\n if (typeof args.file === \"string\") return args.file\n return null\n}\n\nfunction getSkillsForExtension(\n ext: string,\n fileTypeSkills: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(fileTypeSkills)) {\n const extensions = pattern.split(\",\").map((e) => e.trim().toLowerCase())\n if (extensions.includes(ext.toLowerCase())) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction getSkillsForPath(\n filePath: string,\n pathPatterns: Record<string, string[]>\n): string[] {\n const skills: string[] = []\n\n for (const [pattern, skillNames] of Object.entries(pathPatterns)) {\n if (matchGlobPattern(filePath, pattern)) {\n skills.push(...skillNames)\n }\n }\n\n return [...new Set(skills)]\n}\n\nfunction resolveSkillGroups(\n skillNames: string[],\n groups: Record<string, string[]>\n): string[] {\n const resolved: string[] = []\n\n for (const name of skillNames) {\n if (name.startsWith(\"@\") && groups[name.slice(1)]) {\n resolved.push(...groups[name.slice(1)]!)\n } else {\n resolved.push(name)\n }\n }\n\n return [...new Set(resolved)]\n}\n\nexport const PreloadSkillsPlugin: Plugin = async (ctx: PluginInput) => {\n const sessionStates = new Map<string, SessionState>()\n const analyticsData = new Map<string, AnalyticsData>()\n\n const fileConfig = loadConfigFile(ctx.directory)\n const config: PreloadSkillsConfig = {\n ...DEFAULT_CONFIG,\n ...fileConfig,\n }\n\n const log = (\n level: \"debug\" | \"info\" | \"warn\" | \"error\",\n message: string,\n extra?: Record<string, unknown>\n ) => {\n if (level === \"debug\" && !config.debug) return\n\n ctx.client.app.log({\n body: {\n service: \"preload-skills\",\n level,\n message,\n extra,\n },\n })\n }\n\n const trackSkillUsage = (\n sessionID: string,\n skillName: string,\n triggerType: SkillUsageStats[\"triggerType\"]\n ) => {\n if (!config.analytics) return\n\n if (!analyticsData.has(sessionID)) {\n analyticsData.set(sessionID, {\n sessionId: sessionID,\n skillUsage: new Map(),\n })\n }\n\n const data = analyticsData.get(sessionID)!\n const now = Date.now()\n\n if (data.skillUsage.has(skillName)) {\n const stats = data.skillUsage.get(skillName)!\n stats.loadCount++\n stats.lastLoaded = now\n } else {\n data.skillUsage.set(skillName, {\n skillName,\n loadCount: 1,\n triggerType,\n firstLoaded: now,\n lastLoaded: now,\n })\n }\n\n saveAnalytics()\n }\n\n const saveAnalytics = () => {\n if (!config.analytics) return\n\n try {\n const analyticsPath = join(ctx.directory, \".opencode\", ANALYTICS_FILENAME)\n const dir = dirname(analyticsPath)\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true })\n }\n\n const serializable: Record<string, unknown> = {}\n for (const [sessionId, data] of analyticsData) {\n serializable[sessionId] = {\n sessionId: data.sessionId,\n skillUsage: Object.fromEntries(data.skillUsage),\n }\n }\n\n writeFileSync(analyticsPath, JSON.stringify(serializable, null, 2))\n } catch {\n log(\"warn\", \"Failed to save analytics\")\n }\n }\n\n const skillCache = new Map<string, ParsedSkill>()\n\n const loadSkillsWithBudget = (\n skillNames: string[],\n currentTokens: number,\n triggerType: SkillUsageStats[\"triggerType\"],\n sessionID: string\n ): { skills: ParsedSkill[]; tokensUsed: number } => {\n const resolved = resolveSkillGroups(skillNames, config.groups ?? {})\n let skills = loadSkills(resolved, ctx.directory)\n\n for (const skill of skills) {\n skillCache.set(skill.name, skill)\n }\n\n if (config.maxTokens) {\n const remainingBudget = config.maxTokens - currentTokens\n skills = filterSkillsByTokenBudget(skills, remainingBudget)\n }\n\n for (const skill of skills) {\n trackSkillUsage(sessionID, skill.name, triggerType)\n }\n\n return {\n skills,\n tokensUsed: calculateTotalTokens(skills),\n }\n }\n\n const resolveConditionalSkills = (): string[] => {\n if (!config.conditionalSkills?.length) return []\n\n const resolved: string[] = []\n for (const { skill, if: condition } of config.conditionalSkills) {\n if (checkCondition(condition, ctx.directory)) {\n resolved.push(skill)\n }\n }\n\n return resolved\n }\n\n let initialSkills: ParsedSkill[] = []\n let initialFormattedContent = \"\"\n let initialTokensUsed = 0\n\n const allInitialSkillNames = [\n ...config.skills,\n ...resolveConditionalSkills(),\n ]\n\n if (allInitialSkillNames.length > 0) {\n const result = loadSkillsWithBudget(\n allInitialSkillNames,\n 0,\n \"initial\",\n \"__init__\"\n )\n initialSkills = result.skills\n initialTokensUsed = result.tokensUsed\n initialFormattedContent = formatSkillsForInjection(\n initialSkills,\n { useSummaries: config.useSummaries, skillSettings: config.skillSettings }\n )\n\n const loadedNames = initialSkills.map((s) => s.name)\n const missingNames = allInitialSkillNames.filter(\n (s) => !loadedNames.includes(s) && !s.startsWith(\"@\")\n )\n\n log(\"info\", `Loaded ${initialSkills.length} initial skills`, {\n loaded: loadedNames,\n tokens: initialTokensUsed,\n missing: missingNames.length > 0 ? missingNames : undefined,\n })\n }\n\n const hasTriggeredSkills =\n Object.keys(config.fileTypeSkills ?? {}).length > 0 ||\n Object.keys(config.agentSkills ?? {}).length > 0 ||\n Object.keys(config.pathPatterns ?? {}).length > 0 ||\n Object.keys(config.contentTriggers ?? {}).length > 0\n\n if (allInitialSkillNames.length === 0 && !hasTriggeredSkills) {\n log(\"warn\", \"No skills configured. Create .opencode/preload-skills.json\")\n }\n\n const getSessionState = (sessionID: string): SessionState => {\n if (!sessionStates.has(sessionID)) {\n sessionStates.set(sessionID, {\n initialSkillsInjected: false,\n loadedSkills: new Set(initialSkills.map((s) => s.name)),\n totalTokensUsed: initialTokensUsed,\n })\n }\n return sessionStates.get(sessionID)!\n }\n\n const pendingSkillInjections = new Map<string, ParsedSkill[]>()\n\n const queueSkillsForInjection = (\n sessionID: string,\n skillNames: string[],\n triggerType: SkillUsageStats[\"triggerType\"],\n state: SessionState\n ) => {\n const newSkillNames = skillNames.filter((name) => !state.loadedSkills.has(name))\n if (newSkillNames.length === 0) return\n\n const result = loadSkillsWithBudget(\n newSkillNames,\n state.totalTokensUsed,\n triggerType,\n sessionID\n )\n\n if (result.skills.length > 0) {\n for (const skill of result.skills) {\n state.loadedSkills.add(skill.name)\n }\n state.totalTokensUsed += result.tokensUsed\n\n const existing = pendingSkillInjections.get(sessionID) ?? []\n pendingSkillInjections.set(sessionID, [...existing, ...result.skills])\n\n log(\"debug\", `Queued ${triggerType} skills for injection`, {\n sessionID,\n skills: result.skills.map((s) => s.name),\n tokens: result.tokensUsed,\n })\n }\n }\n\n const useSystemPromptInjection = config.injectionMethod === \"systemPrompt\"\n\n return {\n \"experimental.chat.system.transform\": useSystemPromptInjection\n ? async (\n input: { sessionID?: string; model: Model },\n output: { system: string[] }\n ): Promise<void> => {\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n const skillsToInject: ParsedSkill[] = []\n\n if (initialSkills.length > 0) {\n skillsToInject.push(...initialSkills)\n }\n\n for (const name of state.loadedSkills) {\n const skill = skillCache.get(name)\n if (skill && !skillsToInject.find((s) => s.name === name)) {\n skillsToInject.push(skill)\n }\n }\n\n const pending = pendingSkillInjections.get(input.sessionID)\n if (pending && pending.length > 0) {\n for (const skill of pending) {\n if (!skillsToInject.find((s) => s.name === skill.name)) {\n skillsToInject.push(skill)\n }\n }\n pendingSkillInjections.delete(input.sessionID)\n }\n\n if (skillsToInject.length > 0) {\n const formatted = formatSkillsForInjection(skillsToInject, {\n useSummaries: config.useSummaries,\n skillSettings: config.skillSettings,\n })\n output.system.push(formatted)\n\n if (!state.initialSkillsInjected && initialSkills.length > 0) {\n state.initialSkillsInjected = true\n log(\"info\", \"Injected skills into system prompt\", {\n sessionID: input.sessionID,\n skills: skillsToInject.map((s) => s.name),\n })\n }\n }\n }\n : undefined,\n\n \"chat.message\": async (\n input: {\n sessionID: string\n agent?: string\n model?: { providerID: string; modelID: string }\n messageID?: string\n variant?: string\n },\n output: { message: UserMessage; parts: Part[] }\n ): Promise<void> => {\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n const firstTextPart = output.parts.find((p) => p.type === \"text\")\n if (!firstTextPart || !(\"text\" in firstTextPart)) return\n\n const messageText = firstTextPart.text\n\n if (input.agent && config.agentSkills?.[input.agent]) {\n queueSkillsForInjection(\n input.sessionID,\n config.agentSkills[input.agent]!,\n \"agent\",\n state\n )\n }\n\n if (config.contentTriggers) {\n for (const [keyword, skillNames] of Object.entries(\n config.contentTriggers\n )) {\n if (textContainsKeyword(messageText, [keyword])) {\n queueSkillsForInjection(\n input.sessionID,\n skillNames,\n \"content\",\n state\n )\n }\n }\n }\n\n if (!useSystemPromptInjection) {\n const contentToInject: string[] = []\n\n if (!state.initialSkillsInjected && initialFormattedContent) {\n contentToInject.push(initialFormattedContent)\n state.initialSkillsInjected = true\n log(\"info\", \"Injected initial preloaded skills\", {\n sessionID: input.sessionID,\n skills: initialSkills.map((s) => s.name),\n })\n }\n\n const pending = pendingSkillInjections.get(input.sessionID)\n if (pending && pending.length > 0) {\n const formatted = formatSkillsForInjection(pending, {\n useSummaries: config.useSummaries,\n skillSettings: config.skillSettings,\n })\n if (formatted) {\n contentToInject.push(formatted)\n log(\"info\", \"Injected triggered skills\", {\n sessionID: input.sessionID,\n skills: pending.map((s) => s.name),\n })\n }\n pendingSkillInjections.delete(input.sessionID)\n }\n\n if (contentToInject.length > 0) {\n firstTextPart.text = `${contentToInject.join(\"\\n\\n\")}\\n\\n---\\n\\n${firstTextPart.text}`\n }\n }\n },\n\n \"tool.execute.after\": async (\n input: {\n tool: string\n sessionID: string\n callID: string\n },\n _output: {\n title: string\n output: string\n metadata: unknown\n }\n ): Promise<void> => {\n if (!FILE_TOOLS.includes(input.tool)) return\n if (!input.sessionID) return\n\n const state = getSessionState(input.sessionID)\n\n const toolArgs = (_output.metadata as { args?: Record<string, unknown> })\n ?.args\n if (!toolArgs) return\n\n const filePath = getFilePathFromArgs(toolArgs)\n if (!filePath) return\n\n const ext = extname(filePath)\n if (ext && config.fileTypeSkills) {\n const extSkills = getSkillsForExtension(ext, config.fileTypeSkills)\n if (extSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, extSkills, \"fileType\", state)\n }\n }\n\n if (config.pathPatterns) {\n const pathSkills = getSkillsForPath(filePath, config.pathPatterns)\n if (pathSkills.length > 0) {\n queueSkillsForInjection(input.sessionID, pathSkills, \"path\", state)\n }\n }\n },\n\n \"experimental.session.compacting\": async (\n input: { sessionID: string },\n output: { context: string[]; prompt?: string }\n ): Promise<void> => {\n if (!config.persistAfterCompaction) return\n\n const state = sessionStates.get(input.sessionID)\n if (!state || state.loadedSkills.size === 0) return\n\n const allLoadedSkills: ParsedSkill[] = []\n for (const name of state.loadedSkills) {\n const skill = skillCache.get(name)\n if (skill) allLoadedSkills.push(skill)\n }\n\n if (allLoadedSkills.length === 0) return\n\n const formatted = formatSkillsForInjection(\n allLoadedSkills,\n { useSummaries: config.useSummaries, skillSettings: config.skillSettings }\n )\n output.context.push(\n `## Preloaded Skills\\n\\nThe following skills were loaded during this session and should persist:\\n\\n${formatted}`\n )\n\n state.initialSkillsInjected = false\n\n log(\"info\", \"Added all loaded skills to compaction context\", {\n sessionID: input.sessionID,\n skillCount: allLoadedSkills.length,\n })\n\n saveAnalytics()\n },\n\n event: async ({ event }: { event: Event }): Promise<void> => {\n if (\n event.type === \"session.deleted\" &&\n \"sessionID\" in event.properties\n ) {\n const sessionID = event.properties.sessionID as string\n sessionStates.delete(sessionID)\n pendingSkillInjections.delete(sessionID)\n analyticsData.delete(sessionID)\n log(\"debug\", \"Cleaned up session state\", { sessionID })\n saveAnalytics()\n }\n },\n }\n}\n\nexport default PreloadSkillsPlugin\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-plugin-preload-skills",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Smart skill loading for OpenCode — automatic, contextual, and budget-aware",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@opencode-ai/plugin": "^1.0.85",
|
|
58
58
|
"@types/node": "^22.0.0",
|
|
59
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
59
60
|
"tsup": "^8.0.0",
|
|
60
61
|
"typescript": "^5.7.0",
|
|
61
62
|
"vitest": "^4.0.18"
|