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 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, useSummaries = false) {
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 content = useSummaries && skill.summary ? skill.summary : skill.content;
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
- const contentToInject = [];
459
- if (!state.initialSkillsInjected && initialFormattedContent) {
460
- contentToInject.push(initialFormattedContent);
461
- state.initialSkillsInjected = true;
462
- log("info", "Injected initial preloaded skills", {
463
- sessionID: input.sessionID,
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: pending.map((s) => s.name)
529
+ skills: initialSkills.map((s) => s.name)
475
530
  });
476
531
  }
477
- pendingSkillInjections.delete(input.sessionID);
478
- }
479
- if (contentToInject.length > 0) {
480
- firstTextPart.text = `${contentToInject.join("\n\n")}
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
@@ -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":";;;;;;;;;AAGO,SAAS,eAAe,IAAA,EAAsB;AACnD,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AAClC;AAEO,SAAS,gBAAA,CAAiB,UAAkB,OAAA,EAA0B;AAC3E,EAAA,IAAI,eAAe,OAAA,CAChB,OAAA,CAAQ,SAAA,EAAW,qBAAyB,EAC5C,OAAA,CAAQ,OAAA,EAAS,gBAAoB,CAAA,CACrC,QAAQ,KAAA,EAAO,gBAAoB,CAAA,CACnC,OAAA,CAAQ,OAAO,cAAkB,CAAA;AAEpC,EAAA,YAAA,GAAe,YAAA,CAAa,OAAA,CAAQ,mBAAA,EAAqB,MAAM,CAAA;AAE/D,EAAA,YAAA,GAAe,YAAA,CACZ,OAAA,CAAQ,0BAAA,EAA4B,aAAa,EACjD,OAAA,CAAQ,qBAAA,EAAuB,IAAI,CAAA,CACnC,QAAQ,qBAAA,EAAuB,OAAO,CAAA,CACtC,OAAA,CAAQ,qBAAqB,MAAM,CAAA;AAEtC,EAAA,MAAM,KAAA,GAAQ,IAAI,MAAA,CAAO,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA,CAAG,CAAA;AAC5C,EAAA,OAAO,KAAA,CAAM,KAAK,QAAQ,CAAA;AAC5B;AASO,SAAS,cAAA,CACd,WACA,UAAA,EACS;AACT,EAAA,IAAI,UAAU,UAAA,EAAY;AACxB,IAAA,MAAM,QAAA,GAAWA,SAAA,CAAK,UAAA,EAAY,SAAA,CAAU,UAAU,CAAA;AACtD,IAAA,IAAI,CAACC,aAAA,CAAW,QAAQ,CAAA,EAAG,OAAO,KAAA;AAAA,EACpC;AAEA,EAAA,IAAI,UAAU,oBAAA,EAAsB;AAClC,IAAA,MAAM,eAAA,GAAkBD,SAAA,CAAK,UAAA,EAAY,cAAc,CAAA;AACvD,IAAA,IAAI,CAACC,aAAA,CAAW,eAAe,CAAA,EAAG,OAAO,KAAA;AAEzC,IAAA,IAAI;AACF,MAAA,MAAM,cAAc,IAAA,CAAK,KAAA,CAAMC,eAAA,CAAa,eAAA,EAAiB,OAAO,CAAC,CAAA;AACrE,MAAA,MAAM,IAAA,GAAO;AAAA,QACX,GAAG,WAAA,CAAY,YAAA;AAAA,QACf,GAAG,WAAA,CAAY,eAAA;AAAA,QACf,GAAG,WAAA,CAAY;AAAA,OACjB;AACA,MAAA,IAAI,CAAC,IAAA,CAAK,SAAA,CAAU,oBAAoB,GAAG,OAAO,KAAA;AAAA,IACpD,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,SAAA,CAAU,MAAM,GAAG,OAAO,KAAA;AAAA,EAC7C;AAEA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,mBAAA,CAAoB,MAAc,QAAA,EAA6B;AAC7E,EAAA,MAAM,SAAA,GAAY,KAAK,WAAA,EAAY;AACnC,EAAA,OAAO,QAAA,CAAS,KAAK,CAAC,EAAA,KAAO,UAAU,QAAA,CAAS,EAAA,CAAG,WAAA,EAAa,CAAC,CAAA;AACnE;;;ACpEA,IAAM,cAAA,GAAiB,UAAA;AAEvB,IAAM,kBAAA,GAAqB;AAAA,EACzB,CAAC,GAAA,KAAgBF,SAAAA,CAAK,GAAA,EAAK,aAAa,QAAQ,CAAA;AAAA,EAChD,CAAC,GAAA,KAAgBA,SAAAA,CAAK,GAAA,EAAK,WAAW,QAAQ,CAAA;AAAA,EAC9C,MAAMA,SAAAA,CAAKG,UAAA,EAAQ,EAAG,SAAA,EAAW,YAAY,QAAQ,CAAA;AAAA,EACrD,MAAMH,SAAAA,CAAKG,UAAA,EAAQ,EAAG,WAAW,QAAQ;AAC3C,CAAA;AAEA,SAAS,aAAA,CAAc,WAAmB,UAAA,EAAmC;AAC3E,EAAA,KAAA,MAAW,WAAW,kBAAA,EAAoB;AACxC,IAAA,MAAM,QAAA,GAAW,QAAQ,UAAU,CAAA;AACnC,IAAA,MAAM,SAAA,GAAYH,SAAAA,CAAK,QAAA,EAAU,SAAA,EAAW,cAAc,CAAA;AAE1D,IAAA,IAAIC,aAAAA,CAAW,SAAS,CAAA,EAAG;AACzB,MAAA,OAAO,SAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAQA,SAAS,iBAAiB,OAAA,EAAkC;AAC1D,EAAA,MAAM,gBAAA,GAAmB,OAAA,CAAQ,KAAA,CAAM,0BAA0B,CAAA;AACjE,EAAA,IAAI,CAAC,gBAAA,GAAmB,CAAC,CAAA,EAAG;AAC1B,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,WAAA,GAAc,iBAAiB,CAAC,CAAA;AACtC,EAAA,MAAM,SAA0B,EAAC;AAEjC,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,KAAA,CAAM,iBAAiB,CAAA;AACrD,EAAA,IAAI,SAAA,GAAY,CAAC,CAAA,EAAG;AAClB,IAAA,MAAA,CAAO,IAAA,GAAO,SAAA,CAAU,CAAC,CAAA,CAAE,IAAA,EAAK;AAAA,EAClC;AAEA,EAAA,MAAM,SAAA,GAAY,WAAA,CAAY,KAAA,CAAM,wBAAwB,CAAA;AAC5D,EAAA,IAAI,SAAA,GAAY,CAAC,CAAA,EAAG;AAClB,IAAA,MAAA,CAAO,WAAA,GAAc,SAAA,CAAU,CAAC,CAAA,CAAE,IAAA,EAAK;AAAA,EACzC;AAEA,EAAA,MAAM,YAAA,GAAe,WAAA,CAAY,KAAA,CAAM,oBAAoB,CAAA;AAC3D,EAAA,IAAI,YAAA,GAAe,CAAC,CAAA,EAAG;AACrB,IAAA,MAAA,CAAO,OAAA,GAAU,YAAA,CAAa,CAAC,CAAA,CAAE,IAAA,EAAK;AAAA,EACxC;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,kBAAA,CAAmB,OAAA,EAAiB,SAAA,GAAoB,GAAA,EAAa;AAC5E,EAAA,MAAM,kBAAA,GAAqB,OAAA,CAAQ,OAAA,CAAQ,8BAAA,EAAgC,EAAE,CAAA;AAE7E,EAAA,MAAM,eAAe,kBAAA,CAAmB,KAAA,CAAM,QAAQ,CAAA,CAAE,CAAC,CAAA,IAAK,EAAA;AAC9D,EAAA,MAAM,OAAA,GAAU,YAAA,CACb,OAAA,CAAQ,YAAA,EAAc,EAAE,EACxB,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,IAAA,EAAK;AAER,EAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,SAAA,EAAW,OAAO,OAAA;AACxC,EAAA,OAAO,OAAA,CAAQ,MAAM,CAAA,EAAG,SAAS,EAAE,OAAA,CAAQ,SAAA,EAAW,EAAE,CAAA,GAAI,KAAA;AAC9D;AAEO,SAAS,SAAA,CAAU,WAAmB,UAAA,EAAwC;AACnF,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,SAAA,EAAW,UAAU,CAAA;AAEpD,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAUC,eAAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AAC9C,IAAA,MAAM,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAQ,GAAI,iBAAiB,OAAO,CAAA;AAE/D,IAAA,OAAO;AAAA,MACL,MAAM,IAAA,IAAQ,SAAA;AAAA,MACd,aAAa,WAAA,IAAe,EAAA;AAAA,MAC5B,OAAA,EAAS,OAAA,IAAW,kBAAA,CAAmB,OAAO,CAAA;AAAA,MAC9C,OAAA;AAAA,MACA,QAAA;AAAA,MACA,UAAA,EAAY,eAAe,OAAO;AAAA,KACpC;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,UAAA,CAAW,YAAsB,UAAA,EAAmC;AAClF,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,UAAU,CAAA,EAAG;AAC9B,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,SAAwB,EAAC;AAE/B,EAAA,KAAA,MAAW,QAAQ,UAAA,EAAY;AAC7B,IAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,IAAA,EAAM,UAAU,CAAA;AACxC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,IACnB;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAOO,SAAS,wBAAA,CACd,MAAA,EACA,OAAA,GAAmC,KAAA,EAC3B;AACR,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AACjD,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,OAAsB,OAAO,OAAA,KAAY,YAC3C,EAAE,YAAA,EAAc,SAAQ,GACxB,OAAA;AAEJ,EAAA,MAAM,kBAAA,GAAqB,KAAK,YAAA,IAAgB,KAAA;AAChD,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,aAAA,IAAiB,EAAC;AAE7C,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU;AAClC,IAAA,MAAM,eAAA,GAAkB,aAAA,CAAc,KAAA,CAAM,IAAI,CAAA,EAAG,UAAA;AACnD,IAAA,MAAM,mBAAmB,eAAA,IAAmB,kBAAA;AAC5C,IAAA,MAAM,UAAU,gBAAA,IAAoB,KAAA,CAAM,OAAA,GAAU,KAAA,CAAM,UAAU,KAAA,CAAM,OAAA;AAC1E,IAAA,OAAO,CAAA,uBAAA,EAA0B,MAAM,IAAI,CAAA;AAAA,EAAO,OAAO;AAAA,kBAAA,CAAA;AAAA,EAC3D,CAAC,CAAA;AAED,EAAA,OAAO,CAAA;AAAA;;AAAA,EAGP,KAAA,CAAM,IAAA,CAAK,MAAM,CAAC;AAAA,mBAAA,CAAA;AAEpB;AAEO,SAAS,qBAAqB,MAAA,EAA+B;AAClE,EAAA,OAAO,MAAA,CAAO,OAAO,CAAC,GAAA,EAAK,UAAU,GAAA,GAAM,KAAA,CAAM,YAAY,CAAC,CAAA;AAChE;AAEO,SAAS,yBAAA,CACd,QACA,SAAA,EACe;AACf,EAAA,MAAM,SAAwB,EAAC;AAC/B,EAAA,IAAI,WAAA,GAAc,CAAA;AAElB,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAI,WAAA,GAAc,KAAA,CAAM,UAAA,IAAc,SAAA,EAAW;AAC/C,MAAA,MAAA,CAAO,KAAK,KAAK,CAAA;AACjB,MAAA,WAAA,IAAe,KAAA,CAAM,UAAA;AAAA,IACvB;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;;;ACzIA,IAAM,eAAA,GAAkB,qBAAA;AACxB,IAAM,kBAAA,GAAqB,+BAAA;AAC3B,IAAM,aAAa,CAAC,MAAA,EAAQ,MAAA,EAAQ,OAAA,EAAS,QAAQ,MAAM,CAAA;AAE3D,IAAM,cAAA,GAAsC;AAAA,EAC1C,QAAQ,EAAC;AAAA,EACT,gBAAgB,EAAC;AAAA,EACjB,aAAa,EAAC;AAAA,EACd,cAAc,EAAC;AAAA,EACf,iBAAiB,EAAC;AAAA,EAClB,QAAQ,EAAC;AAAA,EACT,mBAAmB,EAAC;AAAA,EACpB,eAAe,EAAC;AAAA,EAChB,eAAA,EAAiB,aAAA;AAAA,EACjB,SAAA,EAAW,MAAA;AAAA,EACX,YAAA,EAAc,KAAA;AAAA,EACd,SAAA,EAAW,KAAA;AAAA,EACX,sBAAA,EAAwB,IAAA;AAAA,EACxB,KAAA,EAAO;AACT,CAAA;AAEA,SAAS,eAAe,UAAA,EAAmC;AACzD,EAAA,MAAM,SAAA,GAAY;AAAA,IAChBF,SAAAA,CAAK,UAAA,EAAY,WAAA,EAAa,eAAe,CAAA;AAAA,IAC7CA,SAAAA,CAAK,YAAY,eAAe,CAAA;AAAA,IAChCA,SAAAA,CAAKG,UAAAA,EAAQ,EAAG,SAAA,EAAW,YAAY,eAAe;AAAA,GACxD;AAEA,EAAA,KAAA,MAAW,QAAQ,SAAA,EAAW;AAC5B,IAAA,IAAIF,aAAAA,CAAW,IAAI,CAAA,EAAG;AACpB,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,uBAAuB,GAAA,EAAwC;AACtE,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,SAAiB,EAAC;AAE7C,EAAA,MAAM,SAAmC,EAAC;AAC1C,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AAC9C,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,MAAA,MAAA,CAAO,GAAG,IAAI,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,OAAO,MAAM,QAAQ,CAAA;AAAA,IACzD;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,uBAAuB,GAAA,EAAkC;AAChE,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,SAAU,EAAC;AAEjC,EAAA,OAAO,GAAA,CAAI,MAAA;AAAA,IACT,CAAC,IAAA,KACC,OAAO,IAAA,KAAS,QAAA,IAChB,IAAA,KAAS,IAAA,IACT,OAAO,IAAA,CAAK,KAAA,KAAU,QAAA,IACtB,OAAO,KAAK,EAAA,KAAO;AAAA,GACvB;AACF;AAEA,SAAS,mBAAmB,GAAA,EAA6C;AACvE,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,SAAiB,EAAC;AAE7C,EAAA,MAAM,SAAwC,EAAC;AAC/C,EAAA,KAAA,MAAW,CAAC,SAAA,EAAW,QAAQ,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AACvD,IAAA,IAAI,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,KAAa,IAAA,EAAM;AACrD,MAAA,MAAM,SAAwB,EAAC;AAC/B,MAAA,IAAI,YAAA,IAAgB,QAAA,IAAY,OAAO,QAAA,CAAS,eAAe,SAAA,EAAW;AACxE,QAAA,MAAA,CAAO,aAAa,QAAA,CAAS,UAAA;AAAA,MAC/B;AACA,MAAA,IAAI,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAClC,QAAA,MAAA,CAAO,SAAS,CAAA,GAAI,MAAA;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,eAAe,UAAA,EAAkD;AACxE,EAAA,MAAM,UAAA,GAAa,eAAe,UAAU,CAAA;AAC5C,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAUC,eAAAA,CAAa,UAAA,EAAY,OAAO,CAAA;AAChD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAEjC,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,MAAM,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA,GAAI,MAAA,CAAO,SAAS,EAAC;AAAA,MACxD,cAAA,EAAgB,sBAAA,CAAuB,MAAA,CAAO,cAAc,CAAA;AAAA,MAC5D,WAAA,EAAa,sBAAA,CAAuB,MAAA,CAAO,WAAW,CAAA;AAAA,MACtD,YAAA,EAAc,sBAAA,CAAuB,MAAA,CAAO,YAAY,CAAA;AAAA,MACxD,eAAA,EAAiB,sBAAA,CAAuB,MAAA,CAAO,eAAe,CAAA;AAAA,MAC9D,MAAA,EAAQ,sBAAA,CAAuB,MAAA,CAAO,MAAM,CAAA;AAAA,MAC5C,iBAAA,EAAmB,sBAAA,CAAuB,MAAA,CAAO,iBAAiB,CAAA;AAAA,MAClE,aAAA,EAAe,kBAAA,CAAmB,MAAA,CAAO,aAAa,CAAA;AAAA,MACtD,WACE,OAAO,MAAA,CAAO,SAAA,KAAc,QAAA,GAAW,OAAO,SAAA,GAAY,KAAA,CAAA;AAAA,MAC5D,cACE,OAAO,MAAA,CAAO,YAAA,KAAiB,SAAA,GAC3B,OAAO,YAAA,GACP,KAAA,CAAA;AAAA,MACN,WACE,OAAO,MAAA,CAAO,SAAA,KAAc,SAAA,GAAY,OAAO,SAAA,GAAY,KAAA,CAAA;AAAA,MAC7D,wBACE,OAAO,MAAA,CAAO,sBAAA,KAA2B,SAAA,GACrC,OAAO,sBAAA,GACP,KAAA,CAAA;AAAA,MACN,OAAO,OAAO,MAAA,CAAO,KAAA,KAAU,SAAA,GAAY,OAAO,KAAA,GAAQ,KAAA,CAAA;AAAA,MAC1D,eAAA,EACE,OAAO,eAAA,KAAoB,cAAA,IAC3B,OAAO,eAAA,KAAoB,aAAA,GACtB,OAAO,eAAA,GACR,KAAA;AAAA,KACR;AAAA,EACF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAEA,SAAS,oBAAoB,IAAA,EAA8C;AACzE,EAAA,IAAI,OAAO,IAAA,CAAK,QAAA,KAAa,QAAA,SAAiB,IAAA,CAAK,QAAA;AACnD,EAAA,IAAI,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,SAAiB,IAAA,CAAK,IAAA;AAC/C,EAAA,IAAI,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,SAAiB,IAAA,CAAK,IAAA;AAC/C,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,qBAAA,CACP,KACA,cAAA,EACU;AACV,EAAA,MAAM,SAAmB,EAAC;AAE1B,EAAA,KAAA,MAAW,CAAC,OAAA,EAAS,UAAU,KAAK,MAAA,CAAO,OAAA,CAAQ,cAAc,CAAA,EAAG;AAClE,IAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAK,CAAE,WAAA,EAAa,CAAA;AACvE,IAAA,IAAI,UAAA,CAAW,QAAA,CAAS,GAAA,CAAI,WAAA,EAAa,CAAA,EAAG;AAC1C,MAAA,MAAA,CAAO,IAAA,CAAK,GAAG,UAAU,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,MAAM,CAAC,CAAA;AAC5B;AAEA,SAAS,gBAAA,CACP,UACA,YAAA,EACU;AACV,EAAA,MAAM,SAAmB,EAAC;AAE1B,EAAA,KAAA,MAAW,CAAC,OAAA,EAAS,UAAU,KAAK,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,EAAG;AAChE,IAAA,IAAI,gBAAA,CAAiB,QAAA,EAAU,OAAO,CAAA,EAAG;AACvC,MAAA,MAAA,CAAO,IAAA,CAAK,GAAG,UAAU,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,MAAM,CAAC,CAAA;AAC5B;AAEA,SAAS,kBAAA,CACP,YACA,MAAA,EACU;AACV,EAAA,MAAM,WAAqB,EAAC;AAE5B,EAAA,KAAA,MAAW,QAAQ,UAAA,EAAY;AAC7B,IAAA,IAAI,IAAA,CAAK,WAAW,GAAG,CAAA,IAAK,OAAO,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA,EAAG;AACjD,MAAA,QAAA,CAAS,KAAK,GAAG,MAAA,CAAO,KAAK,KAAA,CAAM,CAAC,CAAC,CAAE,CAAA;AAAA,IACzC,CAAA,MAAO;AACL,MAAA,QAAA,CAAS,KAAK,IAAI,CAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,QAAQ,CAAC,CAAA;AAC9B;AAEO,IAAM,mBAAA,GAA8B,OAAO,GAAA,KAAqB;AACrE,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAA0B;AACpD,EAAA,MAAM,aAAA,uBAAoB,GAAA,EAA2B;AAErD,EAAA,MAAM,UAAA,GAAa,cAAA,CAAe,GAAA,CAAI,SAAS,CAAA;AAC/C,EAAA,MAAM,MAAA,GAA8B;AAAA,IAClC,GAAG,cAAA;AAAA,IACH,GAAG;AAAA,GACL;AAEA,EAAA,MAAM,GAAA,GAAM,CACV,KAAA,EACA,OAAA,EACA,KAAA,KACG;AACH,IAAA,IAAI,KAAA,KAAU,OAAA,IAAW,CAAC,MAAA,CAAO,KAAA,EAAO;AAExC,IAAA,GAAA,CAAI,MAAA,CAAO,IAAI,GAAA,CAAI;AAAA,MACjB,IAAA,EAAM;AAAA,QACJ,OAAA,EAAS,gBAAA;AAAA,QACT,KAAA;AAAA,QACA,OAAA;AAAA,QACA;AAAA;AACF,KACD,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,eAAA,GAAkB,CACtB,SAAA,EACA,SAAA,EACA,WAAA,KACG;AACH,IAAA,IAAI,CAAC,OAAO,SAAA,EAAW;AAEvB,IAAA,IAAI,CAAC,aAAA,CAAc,GAAA,CAAI,SAAS,CAAA,EAAG;AACjC,MAAA,aAAA,CAAc,IAAI,SAAA,EAAW;AAAA,QAC3B,SAAA,EAAW,SAAA;AAAA,QACX,UAAA,sBAAgB,GAAA;AAAI,OACrB,CAAA;AAAA,IACH;AAEA,IAAA,MAAM,IAAA,GAAO,aAAA,CAAc,GAAA,CAAI,SAAS,CAAA;AACxC,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AAErB,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,SAAS,CAAA,EAAG;AAClC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,SAAS,CAAA;AAC3C,MAAA,KAAA,CAAM,SAAA,EAAA;AACN,MAAA,KAAA,CAAM,UAAA,GAAa,GAAA;AAAA,IACrB,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,UAAA,CAAW,IAAI,SAAA,EAAW;AAAA,QAC7B,SAAA;AAAA,QACA,SAAA,EAAW,CAAA;AAAA,QACX,WAAA;AAAA,QACA,WAAA,EAAa,GAAA;AAAA,QACb,UAAA,EAAY;AAAA,OACb,CAAA;AAAA,IACH;AAEA,IAAA,aAAA,EAAc;AAAA,EAChB,CAAA;AAEA,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,IAAI,CAAC,OAAO,SAAA,EAAW;AAEvB,IAAA,IAAI;AACF,MAAA,MAAM,aAAA,GAAgBF,SAAAA,CAAK,GAAA,CAAI,SAAA,EAAW,aAAa,kBAAkB,CAAA;AACzE,MAAA,MAAM,GAAA,GAAMI,aAAQ,aAAa,CAAA;AACjC,MAAA,IAAI,CAACH,aAAAA,CAAW,GAAG,CAAA,EAAG;AACpB,QAAAI,YAAA,CAAU,GAAA,EAAK,EAAE,SAAA,EAAW,IAAA,EAAM,CAAA;AAAA,MACpC;AAEA,MAAA,MAAM,eAAwC,EAAC;AAC/C,MAAA,KAAA,MAAW,CAAC,SAAA,EAAW,IAAI,CAAA,IAAK,aAAA,EAAe;AAC7C,QAAA,YAAA,CAAa,SAAS,CAAA,GAAI;AAAA,UACxB,WAAW,IAAA,CAAK,SAAA;AAAA,UAChB,UAAA,EAAY,MAAA,CAAO,WAAA,CAAY,IAAA,CAAK,UAAU;AAAA,SAChD;AAAA,MACF;AAEA,MAAAC,gBAAA,CAAc,eAAe,IAAA,CAAK,SAAA,CAAU,YAAA,EAAc,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,IACpE,CAAA,CAAA,MAAQ;AACN,MAAA,GAAA,CAAI,QAAQ,0BAA0B,CAAA;AAAA,IACxC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAA,uBAAiB,GAAA,EAAyB;AAEhD,EAAA,MAAM,oBAAA,GAAuB,CAC3B,UAAA,EACA,aAAA,EACA,aACA,SAAA,KACkD;AAClD,IAAA,MAAM,WAAW,kBAAA,CAAmB,UAAA,EAAY,MAAA,CAAO,MAAA,IAAU,EAAE,CAAA;AACnE,IAAA,IAAI,MAAA,GAAS,UAAA,CAAW,QAAA,EAAU,GAAA,CAAI,SAAS,CAAA;AAE/C,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,UAAA,CAAW,GAAA,CAAI,KAAA,CAAM,IAAA,EAAM,KAAK,CAAA;AAAA,IAClC;AAEA,IAAA,IAAI,OAAO,SAAA,EAAW;AACpB,MAAA,MAAM,eAAA,GAAkB,OAAO,SAAA,GAAY,aAAA;AAC3C,MAAA,MAAA,GAAS,yBAAA,CAA0B,QAAQ,eAAe,CAAA;AAAA,IAC5D;AAEA,IAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,MAAA,eAAA,CAAgB,SAAA,EAAW,KAAA,CAAM,IAAA,EAAM,WAAW,CAAA;AAAA,IACpD;AAEA,IAAA,OAAO;AAAA,MACL,MAAA;AAAA,MACA,UAAA,EAAY,qBAAqB,MAAM;AAAA,KACzC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,2BAA2B,MAAgB;AAC/C,IAAA,IAAI,CAAC,MAAA,CAAO,iBAAA,EAAmB,MAAA,SAAe,EAAC;AAE/C,IAAA,MAAM,WAAqB,EAAC;AAC5B,IAAA,KAAA,MAAW,EAAE,KAAA,EAAO,EAAA,EAAI,SAAA,EAAU,IAAK,OAAO,iBAAA,EAAmB;AAC/D,MAAA,IAAI,cAAA,CAAe,SAAA,EAAW,GAAA,CAAI,SAAS,CAAA,EAAG;AAC5C,QAAA,QAAA,CAAS,KAAK,KAAK,CAAA;AAAA,MACrB;AAAA,IACF;AAEA,IAAA,OAAO,QAAA;AAAA,EACT,CAAA;AAEA,EAAA,IAAI,gBAA+B,EAAC;AACpC,EAAA,IAAI,uBAAA,GAA0B,EAAA;AAC9B,EAAA,IAAI,iBAAA,GAAoB,CAAA;AAExB,EAAA,MAAM,oBAAA,GAAuB;AAAA,IAC3B,GAAG,MAAA,CAAO,MAAA;AAAA,IACV,GAAG,wBAAA;AAAyB,GAC9B;AAEA,EAAA,IAAI,oBAAA,CAAqB,SAAS,CAAA,EAAG;AACnC,IAAA,MAAM,MAAA,GAAS,oBAAA;AAAA,MACb,oBAAA;AAAA,MACA,CAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,aAAA,GAAgB,MAAA,CAAO,MAAA;AACvB,IAAA,iBAAA,GAAoB,MAAA,CAAO,UAAA;AAC3B,IAAA,uBAAA,GAA0B,wBAAA;AAAA,MACxB,aAAA;AAAA,MACA,EAAE,YAAA,EAAc,MAAA,CAAO,YAAA,EAAc,aAAA,EAAe,OAAO,aAAA;AAAc,KAC3E;AAEA,IAAA,MAAM,cAAc,aAAA,CAAc,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA;AACnD,IAAA,MAAM,eAAe,oBAAA,CAAqB,MAAA;AAAA,MACxC,CAAC,CAAA,KAAM,CAAC,WAAA,CAAY,QAAA,CAAS,CAAC,CAAA,IAAK,CAAC,CAAA,CAAE,UAAA,CAAW,GAAG;AAAA,KACtD;AAEA,IAAA,GAAA,CAAI,MAAA,EAAQ,CAAA,OAAA,EAAU,aAAA,CAAc,MAAM,CAAA,eAAA,CAAA,EAAmB;AAAA,MAC3D,MAAA,EAAQ,WAAA;AAAA,MACR,MAAA,EAAQ,iBAAA;AAAA,MACR,OAAA,EAAS,YAAA,CAAa,MAAA,GAAS,CAAA,GAAI,YAAA,GAAe;AAAA,KACnD,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,kBAAA,GACJ,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,kBAAkB,EAAE,CAAA,CAAE,MAAA,GAAS,KAClD,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,WAAA,IAAe,EAAE,CAAA,CAAE,MAAA,GAAS,CAAA,IAC/C,OAAO,IAAA,CAAK,MAAA,CAAO,YAAA,IAAgB,EAAE,CAAA,CAAE,MAAA,GAAS,CAAA,IAChD,MAAA,CAAO,KAAK,MAAA,CAAO,eAAA,IAAmB,EAAE,EAAE,MAAA,GAAS,CAAA;AAErD,EAAA,IAAI,oBAAA,CAAqB,MAAA,KAAW,CAAA,IAAK,CAAC,kBAAA,EAAoB;AAC5D,IAAA,GAAA,CAAI,QAAQ,4DAA4D,CAAA;AAAA,EAC1E;AAEA,EAAA,MAAM,eAAA,GAAkB,CAAC,SAAA,KAAoC;AAC3D,IAAA,IAAI,CAAC,aAAA,CAAc,GAAA,CAAI,SAAS,CAAA,EAAG;AACjC,MAAA,aAAA,CAAc,IAAI,SAAA,EAAW;AAAA,QAC3B,qBAAA,EAAuB,KAAA;AAAA,QACvB,YAAA,EAAc,IAAI,GAAA,CAAI,aAAA,CAAc,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAC,CAAA;AAAA,QACtD,eAAA,EAAiB;AAAA,OAClB,CAAA;AAAA,IACH;AACA,IAAA,OAAO,aAAA,CAAc,IAAI,SAAS,CAAA;AAAA,EACpC,CAAA;AAEA,EAAA,MAAM,sBAAA,uBAA6B,GAAA,EAA2B;AAE9D,EAAA,MAAM,uBAAA,GAA0B,CAC9B,SAAA,EACA,UAAA,EACA,aACA,KAAA,KACG;AACH,IAAA,MAAM,aAAA,GAAgB,UAAA,CAAW,MAAA,CAAO,CAAC,IAAA,KAAS,CAAC,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,IAAI,CAAC,CAAA;AAC/E,IAAA,IAAI,aAAA,CAAc,WAAW,CAAA,EAAG;AAEhC,IAAA,MAAM,MAAA,GAAS,oBAAA;AAAA,MACb,aAAA;AAAA,MACA,KAAA,CAAM,eAAA;AAAA,MACN,WAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,IAAI,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG;AAC5B,MAAA,KAAA,MAAW,KAAA,IAAS,OAAO,MAAA,EAAQ;AACjC,QAAA,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA;AAAA,MACnC;AACA,MAAA,KAAA,CAAM,mBAAmB,MAAA,CAAO,UAAA;AAEhC,MAAA,MAAM,QAAA,GAAW,sBAAA,CAAuB,GAAA,CAAI,SAAS,KAAK,EAAC;AAC3D,MAAA,sBAAA,CAAuB,GAAA,CAAI,WAAW,CAAC,GAAG,UAAU,GAAG,MAAA,CAAO,MAAM,CAAC,CAAA;AAErE,MAAA,GAAA,CAAI,OAAA,EAAS,CAAA,OAAA,EAAU,WAAW,CAAA,qBAAA,CAAA,EAAyB;AAAA,QACzD,SAAA;AAAA,QACA,QAAQ,MAAA,CAAO,MAAA,CAAO,IAAI,CAAC,CAAA,KAAM,EAAE,IAAI,CAAA;AAAA,QACvC,QAAQ,MAAA,CAAO;AAAA,OAChB,CAAA;AAAA,IACH;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,wBAAA,GAA2B,OAAO,eAAA,KAAoB,cAAA;AAE5D,EAAA,OAAO;AAAA,IACL,oCAAA,EAAsC,wBAAA,GAClC,OACE,KAAA,EACA,MAAA,KACkB;AAClB,MAAA,IAAI,CAAC,MAAM,SAAA,EAAW;AAEtB,MAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,KAAA,CAAM,SAAS,CAAA;AAC7C,MAAA,MAAM,iBAAgC,EAAC;AAEvC,MAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5B,QAAA,cAAA,CAAe,IAAA,CAAK,GAAG,aAAa,CAAA;AAAA,MACtC;AAEA,MAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,YAAA,EAAc;AACrC,QAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA;AACjC,QAAA,IAAI,KAAA,IAAS,CAAC,cAAA,CAAe,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,IAAI,CAAA,EAAG;AACzD,UAAA,cAAA,CAAe,KAAK,KAAK,CAAA;AAAA,QAC3B;AAAA,MACF;AAEA,MAAA,MAAM,OAAA,GAAU,sBAAA,CAAuB,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA;AAC1D,MAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACjC,QAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,UAAA,IAAI,CAAC,eAAe,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,KAAA,CAAM,IAAI,CAAA,EAAG;AACtD,YAAA,cAAA,CAAe,KAAK,KAAK,CAAA;AAAA,UAC3B;AAAA,QACF;AACA,QAAA,sBAAA,CAAuB,MAAA,CAAO,MAAM,SAAS,CAAA;AAAA,MAC/C;AAEA,MAAA,IAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AAC7B,QAAA,MAAM,SAAA,GAAY,yBAAyB,cAAA,EAAgB;AAAA,UACzD,cAAc,MAAA,CAAO,YAAA;AAAA,UACrB,eAAe,MAAA,CAAO;AAAA,SACvB,CAAA;AACD,QAAA,MAAA,CAAO,MAAA,CAAO,KAAK,SAAS,CAAA;AAE5B,QAAA,IAAI,CAAC,KAAA,CAAM,qBAAA,IAAyB,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5D,UAAA,KAAA,CAAM,qBAAA,GAAwB,IAAA;AAC9B,UAAA,GAAA,CAAI,QAAQ,oCAAA,EAAsC;AAAA,YAChD,WAAW,KAAA,CAAM,SAAA;AAAA,YACjB,QAAQ,cAAA,CAAe,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAI;AAAA,WACzC,CAAA;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAA,GACA,MAAA;AAAA,IAEJ,cAAA,EAAgB,OACd,KAAA,EAOA,MAAA,KACkB;AAClB,MAAA,IAAI,CAAC,MAAM,SAAA,EAAW;AAEtB,MAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,KAAA,CAAM,SAAS,CAAA;AAC7C,MAAA,MAAM,aAAA,GAAgB,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,MAAM,CAAA;AAChE,MAAA,IAAI,CAAC,aAAA,IAAiB,EAAE,MAAA,IAAU,aAAA,CAAA,EAAgB;AAElD,MAAA,MAAM,cAAc,aAAA,CAAc,IAAA;AAElC,MAAA,IAAI,MAAM,KAAA,IAAS,MAAA,CAAO,WAAA,GAAc,KAAA,CAAM,KAAK,CAAA,EAAG;AACpD,QAAA,uBAAA;AAAA,UACE,KAAA,CAAM,SAAA;AAAA,UACN,MAAA,CAAO,WAAA,CAAY,KAAA,CAAM,KAAK,CAAA;AAAA,UAC9B,OAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAEA,MAAA,IAAI,OAAO,eAAA,EAAiB;AAC1B,QAAA,KAAA,MAAW,CAAC,OAAA,EAAS,UAAU,CAAA,IAAK,MAAA,CAAO,OAAA;AAAA,UACzC,MAAA,CAAO;AAAA,SACT,EAAG;AACD,UAAA,IAAI,mBAAA,CAAoB,WAAA,EAAa,CAAC,OAAO,CAAC,CAAA,EAAG;AAC/C,YAAA,uBAAA;AAAA,cACE,KAAA,CAAM,SAAA;AAAA,cACN,UAAA;AAAA,cACA,SAAA;AAAA,cACA;AAAA,aACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,wBAAA,EAA0B;AAC7B,QAAA,MAAM,kBAA4B,EAAC;AAEnC,QAAA,IAAI,CAAC,KAAA,CAAM,qBAAA,IAAyB,uBAAA,EAAyB;AAC3D,UAAA,eAAA,CAAgB,KAAK,uBAAuB,CAAA;AAC5C,UAAA,KAAA,CAAM,qBAAA,GAAwB,IAAA;AAC9B,UAAA,GAAA,CAAI,QAAQ,mCAAA,EAAqC;AAAA,YAC/C,WAAW,KAAA,CAAM,SAAA;AAAA,YACjB,QAAQ,aAAA,CAAc,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAI;AAAA,WACxC,CAAA;AAAA,QACH;AAEA,QAAA,MAAM,OAAA,GAAU,sBAAA,CAAuB,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA;AAC1D,QAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACjC,UAAA,MAAM,SAAA,GAAY,yBAAyB,OAAA,EAAS;AAAA,YAClD,cAAc,MAAA,CAAO,YAAA;AAAA,YACrB,eAAe,MAAA,CAAO;AAAA,WACvB,CAAA;AACD,UAAA,IAAI,SAAA,EAAW;AACb,YAAA,eAAA,CAAgB,KAAK,SAAS,CAAA;AAC9B,YAAA,GAAA,CAAI,QAAQ,2BAAA,EAA6B;AAAA,cACvC,WAAW,KAAA,CAAM,SAAA;AAAA,cACjB,QAAQ,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,EAAE,IAAI;AAAA,aAClC,CAAA;AAAA,UACH;AACA,UAAA,sBAAA,CAAuB,MAAA,CAAO,MAAM,SAAS,CAAA;AAAA,QAC/C;AAEA,QAAA,IAAI,eAAA,CAAgB,SAAS,CAAA,EAAG;AAC9B,UAAA,aAAA,CAAc,IAAA,GAAO,CAAA,EAAG,eAAA,CAAgB,IAAA,CAAK,MAAM,CAAC;;AAAA;;AAAA,EAAc,cAAc,IAAI,CAAA,CAAA;AAAA,QACtF;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IAEA,oBAAA,EAAsB,OACpB,KAAA,EAKA,OAAA,KAKkB;AAClB,MAAA,IAAI,CAAC,UAAA,CAAW,QAAA,CAAS,KAAA,CAAM,IAAI,CAAA,EAAG;AACtC,MAAA,IAAI,CAAC,MAAM,SAAA,EAAW;AAEtB,MAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,KAAA,CAAM,SAAS,CAAA;AAE7C,MAAA,MAAM,QAAA,GAAY,QAAQ,QAAA,EACtB,IAAA;AACJ,MAAA,IAAI,CAAC,QAAA,EAAU;AAEf,MAAA,MAAM,QAAA,GAAW,oBAAoB,QAAQ,CAAA;AAC7C,MAAA,IAAI,CAAC,QAAA,EAAU;AAEf,MAAA,MAAM,GAAA,GAAMC,aAAQ,QAAQ,CAAA;AAC5B,MAAA,IAAI,GAAA,IAAO,OAAO,cAAA,EAAgB;AAChC,QAAA,MAAM,SAAA,GAAY,qBAAA,CAAsB,GAAA,EAAK,MAAA,CAAO,cAAc,CAAA;AAClE,QAAA,IAAI,SAAA,CAAU,SAAS,CAAA,EAAG;AACxB,UAAA,uBAAA,CAAwB,KAAA,CAAM,SAAA,EAAW,SAAA,EAAW,UAAA,EAAY,KAAK,CAAA;AAAA,QACvE;AAAA,MACF;AAEA,MAAA,IAAI,OAAO,YAAA,EAAc;AACvB,QAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,QAAA,EAAU,MAAA,CAAO,YAAY,CAAA;AACjE,QAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACzB,UAAA,uBAAA,CAAwB,KAAA,CAAM,SAAA,EAAW,UAAA,EAAY,MAAA,EAAQ,KAAK,CAAA;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IAEA,iCAAA,EAAmC,OACjC,KAAA,EACA,MAAA,KACkB;AAClB,MAAA,IAAI,CAAC,OAAO,sBAAA,EAAwB;AAEpC,MAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,GAAA,CAAI,KAAA,CAAM,SAAS,CAAA;AAC/C,MAAA,IAAI,CAAC,KAAA,IAAS,KAAA,CAAM,YAAA,CAAa,SAAS,CAAA,EAAG;AAE7C,MAAA,MAAM,kBAAiC,EAAC;AACxC,MAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,YAAA,EAAc;AACrC,QAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA;AACjC,QAAA,IAAI,KAAA,EAAO,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA;AAAA,MACvC;AAEA,MAAA,IAAI,eAAA,CAAgB,WAAW,CAAA,EAAG;AAElC,MAAA,MAAM,SAAA,GAAY,wBAAA;AAAA,QAChB,eAAA;AAAA,QACA,EAAE,YAAA,EAAc,MAAA,CAAO,YAAA,EAAc,aAAA,EAAe,OAAO,aAAA;AAAc,OAC3E;AACA,MAAA,MAAA,CAAO,OAAA,CAAQ,IAAA;AAAA,QACb,CAAA;;AAAA;;AAAA,EAAsG,SAAS,CAAA;AAAA,OACjH;AAEA,MAAA,KAAA,CAAM,qBAAA,GAAwB,KAAA;AAE9B,MAAA,GAAA,CAAI,QAAQ,+CAAA,EAAiD;AAAA,QAC3D,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,YAAY,eAAA,CAAgB;AAAA,OAC7B,CAAA;AAED,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAAA,IAEA,KAAA,EAAO,OAAO,EAAE,KAAA,EAAM,KAAuC;AAC3D,MAAA,IACE,KAAA,CAAM,IAAA,KAAS,iBAAA,IACf,WAAA,IAAe,MAAM,UAAA,EACrB;AACA,QAAA,MAAM,SAAA,GAAY,MAAM,UAAA,CAAW,SAAA;AACnC,QAAA,aAAA,CAAc,OAAO,SAAS,CAAA;AAC9B,QAAA,sBAAA,CAAuB,OAAO,SAAS,CAAA;AACvC,QAAA,aAAA,CAAc,OAAO,SAAS,CAAA;AAC9B,QAAA,GAAA,CAAI,OAAA,EAAS,0BAAA,EAA4B,EAAE,SAAA,EAAW,CAAA;AACtD,QAAA,aAAA,EAAc;AAAA,MAChB;AAAA,IACF;AAAA,GACF;AACF;AAEA,IAAO,aAAA,GAAQ","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
- declare function formatSkillsForInjection(skills: ParsedSkill[], useSummaries?: boolean): string;
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
- declare function formatSkillsForInjection(skills: ParsedSkill[], useSummaries?: boolean): string;
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, useSummaries = false) {
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 content = useSummaries && skill.summary ? skill.summary : skill.content;
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
- const contentToInject = [];
455
- if (!state.initialSkillsInjected && initialFormattedContent) {
456
- contentToInject.push(initialFormattedContent);
457
- state.initialSkillsInjected = true;
458
- log("info", "Injected initial preloaded skills", {
459
- sessionID: input.sessionID,
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: pending.map((s) => s.name)
525
+ skills: initialSkills.map((s) => s.name)
471
526
  });
472
527
  }
473
- pendingSkillInjections.delete(input.sessionID);
474
- }
475
- if (contentToInject.length > 0) {
476
- firstTextPart.text = `${contentToInject.join("\n\n")}
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.0",
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"