specweave 1.0.71 → 1.0.73

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 (43) hide show
  1. package/CLAUDE.md +38 -31
  2. package/dist/src/cli/commands/save.d.ts.map +1 -1
  3. package/dist/src/cli/commands/save.js +29 -6
  4. package/dist/src/cli/commands/save.js.map +1 -1
  5. package/dist/src/core/auto/e2e-coverage.d.ts +413 -0
  6. package/dist/src/core/auto/e2e-coverage.d.ts.map +1 -0
  7. package/dist/src/core/auto/e2e-coverage.js +1378 -0
  8. package/dist/src/core/auto/e2e-coverage.js.map +1 -0
  9. package/dist/src/core/auto/increment-planner.js +7 -1
  10. package/dist/src/core/auto/increment-planner.js.map +1 -1
  11. package/dist/src/core/auto/index.d.ts +2 -0
  12. package/dist/src/core/auto/index.d.ts.map +1 -1
  13. package/dist/src/core/auto/index.js +10 -0
  14. package/dist/src/core/auto/index.js.map +1 -1
  15. package/dist/src/core/auto/plan-approval.d.ts +104 -0
  16. package/dist/src/core/auto/plan-approval.d.ts.map +1 -0
  17. package/dist/src/core/auto/plan-approval.js +361 -0
  18. package/dist/src/core/auto/plan-approval.js.map +1 -0
  19. package/dist/src/core/plugins/skill-trigger-extractor.d.ts +147 -0
  20. package/dist/src/core/plugins/skill-trigger-extractor.d.ts.map +1 -0
  21. package/dist/src/core/plugins/skill-trigger-extractor.js +352 -0
  22. package/dist/src/core/plugins/skill-trigger-extractor.js.map +1 -0
  23. package/dist/src/core/plugins/skill-trigger-index.d.ts +91 -0
  24. package/dist/src/core/plugins/skill-trigger-index.d.ts.map +1 -0
  25. package/dist/src/core/plugins/skill-trigger-index.js +196 -0
  26. package/dist/src/core/plugins/skill-trigger-index.js.map +1 -0
  27. package/package.json +1 -1
  28. package/plugins/specweave/commands/auto.md +197 -0
  29. package/plugins/specweave/commands/save.md +24 -1
  30. package/plugins/specweave/commands/skip-increment.md +93 -0
  31. package/plugins/specweave/hooks/lib/resolve-package.sh +126 -0
  32. package/plugins/specweave/hooks/lib/sync-spec-content.sh +47 -3
  33. package/plugins/specweave/hooks/stop-auto.sh +230 -11
  34. package/plugins/specweave/hooks/user-prompt-submit.sh +4 -2
  35. package/plugins/specweave/hooks/v2/handlers/github-sync-handler.sh +8 -0
  36. package/plugins/specweave/hooks/v2/handlers/living-docs-handler.sh +10 -3
  37. package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +18 -7
  38. package/plugins/specweave/hooks/v2/handlers/project-bridge-handler.sh +10 -3
  39. package/plugins/specweave/hooks/v2/session-end.sh +50 -2
  40. package/plugins/specweave/hooks/v2/session-start.sh +68 -4
  41. package/plugins/specweave/scripts/chunk-prompt.js +204 -0
  42. package/plugins/specweave/scripts/setup-auto.sh +66 -0
  43. package/src/templates/CLAUDE.md.template +37 -30
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Skill Trigger Extractor
3
+ *
4
+ * Extracts activation trigger keywords from SKILL.md and AGENT.md files.
5
+ * These triggers enable automatic skill activation based on user prompts.
6
+ *
7
+ * @module core/plugins/skill-trigger-extractor
8
+ * @version 1.0.0
9
+ */
10
+ import * as path from 'path';
11
+ import * as fs from '../../utils/fs-native.js';
12
+ /**
13
+ * SkillTriggerExtractor - Extract activation triggers from plugin skills
14
+ */
15
+ export class SkillTriggerExtractor {
16
+ /**
17
+ * Extract triggers from a single SKILL.md or AGENT.md content
18
+ *
19
+ * @param content - File content
20
+ * @param name - Skill/agent name
21
+ * @param plugin - Parent plugin name
22
+ * @param type - 'skill' or 'agent'
23
+ * @param filePath - Path to the file
24
+ * @returns Extracted triggers
25
+ */
26
+ extractFromContent(content, name, plugin, type, filePath) {
27
+ const description = this.extractDescription(content);
28
+ const triggers = this.extractTriggerKeywords(content, description);
29
+ return {
30
+ name,
31
+ plugin,
32
+ type,
33
+ description,
34
+ triggers,
35
+ path: filePath
36
+ };
37
+ }
38
+ /**
39
+ * Extract description from YAML frontmatter
40
+ *
41
+ * @param content - File content
42
+ * @returns Description string
43
+ */
44
+ extractDescription(content) {
45
+ const frontmatterMatch = content.match(/^---\n([\s\S]+?)\n---/);
46
+ if (frontmatterMatch) {
47
+ const descMatch = frontmatterMatch[1].match(/description:\s*(.+)/);
48
+ if (descMatch) {
49
+ return descMatch[1].trim();
50
+ }
51
+ }
52
+ return '';
53
+ }
54
+ /**
55
+ * Extract trigger keywords from content and description
56
+ *
57
+ * Looks for:
58
+ * 1. "Activates for:" sections in description
59
+ * 2. Keywords in YAML frontmatter
60
+ * 3. Technology names and patterns in the description
61
+ *
62
+ * @param content - Full file content
63
+ * @param description - Extracted description
64
+ * @returns Array of normalized trigger keywords
65
+ */
66
+ extractTriggerKeywords(content, description) {
67
+ const triggers = new Set();
68
+ // 1. Extract from "Activates for:" pattern in description
69
+ const activatesForMatch = description.match(/Activates\s+for[:\s]+(.+?)(?:\.|$)/i);
70
+ if (activatesForMatch) {
71
+ const keywords = this.parseKeywordList(activatesForMatch[1]);
72
+ keywords.forEach(k => triggers.add(k));
73
+ }
74
+ // 2. Extract from "Use when" or "Use this skill when" patterns
75
+ const useWhenMatch = description.match(/Use\s+(?:this\s+skill\s+)?when[:\s]+(.+?)(?:\.|$)/i);
76
+ if (useWhenMatch) {
77
+ const keywords = this.extractTechnologyTerms(useWhenMatch[1]);
78
+ keywords.forEach(k => triggers.add(k));
79
+ }
80
+ // 3. Extract keywords from YAML frontmatter
81
+ const frontmatterMatch = content.match(/^---\n([\s\S]+?)\n---/);
82
+ if (frontmatterMatch) {
83
+ const keywordsMatch = frontmatterMatch[1].match(/keywords:\s*\[([^\]]+)\]/);
84
+ if (keywordsMatch) {
85
+ const keywords = this.parseKeywordList(keywordsMatch[1]);
86
+ keywords.forEach(k => triggers.add(k));
87
+ }
88
+ }
89
+ // 4. Extract technology terms from description
90
+ const techTerms = this.extractTechnologyTerms(description);
91
+ techTerms.forEach(t => triggers.add(t));
92
+ // 5. Look for "When to Use" sections in content
93
+ const whenToUseMatch = content.match(/##\s*When to Use[^\n]*\n([\s\S]+?)(?:\n##|$)/i);
94
+ if (whenToUseMatch) {
95
+ const techTerms = this.extractTechnologyTerms(whenToUseMatch[1]);
96
+ // Only add strong technology terms from this section
97
+ techTerms.filter(t => this.isStrongTechnologyTerm(t)).forEach(t => triggers.add(t));
98
+ }
99
+ return Array.from(triggers).filter(t => t.length >= 2);
100
+ }
101
+ /**
102
+ * Parse a keyword list from comma/or separated string
103
+ *
104
+ * @param text - Keyword list text
105
+ * @returns Array of normalized keywords
106
+ */
107
+ parseKeywordList(text) {
108
+ const keywords = [];
109
+ // Split by comma, "or", slash, pipe
110
+ const parts = text.split(/[,|\/]|\s+or\s+/gi);
111
+ for (const part of parts) {
112
+ const cleaned = part.trim()
113
+ .replace(/^["']|["']$/g, '') // Remove quotes
114
+ .replace(/\s+/g, ' ') // Normalize whitespace
115
+ .toLowerCase();
116
+ if (cleaned.length >= 2 && !this.isStopWord(cleaned)) {
117
+ keywords.push(cleaned);
118
+ }
119
+ }
120
+ return keywords;
121
+ }
122
+ /**
123
+ * Extract technology terms from text
124
+ *
125
+ * @param text - Text to extract from
126
+ * @returns Array of technology terms
127
+ */
128
+ extractTechnologyTerms(text) {
129
+ const terms = new Set();
130
+ // Known technology patterns (case-insensitive)
131
+ const techPatterns = [
132
+ // Cloud Providers
133
+ /\bAWS\b/gi, /\bAzure\b/gi, /\bGCP\b/gi, /\bGoogle Cloud\b/gi,
134
+ // Kubernetes
135
+ /\bKubernetes\b/gi, /\bK8s\b/gi, /\bEKS\b/gi, /\bAKS\b/gi, /\bGKE\b/gi,
136
+ /\bHelm\b/gi, /\bGitOps\b/gi, /\bArgoCD\b/gi, /\bFlux\b/gi, /\bIstio\b/gi,
137
+ // Mobile
138
+ /\bReact Native\b/gi, /\bExpo\b/gi, /\biOS\b/gi, /\bAndroid\b/gi,
139
+ /\bSwift\b/gi, /\bKotlin\b/gi, /\bFlutter\b/gi,
140
+ // Frontend
141
+ /\bReact\b/gi, /\bVue\.?js\b/gi, /\bAngular\b/gi, /\bNext\.?js\b/gi,
142
+ /\bNuxt\b/gi, /\bSvelte\b/gi, /\bTailwind\b/gi, /\bCSS\b/gi,
143
+ // Backend
144
+ /\bNode\.?js\b/gi, /\bExpress\b/gi, /\bNestJS\b/gi, /\bFastify\b/gi,
145
+ /\bDjango\b/gi, /\bFlask\b/gi, /\bFastAPI\b/gi,
146
+ /\bSpring Boot\b/gi, /\b\.NET\b/gi, /\bASP\.NET\b/gi,
147
+ /\bRuby on Rails\b/gi, /\bRails\b/gi, /\bLaravel\b/gi,
148
+ /\bGo\b/gi, /\bGolang\b/gi, /\bRust\b/gi,
149
+ // Databases
150
+ /\bPostgreSQL\b/gi, /\bPostgres\b/gi, /\bMySQL\b/gi, /\bMongoDB\b/gi,
151
+ /\bRedis\b/gi, /\bElasticsearch\b/gi, /\bCassandra\b/gi,
152
+ /\bPrisma\b/gi, /\bTypeORM\b/gi, /\bSequelize\b/gi, /\bMongoose\b/gi,
153
+ // Messaging
154
+ /\bKafka\b/gi, /\bRabbitMQ\b/gi, /\bSQS\b/gi, /\bPubSub\b/gi,
155
+ // DevOps/Infra
156
+ /\bTerraform\b/gi, /\bDocker\b/gi, /\bCI\/CD\b/gi,
157
+ /\bGitHub Actions\b/gi, /\bJenkins\b/gi, /\bGitLab CI\b/gi,
158
+ /\bPrometheus\b/gi, /\bGrafana\b/gi, /\bDatadog\b/gi,
159
+ // Testing
160
+ /\bPlaywright\b/gi, /\bCypress\b/gi, /\bJest\b/gi, /\bVitest\b/gi,
161
+ /\bSelenium\b/gi, /\bE2E\b/gi, /\bTDD\b/gi, /\bBDD\b/gi,
162
+ // Security
163
+ /\bOWASP\b/gi, /\bJWT\b/gi, /\bOAuth\b/gi, /\bSSL\b/gi, /\bTLS\b/gi,
164
+ /\bCORS\b/gi, /\bCSRF\b/gi, /\bXSS\b/gi,
165
+ // ML/AI
166
+ /\bTensorFlow\b/gi, /\bPyTorch\b/gi, /\bMLflow\b/gi,
167
+ /\bScikit-learn\b/gi, /\bPandas\b/gi, /\bNumPy\b/gi,
168
+ // API
169
+ /\bREST API\b/gi, /\bGraphQL\b/gi, /\btRPC\b/gi, /\bgRPC\b/gi,
170
+ /\bOpenAPI\b/gi, /\bSwagger\b/gi,
171
+ // Payments
172
+ /\bStripe\b/gi, /\bPayPal\b/gi, /\bPCI\b/gi,
173
+ // General
174
+ /\bTypeScript\b/gi, /\bJavaScript\b/gi, /\bPython\b/gi, /\bJava\b/gi,
175
+ /\bC#\b/gi, /\bRuby\b/gi, /\bPHP\b/gi
176
+ ];
177
+ for (const pattern of techPatterns) {
178
+ const matches = text.match(pattern);
179
+ if (matches) {
180
+ matches.forEach(m => terms.add(m.toLowerCase().trim()));
181
+ }
182
+ }
183
+ return Array.from(terms);
184
+ }
185
+ /**
186
+ * Check if a term is a strong technology term (not generic)
187
+ *
188
+ * @param term - Term to check
189
+ * @returns True if strong technology term
190
+ */
191
+ isStrongTechnologyTerm(term) {
192
+ const strongTerms = new Set([
193
+ 'kubernetes', 'k8s', 'eks', 'aks', 'gke', 'helm', 'gitops', 'argocd',
194
+ 'react native', 'expo', 'ios', 'android', 'flutter',
195
+ 'react', 'vue', 'angular', 'next.js', 'nextjs', 'nuxt', 'svelte',
196
+ 'node.js', 'nodejs', 'express', 'nestjs', 'fastify',
197
+ 'django', 'flask', 'fastapi', 'spring boot', '.net', 'asp.net',
198
+ 'postgresql', 'postgres', 'mysql', 'mongodb', 'redis',
199
+ 'prisma', 'typeorm', 'sequelize', 'mongoose',
200
+ 'kafka', 'rabbitmq', 'terraform', 'docker',
201
+ 'playwright', 'cypress', 'jest', 'vitest',
202
+ 'stripe', 'paypal', 'owasp', 'jwt', 'oauth',
203
+ 'tensorflow', 'pytorch', 'mlflow',
204
+ 'graphql', 'trpc', 'grpc', 'openapi'
205
+ ]);
206
+ return strongTerms.has(term.toLowerCase());
207
+ }
208
+ /**
209
+ * Check if word is a stop word (common words to ignore)
210
+ *
211
+ * @param word - Word to check
212
+ * @returns True if stop word
213
+ */
214
+ isStopWord(word) {
215
+ const stopWords = new Set([
216
+ 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
217
+ 'of', 'with', 'by', 'from', 'as', 'is', 'was', 'are', 'were', 'been',
218
+ 'be', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
219
+ 'could', 'should', 'may', 'might', 'must', 'shall', 'can', 'need',
220
+ 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it',
221
+ 'we', 'they', 'what', 'which', 'who', 'when', 'where', 'why', 'how',
222
+ 'all', 'each', 'every', 'both', 'few', 'more', 'most', 'other',
223
+ 'some', 'such', 'only', 'own', 'same', 'so', 'than', 'too', 'very',
224
+ 'just', 'use', 'using', 'used', 'create', 'creating', 'created',
225
+ 'build', 'building', 'built', 'implement', 'implementing',
226
+ 'help', 'helps', 'helping', 'want', 'wants', 'wanted', 'need', 'needs'
227
+ ]);
228
+ return stopWords.has(word.toLowerCase());
229
+ }
230
+ /**
231
+ * Scan all plugins and extract triggers
232
+ *
233
+ * @param pluginsDir - Path to plugins directory
234
+ * @returns Array of extracted triggers
235
+ */
236
+ async scanAllPlugins(pluginsDir) {
237
+ const allTriggers = [];
238
+ // Get all plugin directories
239
+ if (!(await fs.pathExists(pluginsDir))) {
240
+ return allTriggers;
241
+ }
242
+ const entries = await fs.readdir(pluginsDir, { withFileTypes: true });
243
+ for (const entry of entries) {
244
+ if (!entry.isDirectory())
245
+ continue;
246
+ const pluginPath = path.join(pluginsDir, entry.name);
247
+ const pluginName = entry.name;
248
+ // Scan skills
249
+ const skillsDir = path.join(pluginPath, 'skills');
250
+ if (await fs.pathExists(skillsDir)) {
251
+ const skillEntries = await fs.readdir(skillsDir, { withFileTypes: true });
252
+ for (const skillEntry of skillEntries) {
253
+ if (!skillEntry.isDirectory())
254
+ continue;
255
+ const skillPath = path.join(skillsDir, skillEntry.name, 'SKILL.md');
256
+ if (await fs.pathExists(skillPath)) {
257
+ const content = await fs.readFile(skillPath, 'utf-8');
258
+ const triggers = this.extractFromContent(content, skillEntry.name, pluginName, 'skill', skillPath);
259
+ allTriggers.push(triggers);
260
+ }
261
+ }
262
+ }
263
+ // Scan agents
264
+ const agentsDir = path.join(pluginPath, 'agents');
265
+ if (await fs.pathExists(agentsDir)) {
266
+ const agentEntries = await fs.readdir(agentsDir, { withFileTypes: true });
267
+ for (const agentEntry of agentEntries) {
268
+ if (!agentEntry.isDirectory())
269
+ continue;
270
+ const agentPath = path.join(agentsDir, agentEntry.name, 'AGENT.md');
271
+ if (await fs.pathExists(agentPath)) {
272
+ const content = await fs.readFile(agentPath, 'utf-8');
273
+ const triggers = this.extractFromContent(content, agentEntry.name, pluginName, 'agent', agentPath);
274
+ allTriggers.push(triggers);
275
+ }
276
+ }
277
+ }
278
+ }
279
+ return allTriggers;
280
+ }
281
+ /**
282
+ * Build the skill triggers index from extracted triggers
283
+ *
284
+ * @param triggers - Array of extracted triggers
285
+ * @returns Skill triggers index
286
+ */
287
+ buildIndex(triggers) {
288
+ const keywords = {};
289
+ const skills = {};
290
+ for (const trigger of triggers) {
291
+ // Full qualified name: plugin:type:name
292
+ const fqn = `${trigger.plugin}:${trigger.name}`;
293
+ // Add to skills metadata
294
+ skills[fqn] = {
295
+ plugin: trigger.plugin,
296
+ type: trigger.type,
297
+ triggers: trigger.triggers,
298
+ description: trigger.description.substring(0, 150),
299
+ fqn
300
+ };
301
+ // Build inverted index
302
+ for (const keyword of trigger.triggers) {
303
+ if (!keywords[keyword]) {
304
+ keywords[keyword] = [];
305
+ }
306
+ if (!keywords[keyword].includes(fqn)) {
307
+ keywords[keyword].push(fqn);
308
+ }
309
+ }
310
+ }
311
+ return {
312
+ keywords,
313
+ skills,
314
+ generatedAt: new Date().toISOString(),
315
+ skillCount: Object.keys(skills).length,
316
+ keywordCount: Object.keys(keywords).length
317
+ };
318
+ }
319
+ /**
320
+ * Match a user prompt against the trigger index
321
+ *
322
+ * @param prompt - User prompt
323
+ * @param index - Skill triggers index
324
+ * @returns Array of matched skill FQNs sorted by relevance
325
+ */
326
+ matchPrompt(prompt, index) {
327
+ const matches = new Map();
328
+ // Normalize prompt
329
+ const normalizedPrompt = prompt.toLowerCase();
330
+ // Check each keyword
331
+ for (const [keyword, skillFqns] of Object.entries(index.keywords)) {
332
+ // Check if keyword appears in prompt
333
+ if (normalizedPrompt.includes(keyword)) {
334
+ for (const fqn of skillFqns) {
335
+ const existing = matches.get(fqn) || { score: 0, keywords: [] };
336
+ existing.score += keyword.length; // Longer keywords = higher score
337
+ existing.keywords.push(keyword);
338
+ matches.set(fqn, existing);
339
+ }
340
+ }
341
+ }
342
+ // Convert to array and sort by score
343
+ return Array.from(matches.entries())
344
+ .map(([fqn, data]) => ({
345
+ fqn,
346
+ score: data.score,
347
+ matchedKeywords: data.keywords
348
+ }))
349
+ .sort((a, b) => b.score - a.score);
350
+ }
351
+ }
352
+ //# sourceMappingURL=skill-trigger-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-trigger-extractor.js","sourceRoot":"","sources":["../../../../src/core/plugins/skill-trigger-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAoD/C;;GAEG;AACH,MAAM,OAAO,qBAAqB;IAChC;;;;;;;;;OASG;IACH,kBAAkB,CAChB,OAAe,EACf,IAAY,EACZ,MAAc,EACd,IAAuB,EACvB,QAAgB;QAEhB,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAEnE,OAAO;YACL,IAAI;YACJ,MAAM;YACN,IAAI;YACJ,WAAW;YACX,QAAQ;YACR,IAAI,EAAE,QAAQ;SACf,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACK,kBAAkB,CAAC,OAAe;QACxC,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAChE,IAAI,gBAAgB,EAAE,CAAC;YACrB,MAAM,SAAS,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACnE,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;;;;;;;;;OAWG;IACH,sBAAsB,CAAC,OAAe,EAAE,WAAmB;QACzD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;QAEnC,0DAA0D;QAC1D,MAAM,iBAAiB,GAAG,WAAW,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACnF,IAAI,iBAAiB,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7D,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;QAED,+DAA+D;QAC/D,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC7F,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YAC9D,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;QAED,4CAA4C;QAC5C,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAChE,IAAI,gBAAgB,EAAE,CAAC;YACrB,MAAM,aAAa,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC5E,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;gBACzD,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,+CAA+C;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;QAC3D,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAExC,gDAAgD;QAChD,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACtF,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,SAAS,GAAG,IAAI,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,qDAAqD;YACrD,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtF,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IACzD,CAAC;IAED;;;;;OAKG;IACK,gBAAgB,CAAC,IAAY;QACnC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,oCAAoC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAE9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE;iBACxB,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,gBAAgB;iBAC5C,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,uBAAuB;iBAC5C,WAAW,EAAE,CAAC;YAEjB,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBACrD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACK,sBAAsB,CAAC,IAAY;QACzC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAEhC,+CAA+C;QAC/C,MAAM,YAAY,GAAG;YACnB,kBAAkB;YAClB,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB;YAC7D,aAAa;YACb,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW;YACtE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa;YACzE,SAAS;YACT,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,eAAe;YAChE,aAAa,EAAE,cAAc,EAAE,eAAe;YAC9C,WAAW;YACX,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB;YACnE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW;YAC3D,UAAU;YACV,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe;YACnE,cAAc,EAAE,aAAa,EAAE,eAAe;YAC9C,mBAAmB,EAAE,aAAa,EAAE,gBAAgB;YACpD,qBAAqB,EAAE,aAAa,EAAE,eAAe;YACrD,UAAU,EAAE,cAAc,EAAE,YAAY;YACxC,YAAY;YACZ,kBAAkB,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe;YACpE,aAAa,EAAE,qBAAqB,EAAE,iBAAiB;YACvD,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB;YACpE,YAAY;YACZ,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc;YAC5D,eAAe;YACf,iBAAiB,EAAE,cAAc,EAAE,cAAc;YACjD,sBAAsB,EAAE,eAAe,EAAE,iBAAiB;YAC1D,kBAAkB,EAAE,eAAe,EAAE,eAAe;YACpD,UAAU;YACV,kBAAkB,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc;YACjE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW;YACvD,WAAW;YACX,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW;YACnE,YAAY,EAAE,YAAY,EAAE,WAAW;YACvC,QAAQ;YACR,kBAAkB,EAAE,eAAe,EAAE,cAAc;YACnD,oBAAoB,EAAE,cAAc,EAAE,aAAa;YACnD,MAAM;YACN,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY;YAC7D,eAAe,EAAE,eAAe;YAChC,WAAW;YACX,cAAc,EAAE,cAAc,EAAE,WAAW;YAC3C,UAAU;YACV,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,EAAE,YAAY;YACpE,UAAU,EAAE,YAAY,EAAE,WAAW;SACtC,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpC,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED;;;;;OAKG;IACK,sBAAsB,CAAC,IAAY;QACzC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;YAC1B,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ;YACpE,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;YACnD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ;YAChE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS;YACnD,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS;YAC9D,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO;YACrD,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU;YAC5C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ;YAC1C,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ;YACzC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO;YAC3C,YAAY,EAAE,SAAS,EAAE,QAAQ;YACjC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS;SACrC,CAAC,CAAC;QACH,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;OAKG;IACK,UAAU,CAAC,IAAY;QAC7B,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;YACxB,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK;YACnE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM;YACpE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO;YAChE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM;YACjE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI;YAC/D,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK;YACnE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;YAC9D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;YAClE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS;YAC/D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc;YACzD,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO;SACvE,CAAC,CAAC;QACH,OAAO,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,cAAc,CAAC,UAAkB;QACrC,MAAM,WAAW,GAAwB,EAAE,CAAC;QAE5C,6BAA6B;QAC7B,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;YACvC,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;gBAAE,SAAS;YAEnC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC;YAE9B,cAAc;YACd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAClD,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnC,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1E,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;oBACtC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE;wBAAE,SAAS;oBAExC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;oBACpE,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;wBACnC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;wBACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CACtC,OAAO,EACP,UAAU,CAAC,IAAI,EACf,UAAU,EACV,OAAO,EACP,SAAS,CACV,CAAC;wBACF,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;YAED,cAAc;YACd,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAClD,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnC,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1E,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;oBACtC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE;wBAAE,SAAS;oBAExC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;oBACpE,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;wBACnC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;wBACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CACtC,OAAO,EACP,UAAU,CAAC,IAAI,EACf,UAAU,EACV,OAAO,EACP,SAAS,CACV,CAAC;wBACF,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,QAA6B;QACtC,MAAM,QAAQ,GAA6B,EAAE,CAAC;QAC9C,MAAM,MAAM,GAAkC,EAAE,CAAC;QAEjD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,wCAAwC;YACxC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YAEhD,yBAAyB;YACzB,MAAM,CAAC,GAAG,CAAC,GAAG;gBACZ,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;gBAClD,GAAG;aACJ,CAAC;YAEF,uBAAuB;YACvB,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACvC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;oBACvB,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;gBACzB,CAAC;gBACD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBACrC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,QAAQ;YACR,MAAM;YACN,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM;YACtC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM;SAC3C,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,WAAW,CAAC,MAAc,EAAE,KAAyB;QACnD,MAAM,OAAO,GAAuD,IAAI,GAAG,EAAE,CAAC;QAE9E,mBAAmB;QACnB,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QAE9C,qBAAqB;QACrB,KAAK,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClE,qCAAqC;YACrC,IAAI,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;oBAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;oBAChE,QAAQ,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,iCAAiC;oBACnE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAChC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;QACH,CAAC;QAED,qCAAqC;QACrC,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;aACjC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACrB,GAAG;YACH,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,eAAe,EAAE,IAAI,CAAC,QAAQ;SAC/B,CAAC,CAAC;aACF,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;CACF"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Skill Trigger Index Manager
3
+ *
4
+ * Manages the skill triggers index file used for automatic skill activation.
5
+ *
6
+ * @module core/plugins/skill-trigger-index
7
+ * @version 1.0.0
8
+ */
9
+ import { SkillTriggersIndex } from './skill-trigger-extractor.js';
10
+ /**
11
+ * SkillTriggerIndexManager - Generate and manage skill triggers index
12
+ */
13
+ export declare class SkillTriggerIndexManager {
14
+ private extractor;
15
+ private projectRoot;
16
+ constructor(projectRoot?: string);
17
+ /**
18
+ * Generate the skill triggers index from all plugins
19
+ *
20
+ * @param pluginsDir - Path to plugins directory (relative or absolute)
21
+ * @returns Generated index
22
+ */
23
+ generateIndex(pluginsDir?: string): Promise<SkillTriggersIndex>;
24
+ /**
25
+ * Save index to file
26
+ *
27
+ * @param index - Skill triggers index
28
+ * @param indexPath - Path to save index (relative or absolute)
29
+ */
30
+ saveIndex(index: SkillTriggersIndex, indexPath?: string): Promise<string>;
31
+ /**
32
+ * Load index from file
33
+ *
34
+ * @param indexPath - Path to index file (relative or absolute)
35
+ * @returns Loaded index or null if not found
36
+ */
37
+ loadIndex(indexPath?: string): Promise<SkillTriggersIndex | null>;
38
+ /**
39
+ * Generate and save index (convenience method)
40
+ *
41
+ * @param pluginsDir - Path to plugins directory
42
+ * @param indexPath - Path to save index
43
+ * @returns Generated index and path
44
+ */
45
+ generateAndSave(pluginsDir?: string, indexPath?: string): Promise<{
46
+ index: SkillTriggersIndex;
47
+ path: string;
48
+ }>;
49
+ /**
50
+ * Match a user prompt against the index
51
+ *
52
+ * @param prompt - User prompt
53
+ * @param index - Optional pre-loaded index
54
+ * @returns Matched skills with scores
55
+ */
56
+ matchPrompt(prompt: string, index?: SkillTriggersIndex): Promise<Array<{
57
+ fqn: string;
58
+ score: number;
59
+ matchedKeywords: string[];
60
+ }>>;
61
+ /**
62
+ * Check if index needs regeneration
63
+ *
64
+ * @param maxAgeMs - Maximum age in milliseconds (default: 24 hours)
65
+ * @returns True if index needs regeneration
66
+ */
67
+ needsRegeneration(maxAgeMs?: number): Promise<boolean>;
68
+ /**
69
+ * Get index statistics
70
+ *
71
+ * @returns Index stats or null if not found
72
+ */
73
+ getStats(): Promise<{
74
+ skillCount: number;
75
+ keywordCount: number;
76
+ generatedAt: string;
77
+ topKeywords: Array<{
78
+ keyword: string;
79
+ skillCount: number;
80
+ }>;
81
+ } | null>;
82
+ }
83
+ /**
84
+ * CLI helper to generate index
85
+ */
86
+ export declare function generateSkillTriggersIndexCLI(projectRoot?: string, pluginsDir?: string, indexPath?: string, verbose?: boolean): Promise<void>;
87
+ /**
88
+ * CLI helper to test prompt matching
89
+ */
90
+ export declare function testPromptMatchingCLI(prompt: string, projectRoot?: string, verbose?: boolean): Promise<void>;
91
+ //# sourceMappingURL=skill-trigger-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-trigger-index.d.ts","sourceRoot":"","sources":["../../../../src/core/plugins/skill-trigger-index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAyB,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAYzF;;GAEG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,SAAS,CAAwB;IACzC,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,GAAE,MAAsB;IAK/C;;;;;OAKG;IACG,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAcrE;;;;;OAKG;IACG,SAAS,CAAC,KAAK,EAAE,kBAAkB,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAc/E;;;;;OAKG;IACG,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAgBvE;;;;;;OAMG;IACG,eAAe,CACnB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC;QAAE,KAAK,EAAE,kBAAkB,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAMvD;;;;;;OAMG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,kBAAkB,GACzB,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAU5E;;;;;OAKG;IACG,iBAAiB,CAAC,QAAQ,GAAE,MAA4B,GAAG,OAAO,CAAC,OAAO,CAAC;IAajF;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KAC7D,GAAG,IAAI,CAAC;CAoBV;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,GAAE,MAAsB,EACnC,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,GAAE,OAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAwBf;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,WAAW,GAAE,MAAsB,EACnC,OAAO,GAAE,OAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Skill Trigger Index Manager
3
+ *
4
+ * Manages the skill triggers index file used for automatic skill activation.
5
+ *
6
+ * @module core/plugins/skill-trigger-index
7
+ * @version 1.0.0
8
+ */
9
+ import * as path from 'path';
10
+ import * as fs from '../../utils/fs-native.js';
11
+ import { SkillTriggerExtractor } from './skill-trigger-extractor.js';
12
+ /**
13
+ * Default path for the skill triggers index
14
+ */
15
+ const DEFAULT_INDEX_PATH = '.specweave/state/skill-triggers-index.json';
16
+ /**
17
+ * Default plugins directory
18
+ */
19
+ const DEFAULT_PLUGINS_DIR = 'plugins';
20
+ /**
21
+ * SkillTriggerIndexManager - Generate and manage skill triggers index
22
+ */
23
+ export class SkillTriggerIndexManager {
24
+ constructor(projectRoot = process.cwd()) {
25
+ this.extractor = new SkillTriggerExtractor();
26
+ this.projectRoot = projectRoot;
27
+ }
28
+ /**
29
+ * Generate the skill triggers index from all plugins
30
+ *
31
+ * @param pluginsDir - Path to plugins directory (relative or absolute)
32
+ * @returns Generated index
33
+ */
34
+ async generateIndex(pluginsDir) {
35
+ const resolvedPluginsDir = pluginsDir
36
+ ? path.isAbsolute(pluginsDir) ? pluginsDir : path.join(this.projectRoot, pluginsDir)
37
+ : path.join(this.projectRoot, DEFAULT_PLUGINS_DIR);
38
+ // Scan all plugins
39
+ const triggers = await this.extractor.scanAllPlugins(resolvedPluginsDir);
40
+ // Build index
41
+ const index = this.extractor.buildIndex(triggers);
42
+ return index;
43
+ }
44
+ /**
45
+ * Save index to file
46
+ *
47
+ * @param index - Skill triggers index
48
+ * @param indexPath - Path to save index (relative or absolute)
49
+ */
50
+ async saveIndex(index, indexPath) {
51
+ const resolvedPath = indexPath
52
+ ? path.isAbsolute(indexPath) ? indexPath : path.join(this.projectRoot, indexPath)
53
+ : path.join(this.projectRoot, DEFAULT_INDEX_PATH);
54
+ // Ensure directory exists
55
+ await fs.ensureDir(path.dirname(resolvedPath));
56
+ // Write index
57
+ await fs.writeJSON(resolvedPath, index, { spaces: 2 });
58
+ return resolvedPath;
59
+ }
60
+ /**
61
+ * Load index from file
62
+ *
63
+ * @param indexPath - Path to index file (relative or absolute)
64
+ * @returns Loaded index or null if not found
65
+ */
66
+ async loadIndex(indexPath) {
67
+ const resolvedPath = indexPath
68
+ ? path.isAbsolute(indexPath) ? indexPath : path.join(this.projectRoot, indexPath)
69
+ : path.join(this.projectRoot, DEFAULT_INDEX_PATH);
70
+ if (!(await fs.pathExists(resolvedPath))) {
71
+ return null;
72
+ }
73
+ try {
74
+ return await fs.readJSON(resolvedPath);
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ /**
81
+ * Generate and save index (convenience method)
82
+ *
83
+ * @param pluginsDir - Path to plugins directory
84
+ * @param indexPath - Path to save index
85
+ * @returns Generated index and path
86
+ */
87
+ async generateAndSave(pluginsDir, indexPath) {
88
+ const index = await this.generateIndex(pluginsDir);
89
+ const savedPath = await this.saveIndex(index, indexPath);
90
+ return { index, path: savedPath };
91
+ }
92
+ /**
93
+ * Match a user prompt against the index
94
+ *
95
+ * @param prompt - User prompt
96
+ * @param index - Optional pre-loaded index
97
+ * @returns Matched skills with scores
98
+ */
99
+ async matchPrompt(prompt, index) {
100
+ const loadedIndex = index || await this.loadIndex();
101
+ if (!loadedIndex) {
102
+ return [];
103
+ }
104
+ return this.extractor.matchPrompt(prompt, loadedIndex);
105
+ }
106
+ /**
107
+ * Check if index needs regeneration
108
+ *
109
+ * @param maxAgeMs - Maximum age in milliseconds (default: 24 hours)
110
+ * @returns True if index needs regeneration
111
+ */
112
+ async needsRegeneration(maxAgeMs = 24 * 60 * 60 * 1000) {
113
+ const index = await this.loadIndex();
114
+ if (!index) {
115
+ return true;
116
+ }
117
+ const generatedAt = new Date(index.generatedAt).getTime();
118
+ const now = Date.now();
119
+ return (now - generatedAt) > maxAgeMs;
120
+ }
121
+ /**
122
+ * Get index statistics
123
+ *
124
+ * @returns Index stats or null if not found
125
+ */
126
+ async getStats() {
127
+ const index = await this.loadIndex();
128
+ if (!index) {
129
+ return null;
130
+ }
131
+ // Get top 20 keywords by skill count
132
+ const keywordCounts = Object.entries(index.keywords)
133
+ .map(([keyword, skills]) => ({ keyword, skillCount: skills.length }))
134
+ .sort((a, b) => b.skillCount - a.skillCount)
135
+ .slice(0, 20);
136
+ return {
137
+ skillCount: index.skillCount,
138
+ keywordCount: index.keywordCount,
139
+ generatedAt: index.generatedAt,
140
+ topKeywords: keywordCounts
141
+ };
142
+ }
143
+ }
144
+ /**
145
+ * CLI helper to generate index
146
+ */
147
+ export async function generateSkillTriggersIndexCLI(projectRoot = process.cwd(), pluginsDir, indexPath, verbose = false) {
148
+ const manager = new SkillTriggerIndexManager(projectRoot);
149
+ if (verbose) {
150
+ console.log('šŸ” Scanning plugins for skill triggers...');
151
+ }
152
+ const { index, path: savedPath } = await manager.generateAndSave(pluginsDir, indexPath);
153
+ if (verbose) {
154
+ console.log(`āœ… Generated skill triggers index:`);
155
+ console.log(` Skills: ${index.skillCount}`);
156
+ console.log(` Keywords: ${index.keywordCount}`);
157
+ console.log(` Path: ${savedPath}`);
158
+ // Show top keywords
159
+ const stats = await manager.getStats();
160
+ if (stats && stats.topKeywords.length > 0) {
161
+ console.log('\nšŸ“Š Top keywords:');
162
+ for (const { keyword, skillCount } of stats.topKeywords.slice(0, 10)) {
163
+ console.log(` ${keyword}: ${skillCount} skills`);
164
+ }
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * CLI helper to test prompt matching
170
+ */
171
+ export async function testPromptMatchingCLI(prompt, projectRoot = process.cwd(), verbose = false) {
172
+ const manager = new SkillTriggerIndexManager(projectRoot);
173
+ const index = await manager.loadIndex();
174
+ if (!index) {
175
+ console.error('āŒ No skill triggers index found. Run refresh-marketplace.sh first.');
176
+ process.exit(1);
177
+ }
178
+ const matches = await manager.matchPrompt(prompt, index);
179
+ if (matches.length === 0) {
180
+ console.log('āŒ No skills matched for prompt:', prompt);
181
+ return;
182
+ }
183
+ console.log(`āœ… Matched ${matches.length} skills for prompt:`);
184
+ console.log(` "${prompt}"\n`);
185
+ for (const match of matches.slice(0, 10)) {
186
+ const skill = index.skills[match.fqn];
187
+ console.log(` šŸ“¦ ${match.fqn}`);
188
+ console.log(` Score: ${match.score}`);
189
+ console.log(` Keywords: ${match.matchedKeywords.join(', ')}`);
190
+ if (verbose && skill) {
191
+ console.log(` Description: ${skill.description}`);
192
+ }
193
+ console.log();
194
+ }
195
+ }
196
+ //# sourceMappingURL=skill-trigger-index.js.map