openvibe 0.58.3 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +50 -3019
  2. package/README.md +267 -98
  3. package/dist/core/agent-modes.d.ts +16 -0
  4. package/dist/core/agent-modes.d.ts.map +1 -0
  5. package/dist/core/agent-modes.js +88 -0
  6. package/dist/core/agent-modes.js.map +1 -0
  7. package/dist/core/agent-session.d.ts +26 -0
  8. package/dist/core/agent-session.d.ts.map +1 -1
  9. package/dist/core/agent-session.js +84 -1
  10. package/dist/core/agent-session.js.map +1 -1
  11. package/dist/core/compaction/compaction.d.ts.map +1 -1
  12. package/dist/core/compaction/compaction.js +1 -1
  13. package/dist/core/compaction/compaction.js.map +1 -1
  14. package/dist/core/context-architecture.d.ts +12 -0
  15. package/dist/core/context-architecture.d.ts.map +1 -0
  16. package/dist/core/context-architecture.js +14 -0
  17. package/dist/core/context-architecture.js.map +1 -0
  18. package/dist/core/context-manager.d.ts +162 -0
  19. package/dist/core/context-manager.d.ts.map +1 -0
  20. package/dist/core/context-manager.js +311 -0
  21. package/dist/core/context-manager.js.map +1 -0
  22. package/dist/core/context-provider-interface.d.ts +134 -0
  23. package/dist/core/context-provider-interface.d.ts.map +1 -0
  24. package/dist/core/context-provider-interface.js +6 -0
  25. package/dist/core/context-provider-interface.js.map +1 -0
  26. package/dist/core/context-provider-registry.d.ts +78 -0
  27. package/dist/core/context-provider-registry.d.ts.map +1 -0
  28. package/dist/core/context-provider-registry.js +164 -0
  29. package/dist/core/context-provider-registry.js.map +1 -0
  30. package/dist/core/index.d.ts +2 -0
  31. package/dist/core/index.d.ts.map +1 -1
  32. package/dist/core/index.js +9 -0
  33. package/dist/core/index.js.map +1 -1
  34. package/dist/core/large-context-provider.d.ts +87 -0
  35. package/dist/core/large-context-provider.d.ts.map +1 -0
  36. package/dist/core/large-context-provider.js +391 -0
  37. package/dist/core/large-context-provider.js.map +1 -0
  38. package/dist/core/skills.d.ts.map +1 -1
  39. package/dist/core/skills.js +52 -5
  40. package/dist/core/skills.js.map +1 -1
  41. package/dist/core/slash-commands.d.ts.map +1 -1
  42. package/dist/core/slash-commands.js +1 -0
  43. package/dist/core/slash-commands.js.map +1 -1
  44. package/dist/core/system-prompt.d.ts +6 -4
  45. package/dist/core/system-prompt.d.ts.map +1 -1
  46. package/dist/core/system-prompt.js +129 -63
  47. package/dist/core/system-prompt.js.map +1 -1
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +2 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/modes/interactive/components/skills-selector.d.ts +13 -0
  53. package/dist/modes/interactive/components/skills-selector.d.ts.map +1 -0
  54. package/dist/modes/interactive/components/skills-selector.js +49 -0
  55. package/dist/modes/interactive/components/skills-selector.js.map +1 -0
  56. package/dist/modes/interactive/interactive-mode.d.ts +2 -2
  57. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  58. package/dist/modes/interactive/interactive-mode.js +44 -37
  59. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  60. package/docs/system-prompt-template.md +176 -0
  61. package/examples/skills/README.md +93 -0
  62. package/examples/skills/api-design/SKILL.md +80 -0
  63. package/examples/skills/code-review/SKILL.md +68 -0
  64. package/examples/skills/git-workflow/SKILL.md +108 -0
  65. package/examples/skills/testing/SKILL.md +94 -0
  66. package/package.json +2 -2
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Large Context Provider Implementation
3
+ * Provides 1M context window support for compatible models
4
+ * This is a third-party architecture implementation
5
+ */
6
+ /**
7
+ * Large context model definitions
8
+ */
9
+ export const LARGE_CONTEXT_DEFINITIONS = {
10
+ // ═══════════════════════════════════════════════════════════════
11
+ // Google Gemini - 1M Context
12
+ // ═══════════════════════════════════════════════════════════════
13
+ "gemini-1.5-pro": {
14
+ contextWindow: 1000000,
15
+ maxTokens: 8192,
16
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
17
+ },
18
+ "gemini-1.5-flash": {
19
+ contextWindow: 1000000,
20
+ maxTokens: 8192,
21
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
22
+ },
23
+ "gemini-2.0-flash": {
24
+ contextWindow: 1000000,
25
+ maxTokens: 8192,
26
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
27
+ },
28
+ "gemini-2.0-pro": {
29
+ contextWindow: 1000000,
30
+ maxTokens: 8192,
31
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
32
+ },
33
+ // ═══════════════════════════════════════════════════════════════
34
+ // Anthropic Claude - 200K Context
35
+ // ═══════════════════════════════════════════════════════════════
36
+ "claude-3-opus-20240229": {
37
+ contextWindow: 200000,
38
+ maxTokens: 4096,
39
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
40
+ },
41
+ "claude-3-sonnet-20240229": {
42
+ contextWindow: 200000,
43
+ maxTokens: 4096,
44
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
45
+ },
46
+ "claude-3-haiku-20240307": {
47
+ contextWindow: 200000,
48
+ maxTokens: 4096,
49
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
50
+ },
51
+ "claude-3-5-sonnet-20241022": {
52
+ contextWindow: 200000,
53
+ maxTokens: 8192,
54
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
55
+ },
56
+ "claude-3-5-haiku-20241022": {
57
+ contextWindow: 200000,
58
+ maxTokens: 8192,
59
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
60
+ },
61
+ "claude-sonnet-4-20250514": {
62
+ contextWindow: 200000,
63
+ maxTokens: 16384,
64
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
65
+ },
66
+ // ═══════════════════════════════════════════════════════════════
67
+ // OpenAI - 128K Context
68
+ // ═══════════════════════════════════════════════════════════════
69
+ "gpt-4-turbo": {
70
+ contextWindow: 128000,
71
+ maxTokens: 4096,
72
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
73
+ },
74
+ "gpt-4-turbo-preview": {
75
+ contextWindow: 128000,
76
+ maxTokens: 4096,
77
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
78
+ },
79
+ "gpt-4o": {
80
+ contextWindow: 128000,
81
+ maxTokens: 16384,
82
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
83
+ },
84
+ "gpt-4o-mini": {
85
+ contextWindow: 128000,
86
+ maxTokens: 16384,
87
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
88
+ },
89
+ "gpt-4-0125-preview": {
90
+ contextWindow: 128000,
91
+ maxTokens: 4096,
92
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
93
+ },
94
+ // ═══════════════════════════════════════════════════════════════
95
+ // DeepSeek - 64K Context
96
+ // ═══════════════════════════════════════════════════════════════
97
+ "deepseek-chat": {
98
+ contextWindow: 64000,
99
+ maxTokens: 4096,
100
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
101
+ },
102
+ "deepseek-coder": {
103
+ contextWindow: 64000,
104
+ maxTokens: 4096,
105
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
106
+ },
107
+ "deepseek-reasoner": {
108
+ contextWindow: 64000,
109
+ maxTokens: 8192,
110
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
111
+ },
112
+ // ═══════════════════════════════════════════════════════════════
113
+ // Alibaba Qwen - Up to 1M Context
114
+ // ═══════════════════════════════════════════════════════════════
115
+ "qwen-2.5-72b-instruct": {
116
+ contextWindow: 131072,
117
+ maxTokens: 8192,
118
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
119
+ },
120
+ "qwen-2.5-32b-instruct": {
121
+ contextWindow: 131072,
122
+ maxTokens: 8192,
123
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
124
+ },
125
+ "qwen-max": {
126
+ contextWindow: 1000000,
127
+ maxTokens: 65536,
128
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
129
+ },
130
+ "qwen-max-longcontext": {
131
+ contextWindow: 1000000,
132
+ maxTokens: 65536,
133
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
134
+ },
135
+ // ═══════════════════════════════════════════════════════════════
136
+ // Moonshot Kimi - Up to 128K Context
137
+ // ═══════════════════════════════════════════════════════════════
138
+ "moonshot-v1-8k": {
139
+ contextWindow: 8192,
140
+ maxTokens: 4096,
141
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
142
+ },
143
+ "moonshot-v1-32k": {
144
+ contextWindow: 32768,
145
+ maxTokens: 4096,
146
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
147
+ },
148
+ "moonshot-v1-128k": {
149
+ contextWindow: 131072,
150
+ maxTokens: 4096,
151
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
152
+ },
153
+ // ═══════════════════════════════════════════════════════════════
154
+ // Meta Llama 3.1 - 128K Context
155
+ // ═══════════════════════════════════════════════════════════════
156
+ "llama-3.1-405b-instruct": {
157
+ contextWindow: 128000,
158
+ maxTokens: 16384,
159
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
160
+ },
161
+ "llama-3.1-70b-instruct": {
162
+ contextWindow: 128000,
163
+ maxTokens: 16384,
164
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
165
+ },
166
+ "llama-3.1-8b-instruct": {
167
+ contextWindow: 128000,
168
+ maxTokens: 16384,
169
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
170
+ },
171
+ // ═══════════════════════════════════════════════════════════════
172
+ // Mistral - Up to 128K Context
173
+ // ═══════════════════════════════════════════════════════════════
174
+ "mistral-large-2407": {
175
+ contextWindow: 128000,
176
+ maxTokens: 8192,
177
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
178
+ },
179
+ "mistral-large-2402": {
180
+ contextWindow: 32000,
181
+ maxTokens: 8192,
182
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
183
+ },
184
+ // ═══════════════════════════════════════════════════════════════
185
+ // 01.AI Yi - Up to 32K Context
186
+ // ═══════════════════════════════════════════════════════════════
187
+ "yi-lightning": {
188
+ contextWindow: 16384,
189
+ maxTokens: 4096,
190
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
191
+ },
192
+ "yi-large": {
193
+ contextWindow: 32768,
194
+ maxTokens: 4096,
195
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
196
+ },
197
+ // ═══════════════════════════════════════════════════════════════
198
+ // Zhipu GLM - 128K Context
199
+ // ═══════════════════════════════════════════════════════════════
200
+ "glm-4": {
201
+ contextWindow: 128000,
202
+ maxTokens: 4096,
203
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
204
+ },
205
+ "glm-4-plus": {
206
+ contextWindow: 128000,
207
+ maxTokens: 4096,
208
+ capabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },
209
+ },
210
+ // ═══════════════════════════════════════════════════════════════
211
+ // Groq Models - Varies
212
+ // ═══════════════════════════════════════════════════════════════
213
+ "llama-3.3-70b-versatile": {
214
+ contextWindow: 128000,
215
+ maxTokens: 8192,
216
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },
217
+ },
218
+ "llama-3.3-70b-specdec": {
219
+ contextWindow: 8192,
220
+ maxTokens: 8192,
221
+ capabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: false },
222
+ },
223
+ };
224
+ /**
225
+ * Large Context Provider
226
+ * Implements the IContextProvider interface for 1M context support
227
+ */
228
+ export class LargeContextProvider {
229
+ name = "large-context";
230
+ version = "1.0.0";
231
+ customModels = new Map();
232
+ /**
233
+ * Check if this provider supports a given model
234
+ */
235
+ supportsModel(modelId) {
236
+ const normalized = this.normalizeModelId(modelId);
237
+ return normalized in LARGE_CONTEXT_DEFINITIONS || this.customModels.has(normalized);
238
+ }
239
+ /**
240
+ * Get context window for a model
241
+ */
242
+ getContextWindow(modelId) {
243
+ return this.getContextConfig(modelId).contextWindow;
244
+ }
245
+ /**
246
+ * Get max output tokens for a model
247
+ */
248
+ getMaxTokens(modelId) {
249
+ return this.getContextConfig(modelId).maxTokens;
250
+ }
251
+ /**
252
+ * Get full context configuration for a model
253
+ */
254
+ getContextConfig(modelId) {
255
+ const normalized = this.normalizeModelId(modelId);
256
+ // Check custom models first
257
+ const custom = this.customModels.get(normalized);
258
+ if (custom) {
259
+ return {
260
+ contextWindow: custom.contextWindow,
261
+ maxTokens: custom.maxTokens,
262
+ supportsStreaming: custom.capabilities.supportsStreaming,
263
+ supportsVision: custom.capabilities.supportsVision,
264
+ supportsFunctions: custom.capabilities.supportsFunctions,
265
+ };
266
+ }
267
+ // Check known models
268
+ const definition = LARGE_CONTEXT_DEFINITIONS[normalized];
269
+ if (definition) {
270
+ return {
271
+ contextWindow: definition.contextWindow,
272
+ maxTokens: definition.maxTokens,
273
+ supportsStreaming: definition.capabilities.supportsStreaming,
274
+ supportsVision: definition.capabilities.supportsVision,
275
+ supportsFunctions: definition.capabilities.supportsFunctions,
276
+ };
277
+ }
278
+ // Default: 1M context for unknown models
279
+ return {
280
+ contextWindow: 1000000,
281
+ maxTokens: 65536,
282
+ supportsStreaming: true,
283
+ supportsVision: true,
284
+ supportsFunctions: true,
285
+ };
286
+ }
287
+ /**
288
+ * Process messages before sending to API
289
+ */
290
+ processMessages(messages, modelId) {
291
+ const config = this.getContextConfig(modelId);
292
+ const messageStr = JSON.stringify(messages);
293
+ const estimatedTokens = Math.ceil(messageStr.length / 4);
294
+ return {
295
+ messages,
296
+ tokenCount: estimatedTokens,
297
+ modified: false,
298
+ metadata: {
299
+ truncated: estimatedTokens > config.contextWindow,
300
+ },
301
+ };
302
+ }
303
+ /**
304
+ * Handle context overflow
305
+ */
306
+ handleOverflow(messages, modelId, tokenCount) {
307
+ const config = this.getContextConfig(modelId);
308
+ if (tokenCount <= config.contextWindow) {
309
+ return { action: "truncate", messages };
310
+ }
311
+ // For large context models, try to keep as much as possible
312
+ if (config.contextWindow >= 100000) {
313
+ // For 1M context, we likely have enough space
314
+ return {
315
+ action: "truncate",
316
+ messages,
317
+ metadata: {
318
+ originalTokens: tokenCount,
319
+ contextWindow: config.contextWindow,
320
+ keepRatio: config.contextWindow / tokenCount,
321
+ },
322
+ };
323
+ }
324
+ return {
325
+ action: "summarize",
326
+ metadata: {
327
+ originalTokens: tokenCount,
328
+ contextWindow: config.contextWindow,
329
+ },
330
+ };
331
+ }
332
+ /**
333
+ * Register a custom model with context configuration
334
+ */
335
+ registerCustomModel(modelId, config) {
336
+ const normalized = this.normalizeModelId(modelId);
337
+ this.customModels.set(normalized, {
338
+ contextWindow: config.contextWindow,
339
+ maxTokens: config.maxTokens,
340
+ capabilities: {
341
+ supportsStreaming: true,
342
+ supportsVision: config.supportsVision ?? true,
343
+ supportsFunctions: config.supportsFunctions ?? true,
344
+ },
345
+ });
346
+ }
347
+ /**
348
+ * Enhance a model with large context configuration
349
+ */
350
+ enhanceModel(model) {
351
+ const config = this.getContextConfig(model.id);
352
+ return {
353
+ ...model,
354
+ contextWindow: config.contextWindow,
355
+ maxTokens: config.maxTokens,
356
+ };
357
+ }
358
+ /**
359
+ * Get all known large context models
360
+ */
361
+ getKnownModels() {
362
+ return Object.keys(LARGE_CONTEXT_DEFINITIONS);
363
+ }
364
+ /**
365
+ * Check if a model has 1M context
366
+ */
367
+ isMillionContextModel(modelId) {
368
+ const config = this.getContextConfig(modelId);
369
+ return config.contextWindow >= 1000000;
370
+ }
371
+ /**
372
+ * Normalize model ID for matching
373
+ */
374
+ normalizeModelId(modelId) {
375
+ return modelId.toLowerCase().trim();
376
+ }
377
+ }
378
+ /**
379
+ * Singleton instance
380
+ */
381
+ let largeContextProviderInstance = null;
382
+ /**
383
+ * Get the singleton instance
384
+ */
385
+ export function getLargeContextProvider() {
386
+ if (!largeContextProviderInstance) {
387
+ largeContextProviderInstance = new LargeContextProvider();
388
+ }
389
+ return largeContextProviderInstance;
390
+ }
391
+ //# sourceMappingURL=large-context-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"large-context-provider.js","sourceRoot":"","sources":["../../src/core/large-context-provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAmBH;;GAEG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAOlC;IACH,gMAAkE;IAClE,6BAA6B;IAC7B,gMAAkE;IAClE,gBAAgB,EAAE;QACjB,aAAa,EAAE,OAAO;QACtB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,kBAAkB,EAAE;QACnB,aAAa,EAAE,OAAO;QACtB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,kBAAkB,EAAE;QACnB,aAAa,EAAE,OAAO;QACtB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,gBAAgB,EAAE;QACjB,aAAa,EAAE,OAAO;QACtB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IAED,gMAAkE;IAClE,kCAAkC;IAClC,gMAAkE;IAClE,wBAAwB,EAAE;QACzB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,0BAA0B,EAAE;QAC3B,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,yBAAyB,EAAE;QAC1B,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,4BAA4B,EAAE;QAC7B,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,2BAA2B,EAAE;QAC5B,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,0BAA0B,EAAE;QAC3B,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IAED,gMAAkE;IAClE,wBAAwB;IACxB,gMAAkE;IAClE,aAAa,EAAE;QACd,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,qBAAqB,EAAE;QACtB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,QAAQ,EAAE;QACT,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,aAAa,EAAE;QACd,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,oBAAoB,EAAE;QACrB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IAED,gMAAkE;IAClE,yBAAyB;IACzB,gMAAkE;IAClE,eAAe,EAAE;QAChB,aAAa,EAAE,KAAK;QACpB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,gBAAgB,EAAE;QACjB,aAAa,EAAE,KAAK;QACpB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,mBAAmB,EAAE;QACpB,aAAa,EAAE,KAAK;QACpB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IAED,gMAAkE;IAClE,kCAAkC;IAClC,gMAAkE;IAClE,uBAAuB,EAAE;QACxB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,uBAAuB,EAAE;QACxB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,UAAU,EAAE;QACX,aAAa,EAAE,OAAO;QACtB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,sBAAsB,EAAE;QACvB,aAAa,EAAE,OAAO;QACtB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IAED,gMAAkE;IAClE,qCAAqC;IACrC,gMAAkE;IAClE,gBAAgB,EAAE;QACjB,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,iBAAiB,EAAE;QAClB,aAAa,EAAE,KAAK;QACpB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,kBAAkB,EAAE;QACnB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IAED,gMAAkE;IAClE,gCAAgC;IAChC,gMAAkE;IAClE,yBAAyB,EAAE;QAC1B,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,wBAAwB,EAAE;QACzB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,uBAAuB,EAAE;QACxB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IAED,gMAAkE;IAClE,+BAA+B;IAC/B,gMAAkE;IAClE,oBAAoB,EAAE;QACrB,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,oBAAoB,EAAE;QACrB,aAAa,EAAE,KAAK;QACpB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IAED,gMAAkE;IAClE,+BAA+B;IAC/B,gMAAkE;IAClE,cAAc,EAAE;QACf,aAAa,EAAE,KAAK;QACpB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,UAAU,EAAE;QACX,aAAa,EAAE,KAAK;QACpB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IAED,gMAAkE;IAClE,2BAA2B;IAC3B,gMAAkE;IAClE,OAAO,EAAE;QACR,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IACD,YAAY,EAAE;QACb,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACxF;IAED,gMAAkE;IAClE,uBAAuB;IACvB,gMAAkE;IAClE,yBAAyB,EAAE;QAC1B,aAAa,EAAE,MAAM;QACrB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE;KACzF;IACD,uBAAuB,EAAE;QACxB,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE;KAC1F;CACD,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,oBAAoB;IACvB,IAAI,GAAG,eAAe,CAAC;IACvB,OAAO,GAAG,OAAO,CAAC;IAEnB,YAAY,GACnB,IAAI,GAAG,EAAE,CAAC;IAEX;;OAEG;IACH,aAAa,CAAC,OAAe,EAAW;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAClD,OAAO,UAAU,IAAI,yBAAyB,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAAA,CACpF;IAED;;OAEG;IACH,gBAAgB,CAAC,OAAe,EAAU;QACzC,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC;IAAA,CACpD;IAED;;OAEG;IACH,YAAY,CAAC,OAAe,EAAU;QACrC,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC;IAAA,CAChD;IAED;;OAEG;IACH,gBAAgB,CAAC,OAAe,EAAuB;QACtD,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAElD,4BAA4B;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACjD,IAAI,MAAM,EAAE,CAAC;YACZ,OAAO;gBACN,aAAa,EAAE,MAAM,CAAC,aAAa;gBACnC,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,iBAAiB,EAAE,MAAM,CAAC,YAAY,CAAC,iBAAiB;gBACxD,cAAc,EAAE,MAAM,CAAC,YAAY,CAAC,cAAc;gBAClD,iBAAiB,EAAE,MAAM,CAAC,YAAY,CAAC,iBAAiB;aACxD,CAAC;QACH,CAAC;QAED,qBAAqB;QACrB,MAAM,UAAU,GAAG,yBAAyB,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,UAAU,EAAE,CAAC;YAChB,OAAO;gBACN,aAAa,EAAE,UAAU,CAAC,aAAa;gBACvC,SAAS,EAAE,UAAU,CAAC,SAAS;gBAC/B,iBAAiB,EAAE,UAAU,CAAC,YAAY,CAAC,iBAAiB;gBAC5D,cAAc,EAAE,UAAU,CAAC,YAAY,CAAC,cAAc;gBACtD,iBAAiB,EAAE,UAAU,CAAC,YAAY,CAAC,iBAAiB;aAC5D,CAAC;QACH,CAAC;QAED,yCAAyC;QACzC,OAAO;YACN,aAAa,EAAE,OAAO;YACtB,SAAS,EAAE,KAAK;YAChB,iBAAiB,EAAE,IAAI;YACvB,cAAc,EAAE,IAAI;YACpB,iBAAiB,EAAE,IAAI;SACvB,CAAC;IAAA,CACF;IAED;;OAEG;IACH,eAAe,CAAC,QAAmB,EAAE,OAAe,EAAqB;QACxE,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEzD,OAAO;YACN,QAAQ;YACR,UAAU,EAAE,eAAe;YAC3B,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE;gBACT,SAAS,EAAE,eAAe,GAAG,MAAM,CAAC,aAAa;aACjD;SACD,CAAC;IAAA,CACF;IAED;;OAEG;IACH,cAAc,CAAC,QAAmB,EAAE,OAAe,EAAE,UAAkB,EAAmB;QACzF,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAE9C,IAAI,UAAU,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACxC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;QACzC,CAAC;QAED,4DAA4D;QAC5D,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,EAAE,CAAC;YACpC,8CAA8C;YAC9C,OAAO;gBACN,MAAM,EAAE,UAAU;gBAClB,QAAQ;gBACR,QAAQ,EAAE;oBACT,cAAc,EAAE,UAAU;oBAC1B,aAAa,EAAE,MAAM,CAAC,aAAa;oBACnC,SAAS,EAAE,MAAM,CAAC,aAAa,GAAG,UAAU;iBAC5C;aACD,CAAC;QACH,CAAC;QAED,OAAO;YACN,MAAM,EAAE,WAAW;YACnB,QAAQ,EAAE;gBACT,cAAc,EAAE,UAAU;gBAC1B,aAAa,EAAE,MAAM,CAAC,aAAa;aACnC;SACD,CAAC;IAAA,CACF;IAED;;OAEG;IACH,mBAAmB,CAClB,OAAe,EACf,MAKC,EACM;QACP,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,EAAE;YACjC,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,YAAY,EAAE;gBACb,iBAAiB,EAAE,IAAI;gBACvB,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI;gBAC7C,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,IAAI;aACnD;SACD,CAAC,CAAC;IAAA,CACH;IAED;;OAEG;IACH,YAAY,CAAkB,KAAiB,EAAc;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAE/C,OAAO;YACN,GAAG,KAAK;YACR,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,SAAS,EAAE,MAAM,CAAC,SAAS;SAC3B,CAAC;IAAA,CACF;IAED;;OAEG;IACH,cAAc,GAAa;QAC1B,OAAO,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAAA,CAC9C;IAED;;OAEG;IACH,qBAAqB,CAAC,OAAe,EAAW;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC9C,OAAO,MAAM,CAAC,aAAa,IAAI,OAAO,CAAC;IAAA,CACvC;IAED;;OAEG;IACK,gBAAgB,CAAC,OAAe,EAAU;QACjD,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAAA,CACpC;CACD;AAED;;GAEG;AACH,IAAI,4BAA4B,GAAgC,IAAI,CAAC;AAErE;;GAEG;AACH,MAAM,UAAU,uBAAuB,GAAyB;IAC/D,IAAI,CAAC,4BAA4B,EAAE,CAAC;QACnC,4BAA4B,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,4BAA4B,CAAC;AAAA,CACpC","sourcesContent":["/**\n * Large Context Provider Implementation\n * Provides 1M context window support for compatible models\n * This is a third-party architecture implementation\n */\n\nimport type { Api, Model } from \"@mariozechner/pi-ai\";\nimport type {\n\tIContextProvider,\n\tIModelContextConfig,\n\tIOverflowResult,\n\tIProcessedContext,\n} from \"./context-provider-interface.js\";\n\n/**\n * Model capability flags\n */\ninterface ModelCapabilities {\n\tsupportsStreaming: boolean;\n\tsupportsVision: boolean;\n\tsupportsFunctions: boolean;\n}\n\n/**\n * Large context model definitions\n */\nexport const LARGE_CONTEXT_DEFINITIONS: Record<\n\tstring,\n\t{\n\t\tcontextWindow: number;\n\t\tmaxTokens: number;\n\t\tcapabilities: ModelCapabilities;\n\t}\n> = {\n\t// ═══════════════════════════════════════════════════════════════\n\t// Google Gemini - 1M Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"gemini-1.5-pro\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gemini-1.5-flash\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gemini-2.0-flash\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gemini-2.0-pro\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Anthropic Claude - 200K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"claude-3-opus-20240229\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-sonnet-20240229\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-haiku-20240307\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-5-sonnet-20241022\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"claude-3-5-haiku-20241022\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"claude-sonnet-4-20250514\": {\n\t\tcontextWindow: 200000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// OpenAI - 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"gpt-4-turbo\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gpt-4-turbo-preview\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"gpt-4o\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gpt-4o-mini\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"gpt-4-0125-preview\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// DeepSeek - 64K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"deepseek-chat\": {\n\t\tcontextWindow: 64000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"deepseek-coder\": {\n\t\tcontextWindow: 64000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"deepseek-reasoner\": {\n\t\tcontextWindow: 64000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Alibaba Qwen - Up to 1M Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"qwen-2.5-72b-instruct\": {\n\t\tcontextWindow: 131072,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"qwen-2.5-32b-instruct\": {\n\t\tcontextWindow: 131072,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"qwen-max\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 65536,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"qwen-max-longcontext\": {\n\t\tcontextWindow: 1000000,\n\t\tmaxTokens: 65536,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Moonshot Kimi - Up to 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"moonshot-v1-8k\": {\n\t\tcontextWindow: 8192,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"moonshot-v1-32k\": {\n\t\tcontextWindow: 32768,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"moonshot-v1-128k\": {\n\t\tcontextWindow: 131072,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Meta Llama 3.1 - 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"llama-3.1-405b-instruct\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"llama-3.1-70b-instruct\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"llama-3.1-8b-instruct\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 16384,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Mistral - Up to 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"mistral-large-2407\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"mistral-large-2402\": {\n\t\tcontextWindow: 32000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// 01.AI Yi - Up to 32K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"yi-lightning\": {\n\t\tcontextWindow: 16384,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"yi-large\": {\n\t\tcontextWindow: 32768,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Zhipu GLM - 128K Context\n\t// ═══════════════════════════════════════════════════════════════\n\t\"glm-4\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\t\"glm-4-plus\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 4096,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: true, supportsFunctions: true },\n\t},\n\n\t// ═══════════════════════════════════════════════════════════════\n\t// Groq Models - Varies\n\t// ═══════════════════════════════════════════════════════════════\n\t\"llama-3.3-70b-versatile\": {\n\t\tcontextWindow: 128000,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: true },\n\t},\n\t\"llama-3.3-70b-specdec\": {\n\t\tcontextWindow: 8192,\n\t\tmaxTokens: 8192,\n\t\tcapabilities: { supportsStreaming: true, supportsVision: false, supportsFunctions: false },\n\t},\n};\n\n/**\n * Large Context Provider\n * Implements the IContextProvider interface for 1M context support\n */\nexport class LargeContextProvider implements IContextProvider {\n\treadonly name = \"large-context\";\n\treadonly version = \"1.0.0\";\n\n\tprivate customModels: Map<string, { contextWindow: number; maxTokens: number; capabilities: ModelCapabilities }> =\n\t\tnew Map();\n\n\t/**\n\t * Check if this provider supports a given model\n\t */\n\tsupportsModel(modelId: string): boolean {\n\t\tconst normalized = this.normalizeModelId(modelId);\n\t\treturn normalized in LARGE_CONTEXT_DEFINITIONS || this.customModels.has(normalized);\n\t}\n\n\t/**\n\t * Get context window for a model\n\t */\n\tgetContextWindow(modelId: string): number {\n\t\treturn this.getContextConfig(modelId).contextWindow;\n\t}\n\n\t/**\n\t * Get max output tokens for a model\n\t */\n\tgetMaxTokens(modelId: string): number {\n\t\treturn this.getContextConfig(modelId).maxTokens;\n\t}\n\n\t/**\n\t * Get full context configuration for a model\n\t */\n\tgetContextConfig(modelId: string): IModelContextConfig {\n\t\tconst normalized = this.normalizeModelId(modelId);\n\n\t\t// Check custom models first\n\t\tconst custom = this.customModels.get(normalized);\n\t\tif (custom) {\n\t\t\treturn {\n\t\t\t\tcontextWindow: custom.contextWindow,\n\t\t\t\tmaxTokens: custom.maxTokens,\n\t\t\t\tsupportsStreaming: custom.capabilities.supportsStreaming,\n\t\t\t\tsupportsVision: custom.capabilities.supportsVision,\n\t\t\t\tsupportsFunctions: custom.capabilities.supportsFunctions,\n\t\t\t};\n\t\t}\n\n\t\t// Check known models\n\t\tconst definition = LARGE_CONTEXT_DEFINITIONS[normalized];\n\t\tif (definition) {\n\t\t\treturn {\n\t\t\t\tcontextWindow: definition.contextWindow,\n\t\t\t\tmaxTokens: definition.maxTokens,\n\t\t\t\tsupportsStreaming: definition.capabilities.supportsStreaming,\n\t\t\t\tsupportsVision: definition.capabilities.supportsVision,\n\t\t\t\tsupportsFunctions: definition.capabilities.supportsFunctions,\n\t\t\t};\n\t\t}\n\n\t\t// Default: 1M context for unknown models\n\t\treturn {\n\t\t\tcontextWindow: 1000000,\n\t\t\tmaxTokens: 65536,\n\t\t\tsupportsStreaming: true,\n\t\t\tsupportsVision: true,\n\t\t\tsupportsFunctions: true,\n\t\t};\n\t}\n\n\t/**\n\t * Process messages before sending to API\n\t */\n\tprocessMessages(messages: unknown[], modelId: string): IProcessedContext {\n\t\tconst config = this.getContextConfig(modelId);\n\t\tconst messageStr = JSON.stringify(messages);\n\t\tconst estimatedTokens = Math.ceil(messageStr.length / 4);\n\n\t\treturn {\n\t\t\tmessages,\n\t\t\ttokenCount: estimatedTokens,\n\t\t\tmodified: false,\n\t\t\tmetadata: {\n\t\t\t\ttruncated: estimatedTokens > config.contextWindow,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Handle context overflow\n\t */\n\thandleOverflow(messages: unknown[], modelId: string, tokenCount: number): IOverflowResult {\n\t\tconst config = this.getContextConfig(modelId);\n\n\t\tif (tokenCount <= config.contextWindow) {\n\t\t\treturn { action: \"truncate\", messages };\n\t\t}\n\n\t\t// For large context models, try to keep as much as possible\n\t\tif (config.contextWindow >= 100000) {\n\t\t\t// For 1M context, we likely have enough space\n\t\t\treturn {\n\t\t\t\taction: \"truncate\",\n\t\t\t\tmessages,\n\t\t\t\tmetadata: {\n\t\t\t\t\toriginalTokens: tokenCount,\n\t\t\t\t\tcontextWindow: config.contextWindow,\n\t\t\t\t\tkeepRatio: config.contextWindow / tokenCount,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\taction: \"summarize\",\n\t\t\tmetadata: {\n\t\t\t\toriginalTokens: tokenCount,\n\t\t\t\tcontextWindow: config.contextWindow,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Register a custom model with context configuration\n\t */\n\tregisterCustomModel(\n\t\tmodelId: string,\n\t\tconfig: {\n\t\t\tcontextWindow: number;\n\t\t\tmaxTokens: number;\n\t\t\tsupportsVision?: boolean;\n\t\t\tsupportsFunctions?: boolean;\n\t\t},\n\t): void {\n\t\tconst normalized = this.normalizeModelId(modelId);\n\t\tthis.customModels.set(normalized, {\n\t\t\tcontextWindow: config.contextWindow,\n\t\t\tmaxTokens: config.maxTokens,\n\t\t\tcapabilities: {\n\t\t\t\tsupportsStreaming: true,\n\t\t\t\tsupportsVision: config.supportsVision ?? true,\n\t\t\t\tsupportsFunctions: config.supportsFunctions ?? true,\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Enhance a model with large context configuration\n\t */\n\tenhanceModel<API extends Api>(model: Model<API>): Model<API> {\n\t\tconst config = this.getContextConfig(model.id);\n\n\t\treturn {\n\t\t\t...model,\n\t\t\tcontextWindow: config.contextWindow,\n\t\t\tmaxTokens: config.maxTokens,\n\t\t};\n\t}\n\n\t/**\n\t * Get all known large context models\n\t */\n\tgetKnownModels(): string[] {\n\t\treturn Object.keys(LARGE_CONTEXT_DEFINITIONS);\n\t}\n\n\t/**\n\t * Check if a model has 1M context\n\t */\n\tisMillionContextModel(modelId: string): boolean {\n\t\tconst config = this.getContextConfig(modelId);\n\t\treturn config.contextWindow >= 1000000;\n\t}\n\n\t/**\n\t * Normalize model ID for matching\n\t */\n\tprivate normalizeModelId(modelId: string): string {\n\t\treturn modelId.toLowerCase().trim();\n\t}\n}\n\n/**\n * Singleton instance\n */\nlet largeContextProviderInstance: LargeContextProvider | null = null;\n\n/**\n * Get the singleton instance\n */\nexport function getLargeContextProvider(): LargeContextProvider {\n\tif (!largeContextProviderInstance) {\n\t\tlargeContextProviderInstance = new LargeContextProvider();\n\t}\n\treturn largeContextProviderInstance;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA6C3D,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AACD,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,OAAO,CAAC;CAChC;AACD,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,kBAAkB,EAAE,CAAC;CAClC;AA6BD,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CACf;AACD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAGrF;AAwGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAqB7D;AASD,MAAM,WAAW,iBAAiB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAyF5E","sourcesContent":["import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"fs\";\nimport ignore from \"ignore\";\nimport { homedir } from \"os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport { parseFrontmatter } from \"../utils/frontmatter.js\";\nimport type { ResourceDiagnostic } from \"./diagnostics.js\";\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\nconst IGNORE_FILE_NAMES = [\".gitignore\", \".ignore\", \".fdignore\"];\ntype IgnoreMatcher = ReturnType<typeof ignore>;\nfunction toPosixPath(p: string): string {\n\treturn p.split(sep).join(\"/\");\n}\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n\tconst trimmed = line.trim();\n\tif (!trimmed) return null;\n\tif (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\")) return null;\n\tlet pattern = line;\n\tlet negated = false;\n\tif (pattern.startsWith(\"!\")) {\n\t\tnegated = true;\n\t\tpattern = pattern.slice(1);\n\t} else if (pattern.startsWith(\"\\\\!\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tif (pattern.startsWith(\"/\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tconst prefixed = prefix ? `${prefix}${pattern}` : pattern;\n\treturn negated ? `!${prefixed}` : prefixed;\n}\nfunction addIgnoreRules(ig: IgnoreMatcher, dir: string, rootDir: string): void {\n\tconst relativeDir = relative(rootDir, dir);\n\tconst prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : \"\";\n\tfor (const filename of IGNORE_FILE_NAMES) {\n\t\tconst ignorePath = join(dir, filename);\n\t\tif (!existsSync(ignorePath)) continue;\n\t\ttry {\n\t\t\tconst content = readFileSync(ignorePath, \"utf-8\");\n\t\t\tconst patterns = content\n\t\t\t\t.split(/\\r?\\n/)\n\t\t\t\t.map((line) => prefixIgnorePattern(line, prefix))\n\t\t\t\t.filter((line): line is string => Boolean(line));\n\t\t\tif (patterns.length > 0) {\n\t\t\t\tig.add(patterns);\n\t\t\t}\n\t\t} catch {}\n\t}\n}\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\nexport interface Skill {\n\tname: string;\n\tdescription: string;\n\tfilePath: string;\n\tbaseDir: string;\n\tsource: string;\n\tdisableModelInvocation: boolean;\n}\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: ResourceDiagnostic[];\n}\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\nexport interface LoadSkillsFromDirOptions {\n\tdir: string;\n\tsource: string;\n}\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, true);\n}\nfunction loadSkillsFromDirInternal(\n\tdir: string,\n\tsource: string,\n\tincludeRootFiles: boolean,\n\tignoreMatcher?: IgnoreMatcher,\n\trootDir?: string,\n): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\tconst root = rootDir ?? dir;\n\tconst ig = ignoreMatcher ?? ignore();\n\taddIgnoreRules(ig, dir, root);\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst relPath = toPosixPath(relative(root, fullPath));\n\t\t\tconst ignorePath = isDirectory ? `${relPath}/` : relPath;\n\t\t\tif (ig.ignores(ignorePath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, false, ig, root);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isFile) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\treturn { skills, diagnostics };\n}\nfunction loadSkillFromFile(\n\tfilePath: string,\n\tsource: string,\n): { skill: Skill | null; diagnostics: ResourceDiagnostic[] } {\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tconst name = frontmatter.name || parentDirName;\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tbaseDir: skillDir,\n\t\t\t\tsource,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tconst visibleSkills = skills.filter((s) => !s.disableModelInvocation);\n\tif (visibleSkills.length === 0) {\n\t\treturn \"\";\n\t}\n\tconst lines = [\n\t\t\"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n\t\t\"Use the read tool to load a skill's file when the task matches its description.\",\n\t\t\"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n\t\t\"\",\n\t\t\"<available_skills>\",\n\t];\n\tfor (const skill of visibleSkills) {\n\t\tlines.push(\" <skill>\");\n\t\tlines.push(` <name>${escapeXml(skill.name)}</name>`);\n\t\tlines.push(` <description>${escapeXml(skill.description)}</description>`);\n\t\tlines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n\t\tlines.push(\" </skill>\");\n\t}\n\tlines.push(\"</available_skills>\");\n\treturn lines.join(\"\\n\");\n}\nfunction escapeXml(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&apos;\");\n}\nexport interface LoadSkillsOptions {\n\tcwd?: string;\n\tagentDir?: string;\n\tskillPaths?: string[];\n\tincludeDefaults?: boolean;\n}\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: ResourceDiagnostic[] = [];\n\tconst collisionDiagnostics: ResourceDiagnostic[] = [];\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\t\t\tif (realPathSet.has(realPath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"skill\",\n\t\t\t\t\t\tname: skill.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: skill.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\tif (includeDefaults) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", true));\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", true));\n\t}\n\tconst userSkillsDir = join(resolvedAgentDir, \"skills\");\n\tconst projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, \"skills\");\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\tconst getSource = (resolvedPath: string): \"user\" | \"project\" | \"path\" => {\n\t\tif (!includeDefaults) {\n\t\t\tif (isUnderPath(resolvedPath, userSkillsDir)) return \"user\";\n\t\t\tif (isUnderPath(resolvedPath, projectSkillsDir)) return \"project\";\n\t\t}\n\t\treturn \"path\";\n\t};\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tconst source = getSource(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, source, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n"]}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAwE3D,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AACD,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,OAAO,CAAC;CAChC;AACD,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,kBAAkB,EAAE,CAAC;CAClC;AA6BD,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CACf;AACD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAGrF;AAwGD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAkC7D;AASD,MAAM,WAAW,iBAAiB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAYD,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAmG5E","sourcesContent":["import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"fs\";\nimport ignore from \"ignore\";\nimport { homedir } from \"os\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport { parseFrontmatter } from \"../utils/frontmatter.js\";\nimport type { ResourceDiagnostic } from \"./diagnostics.js\";\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\nconst IGNORE_FILE_NAMES = [\".gitignore\", \".ignore\", \".fdignore\"];\ntype IgnoreMatcher = ReturnType<typeof ignore>;\n\n/**\n * Get all global skill directories to search.\n * Returns paths in priority order (first found wins).\n */\nfunction getGlobalSkillPaths(): Array<{ path: string; source: string }> {\n\tconst home = homedir();\n\treturn [\n\t\t{ path: join(home, CONFIG_DIR_NAME, \"skills\"), source: \"user\" }, // ~/.openvibe/skills\n\t\t{ path: join(home, \".agents\", \"skills\"), source: \"agents\" }, // ~/.agents/skills (Agent Skills standard)\n\t\t{ path: join(home, \".claude\", \"skills\"), source: \"claude\" }, // ~/.claude/skills (Claude compatibility)\n\t\t{ path: join(home, \".codex\", \"skills\"), source: \"codex\" }, // ~/.codex/skills (OpenAI Codex compatibility)\n\t];\n}\n\n/**\n * Get all project-level skill directories to search.\n * Returns paths in priority order.\n */\nfunction getProjectSkillPaths(cwd: string): Array<{ path: string; source: string }> {\n\treturn [\n\t\t{ path: resolve(cwd, CONFIG_DIR_NAME, \"skills\"), source: \"project\" }, // .openvibe/skills\n\t\t{ path: resolve(cwd, \".agents\", \"skills\"), source: \"project-agents\" }, // .agents/skills\n\t\t{ path: resolve(cwd, \".claude\", \"skills\"), source: \"project-claude\" }, // .claude/skills\n\t];\n}\n\nfunction toPosixPath(p: string): string {\n\treturn p.split(sep).join(\"/\");\n}\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n\tconst trimmed = line.trim();\n\tif (!trimmed) return null;\n\tif (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\")) return null;\n\tlet pattern = line;\n\tlet negated = false;\n\tif (pattern.startsWith(\"!\")) {\n\t\tnegated = true;\n\t\tpattern = pattern.slice(1);\n\t} else if (pattern.startsWith(\"\\\\!\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tif (pattern.startsWith(\"/\")) {\n\t\tpattern = pattern.slice(1);\n\t}\n\tconst prefixed = prefix ? `${prefix}${pattern}` : pattern;\n\treturn negated ? `!${prefixed}` : prefixed;\n}\nfunction addIgnoreRules(ig: IgnoreMatcher, dir: string, rootDir: string): void {\n\tconst relativeDir = relative(rootDir, dir);\n\tconst prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : \"\";\n\tfor (const filename of IGNORE_FILE_NAMES) {\n\t\tconst ignorePath = join(dir, filename);\n\t\tif (!existsSync(ignorePath)) continue;\n\t\ttry {\n\t\t\tconst content = readFileSync(ignorePath, \"utf-8\");\n\t\t\tconst patterns = content\n\t\t\t\t.split(/\\r?\\n/)\n\t\t\t\t.map((line) => prefixIgnorePattern(line, prefix))\n\t\t\t\t.filter((line): line is string => Boolean(line));\n\t\t\tif (patterns.length > 0) {\n\t\t\t\tig.add(patterns);\n\t\t\t}\n\t\t} catch {}\n\t}\n}\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\nexport interface Skill {\n\tname: string;\n\tdescription: string;\n\tfilePath: string;\n\tbaseDir: string;\n\tsource: string;\n\tdisableModelInvocation: boolean;\n}\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: ResourceDiagnostic[];\n}\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\nexport interface LoadSkillsFromDirOptions {\n\tdir: string;\n\tsource: string;\n}\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, true);\n}\nfunction loadSkillsFromDirInternal(\n\tdir: string,\n\tsource: string,\n\tincludeRootFiles: boolean,\n\tignoreMatcher?: IgnoreMatcher,\n\trootDir?: string,\n): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\tconst root = rootDir ?? dir;\n\tconst ig = ignoreMatcher ?? ignore();\n\taddIgnoreRules(ig, dir, root);\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst fullPath = join(dir, entry.name);\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst relPath = toPosixPath(relative(root, fullPath));\n\t\t\tconst ignorePath = isDirectory ? `${relPath}/` : relPath;\n\t\t\tif (ig.ignores(ignorePath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, false, ig, root);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!isFile) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\treturn { skills, diagnostics };\n}\nfunction loadSkillFromFile(\n\tfilePath: string,\n\tsource: string,\n): { skill: Skill | null; diagnostics: ResourceDiagnostic[] } {\n\tconst diagnostics: ResourceDiagnostic[] = [];\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tconst name = frontmatter.name || parentDirName;\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tbaseDir: skillDir,\n\t\t\t\tsource,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tconst visibleSkills = skills.filter((s) => !s.disableModelInvocation);\n\tif (visibleSkills.length === 0) {\n\t\treturn \"\";\n\t}\n\tconst lines = [\n\t\t\"\\n\\n# Skills System\",\n\t\t\"\",\n\t\t\"Skills are specialized knowledge files that provide expert guidance for specific tasks.\",\n\t\t\"Each skill contains detailed instructions, best practices, and context for its domain.\",\n\t\t\"\",\n\t\t\"**How to use skills:**\",\n\t\t\"1. Review the available skills below to find one matching your current task\",\n\t\t\"2. Use the `read` tool to load the skill's full content from its location\",\n\t\t\"3. Apply the skill's guidance to your current task\",\n\t\t\"4. When a skill references relative paths, resolve them against the skill directory\",\n\t\t\"\",\n\t\t\"**Invoking a skill:**\",\n\t\t\"To load a skill, use: `read <location>` where location is the skill's file path\",\n\t\t\"\",\n\t\t\"<available_skills>\",\n\t];\n\tfor (const skill of visibleSkills) {\n\t\tlines.push(\" <skill>\");\n\t\tlines.push(` <name>${escapeXml(skill.name)}</name>`);\n\t\tlines.push(` <description>${escapeXml(skill.description)}</description>`);\n\t\tlines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n\t\tlines.push(\" </skill>\");\n\t}\n\tlines.push(\"</available_skills>\");\n\tlines.push(\"\");\n\tlines.push(\"**Smart Skill Selection:**\");\n\tlines.push(\"Before responding to any task, consider if a skill could help. Skills provide domain expertise.\");\n\treturn lines.join(\"\\n\");\n}\nfunction escapeXml(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&amp;\")\n\t\t.replace(/</g, \"&lt;\")\n\t\t.replace(/>/g, \"&gt;\")\n\t\t.replace(/\"/g, \"&quot;\")\n\t\t.replace(/'/g, \"&apos;\");\n}\nexport interface LoadSkillsOptions {\n\tcwd?: string;\n\tagentDir?: string;\n\tskillPaths?: string[];\n\tincludeDefaults?: boolean;\n}\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: ResourceDiagnostic[] = [];\n\tconst collisionDiagnostics: ResourceDiagnostic[] = [];\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\t\t\tif (realPathSet.has(realPath)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t\tcollision: {\n\t\t\t\t\t\tresourceType: \"skill\",\n\t\t\t\t\t\tname: skill.name,\n\t\t\t\t\t\twinnerPath: existing.filePath,\n\t\t\t\t\t\tloserPath: skill.filePath,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\tif (includeDefaults) {\n\t\t// Load from all global skill directories\n\t\tfor (const { path, source } of getGlobalSkillPaths()) {\n\t\t\tif (existsSync(path)) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(path, source, true));\n\t\t\t}\n\t\t}\n\t\t// Load from all project-level skill directories\n\t\tfor (const { path, source } of getProjectSkillPaths(cwd)) {\n\t\t\tif (existsSync(path)) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(path, source, true));\n\t\t\t}\n\t\t}\n\t}\n\tconst userSkillsDir = join(resolvedAgentDir, \"skills\");\n\tconst projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, \"skills\");\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) {\n\t\t\treturn true;\n\t\t}\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\tconst getSource = (resolvedPath: string): \"user\" | \"project\" | \"path\" => {\n\t\tif (!includeDefaults) {\n\t\t\tif (isUnderPath(resolvedPath, userSkillsDir)) return \"user\";\n\t\t\tif (isUnderPath(resolvedPath, projectSkillsDir)) return \"project\";\n\t\t}\n\t\treturn \"path\";\n\t};\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tconst source = getSource(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, source, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n"]}
@@ -7,6 +7,30 @@ import { parseFrontmatter } from "../utils/frontmatter.js";
7
7
  const MAX_NAME_LENGTH = 64;
8
8
  const MAX_DESCRIPTION_LENGTH = 1024;
9
9
  const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"];
10
+ /**
11
+ * Get all global skill directories to search.
12
+ * Returns paths in priority order (first found wins).
13
+ */
14
+ function getGlobalSkillPaths() {
15
+ const home = homedir();
16
+ return [
17
+ { path: join(home, CONFIG_DIR_NAME, "skills"), source: "user" }, // ~/.openvibe/skills
18
+ { path: join(home, ".agents", "skills"), source: "agents" }, // ~/.agents/skills (Agent Skills standard)
19
+ { path: join(home, ".claude", "skills"), source: "claude" }, // ~/.claude/skills (Claude compatibility)
20
+ { path: join(home, ".codex", "skills"), source: "codex" }, // ~/.codex/skills (OpenAI Codex compatibility)
21
+ ];
22
+ }
23
+ /**
24
+ * Get all project-level skill directories to search.
25
+ * Returns paths in priority order.
26
+ */
27
+ function getProjectSkillPaths(cwd) {
28
+ return [
29
+ { path: resolve(cwd, CONFIG_DIR_NAME, "skills"), source: "project" }, // .openvibe/skills
30
+ { path: resolve(cwd, ".agents", "skills"), source: "project-agents" }, // .agents/skills
31
+ { path: resolve(cwd, ".claude", "skills"), source: "project-claude" }, // .claude/skills
32
+ ];
33
+ }
10
34
  function toPosixPath(p) {
11
35
  return p.split(sep).join("/");
12
36
  }
@@ -187,9 +211,19 @@ export function formatSkillsForPrompt(skills) {
187
211
  return "";
188
212
  }
189
213
  const lines = [
190
- "\n\nThe following skills provide specialized instructions for specific tasks.",
191
- "Use the read tool to load a skill's file when the task matches its description.",
192
- "When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.",
214
+ "\n\n# Skills System",
215
+ "",
216
+ "Skills are specialized knowledge files that provide expert guidance for specific tasks.",
217
+ "Each skill contains detailed instructions, best practices, and context for its domain.",
218
+ "",
219
+ "**How to use skills:**",
220
+ "1. Review the available skills below to find one matching your current task",
221
+ "2. Use the `read` tool to load the skill's full content from its location",
222
+ "3. Apply the skill's guidance to your current task",
223
+ "4. When a skill references relative paths, resolve them against the skill directory",
224
+ "",
225
+ "**Invoking a skill:**",
226
+ "To load a skill, use: `read <location>` where location is the skill's file path",
193
227
  "",
194
228
  "<available_skills>",
195
229
  ];
@@ -201,6 +235,9 @@ export function formatSkillsForPrompt(skills) {
201
235
  lines.push(" </skill>");
202
236
  }
203
237
  lines.push("</available_skills>");
238
+ lines.push("");
239
+ lines.push("**Smart Skill Selection:**");
240
+ lines.push("Before responding to any task, consider if a skill could help. Skills provide domain expertise.");
204
241
  return lines.join("\n");
205
242
  }
206
243
  function escapeXml(str) {
@@ -266,8 +303,18 @@ export function loadSkills(options = {}) {
266
303
  }
267
304
  }
268
305
  if (includeDefaults) {
269
- addSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, "skills"), "user", true));
270
- addSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, "skills"), "project", true));
306
+ // Load from all global skill directories
307
+ for (const { path, source } of getGlobalSkillPaths()) {
308
+ if (existsSync(path)) {
309
+ addSkills(loadSkillsFromDirInternal(path, source, true));
310
+ }
311
+ }
312
+ // Load from all project-level skill directories
313
+ for (const { path, source } of getProjectSkillPaths(cwd)) {
314
+ if (existsSync(path)) {
315
+ addSkills(loadSkillsFromDirInternal(path, source, true));
316
+ }
317
+ }
271
318
  }
272
319
  const userSkillsDir = join(resolvedAgentDir, "skills");
273
320
  const projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, "skills");