matimo 0.1.0-alpha.8 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +10 -8
- package/packages/cli/dist/bin.d.ts +3 -0
- package/packages/cli/dist/bin.d.ts.map +1 -0
- package/packages/cli/dist/bin.js +50 -0
- package/packages/cli/dist/bin.js.map +1 -0
- package/packages/cli/dist/cli.d.ts.map +1 -1
- package/packages/cli/dist/cli.js +64 -2
- package/packages/cli/dist/cli.js.map +1 -1
- package/packages/cli/dist/commands/doctor.d.ts +2 -0
- package/packages/cli/dist/commands/doctor.d.ts.map +1 -0
- package/packages/cli/dist/commands/doctor.js +174 -0
- package/packages/cli/dist/commands/doctor.js.map +1 -0
- package/packages/cli/dist/commands/mcp-setup.d.ts +9 -0
- package/packages/cli/dist/commands/mcp-setup.d.ts.map +1 -0
- package/packages/cli/dist/commands/mcp-setup.js +106 -0
- package/packages/cli/dist/commands/mcp-setup.js.map +1 -0
- package/packages/cli/dist/commands/mcp.d.ts +17 -0
- package/packages/cli/dist/commands/mcp.d.ts.map +1 -0
- package/packages/cli/dist/commands/mcp.js +228 -0
- package/packages/cli/dist/commands/mcp.js.map +1 -0
- package/packages/cli/dist/commands/review.d.ts +10 -0
- package/packages/cli/dist/commands/review.d.ts.map +1 -0
- package/packages/cli/dist/commands/review.js +176 -0
- package/packages/cli/dist/commands/review.js.map +1 -0
- package/packages/core/dist/approval/approval-handler.d.ts +5 -1
- package/packages/core/dist/approval/approval-handler.d.ts.map +1 -1
- package/packages/core/dist/approval/approval-handler.js +6 -0
- package/packages/core/dist/approval/approval-handler.js.map +1 -1
- package/packages/core/dist/core/schema.d.ts +41 -10
- package/packages/core/dist/core/schema.d.ts.map +1 -1
- package/packages/core/dist/core/schema.js +40 -4
- package/packages/core/dist/core/schema.js.map +1 -1
- package/packages/core/dist/core/skill-content-parser.d.ts +91 -0
- package/packages/core/dist/core/skill-content-parser.d.ts.map +1 -0
- package/packages/core/dist/core/skill-content-parser.js +248 -0
- package/packages/core/dist/core/skill-content-parser.js.map +1 -0
- package/packages/core/dist/core/skill-loader.d.ts +46 -0
- package/packages/core/dist/core/skill-loader.d.ts.map +1 -0
- package/packages/core/dist/core/skill-loader.js +310 -0
- package/packages/core/dist/core/skill-loader.js.map +1 -0
- package/packages/core/dist/core/skill-registry.d.ts +131 -0
- package/packages/core/dist/core/skill-registry.d.ts.map +1 -0
- package/packages/core/dist/core/skill-registry.js +316 -0
- package/packages/core/dist/core/skill-registry.js.map +1 -0
- package/packages/core/dist/core/tfidf-embedding.d.ts +45 -0
- package/packages/core/dist/core/tfidf-embedding.d.ts.map +1 -0
- package/packages/core/dist/core/tfidf-embedding.js +199 -0
- package/packages/core/dist/core/tfidf-embedding.js.map +1 -0
- package/packages/core/dist/core/tool-loader.d.ts +3 -1
- package/packages/core/dist/core/tool-loader.d.ts.map +1 -1
- package/packages/core/dist/core/tool-loader.js +33 -10
- package/packages/core/dist/core/tool-loader.js.map +1 -1
- package/packages/core/dist/core/types.d.ts +203 -6
- package/packages/core/dist/core/types.d.ts.map +1 -1
- package/packages/core/dist/encodings/parameter-encoding.d.ts +1 -1
- package/packages/core/dist/encodings/parameter-encoding.d.ts.map +1 -1
- package/packages/core/dist/encodings/parameter-encoding.js +9 -4
- package/packages/core/dist/encodings/parameter-encoding.js.map +1 -1
- package/packages/core/dist/errors/matimo-error.d.ts +11 -2
- package/packages/core/dist/errors/matimo-error.d.ts.map +1 -1
- package/packages/core/dist/errors/matimo-error.js +25 -1
- package/packages/core/dist/errors/matimo-error.js.map +1 -1
- package/packages/core/dist/executors/command-executor.d.ts +9 -2
- package/packages/core/dist/executors/command-executor.d.ts.map +1 -1
- package/packages/core/dist/executors/command-executor.js +29 -5
- package/packages/core/dist/executors/command-executor.js.map +1 -1
- package/packages/core/dist/executors/function-executor.d.ts +10 -3
- package/packages/core/dist/executors/function-executor.d.ts.map +1 -1
- package/packages/core/dist/executors/function-executor.js +44 -24
- package/packages/core/dist/executors/function-executor.js.map +1 -1
- package/packages/core/dist/executors/http-executor.d.ts +79 -4
- package/packages/core/dist/executors/http-executor.d.ts.map +1 -1
- package/packages/core/dist/executors/http-executor.js +232 -28
- package/packages/core/dist/executors/http-executor.js.map +1 -1
- package/packages/core/dist/index.d.ts +25 -3
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +19 -1
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/integrations/langchain.d.ts +55 -0
- package/packages/core/dist/integrations/langchain.d.ts.map +1 -1
- package/packages/core/dist/integrations/langchain.js +71 -4
- package/packages/core/dist/integrations/langchain.js.map +1 -1
- package/packages/core/dist/logging/logger.d.ts +8 -2
- package/packages/core/dist/logging/logger.d.ts.map +1 -1
- package/packages/core/dist/logging/logger.js.map +1 -1
- package/packages/core/dist/logging/winston-logger.d.ts.map +1 -1
- package/packages/core/dist/logging/winston-logger.js +9 -1
- package/packages/core/dist/logging/winston-logger.js.map +1 -1
- package/packages/core/dist/matimo-instance.d.ts +230 -18
- package/packages/core/dist/matimo-instance.d.ts.map +1 -1
- package/packages/core/dist/matimo-instance.js +739 -40
- package/packages/core/dist/matimo-instance.js.map +1 -1
- package/packages/core/dist/mcp/index.d.ts +18 -0
- package/packages/core/dist/mcp/index.d.ts.map +1 -0
- package/packages/core/dist/mcp/index.js +24 -0
- package/packages/core/dist/mcp/index.js.map +1 -0
- package/packages/core/dist/mcp/mcp-server.d.ts +141 -0
- package/packages/core/dist/mcp/mcp-server.d.ts.map +1 -0
- package/packages/core/dist/mcp/mcp-server.js +754 -0
- package/packages/core/dist/mcp/mcp-server.js.map +1 -0
- package/packages/core/dist/mcp/secrets/aws-resolver.d.ts +41 -0
- package/packages/core/dist/mcp/secrets/aws-resolver.d.ts.map +1 -0
- package/packages/core/dist/mcp/secrets/aws-resolver.js +141 -0
- package/packages/core/dist/mcp/secrets/aws-resolver.js.map +1 -0
- package/packages/core/dist/mcp/secrets/dotenv-resolver.d.ts +23 -0
- package/packages/core/dist/mcp/secrets/dotenv-resolver.d.ts.map +1 -0
- package/packages/core/dist/mcp/secrets/dotenv-resolver.js +94 -0
- package/packages/core/dist/mcp/secrets/dotenv-resolver.js.map +1 -0
- package/packages/core/dist/mcp/secrets/env-resolver.d.ts +14 -0
- package/packages/core/dist/mcp/secrets/env-resolver.d.ts.map +1 -0
- package/packages/core/dist/mcp/secrets/env-resolver.js +27 -0
- package/packages/core/dist/mcp/secrets/env-resolver.js.map +1 -0
- package/packages/core/dist/mcp/secrets/index.d.ts +14 -0
- package/packages/core/dist/mcp/secrets/index.d.ts.map +1 -0
- package/packages/core/dist/mcp/secrets/index.js +13 -0
- package/packages/core/dist/mcp/secrets/index.js.map +1 -0
- package/packages/core/dist/mcp/secrets/resolver-chain.d.ts +34 -0
- package/packages/core/dist/mcp/secrets/resolver-chain.d.ts.map +1 -0
- package/packages/core/dist/mcp/secrets/resolver-chain.js +141 -0
- package/packages/core/dist/mcp/secrets/resolver-chain.js.map +1 -0
- package/packages/core/dist/mcp/secrets/types.d.ts +73 -0
- package/packages/core/dist/mcp/secrets/types.d.ts.map +1 -0
- package/packages/core/dist/mcp/secrets/types.js +8 -0
- package/packages/core/dist/mcp/secrets/types.js.map +1 -0
- package/packages/core/dist/mcp/secrets/vault-resolver.d.ts +43 -0
- package/packages/core/dist/mcp/secrets/vault-resolver.d.ts.map +1 -0
- package/packages/core/dist/mcp/secrets/vault-resolver.js +127 -0
- package/packages/core/dist/mcp/secrets/vault-resolver.js.map +1 -0
- package/packages/core/dist/mcp/tool-converter.d.ts +40 -0
- package/packages/core/dist/mcp/tool-converter.d.ts.map +1 -0
- package/packages/core/dist/mcp/tool-converter.js +185 -0
- package/packages/core/dist/mcp/tool-converter.js.map +1 -0
- package/packages/core/dist/policy/approval-manifest.d.ts +76 -0
- package/packages/core/dist/policy/approval-manifest.d.ts.map +1 -0
- package/packages/core/dist/policy/approval-manifest.js +197 -0
- package/packages/core/dist/policy/approval-manifest.js.map +1 -0
- package/packages/core/dist/policy/content-validator.d.ts +19 -0
- package/packages/core/dist/policy/content-validator.d.ts.map +1 -0
- package/packages/core/dist/policy/content-validator.js +196 -0
- package/packages/core/dist/policy/content-validator.js.map +1 -0
- package/packages/core/dist/policy/default-policy.d.ts +46 -0
- package/packages/core/dist/policy/default-policy.d.ts.map +1 -0
- package/packages/core/dist/policy/default-policy.js +241 -0
- package/packages/core/dist/policy/default-policy.js.map +1 -0
- package/packages/core/dist/policy/events.d.ts +71 -0
- package/packages/core/dist/policy/events.d.ts.map +1 -0
- package/packages/core/dist/policy/events.js +8 -0
- package/packages/core/dist/policy/events.js.map +1 -0
- package/packages/core/dist/policy/index.d.ts +13 -0
- package/packages/core/dist/policy/index.d.ts.map +1 -0
- package/packages/core/dist/policy/index.js +9 -0
- package/packages/core/dist/policy/index.js.map +1 -0
- package/packages/core/dist/policy/integrity-tracker.d.ts +62 -0
- package/packages/core/dist/policy/integrity-tracker.d.ts.map +1 -0
- package/packages/core/dist/policy/integrity-tracker.js +79 -0
- package/packages/core/dist/policy/integrity-tracker.js.map +1 -0
- package/packages/core/dist/policy/policy-loader.d.ts +58 -0
- package/packages/core/dist/policy/policy-loader.d.ts.map +1 -0
- package/packages/core/dist/policy/policy-loader.js +156 -0
- package/packages/core/dist/policy/policy-loader.js.map +1 -0
- package/packages/core/dist/policy/risk-classifier.d.ts +18 -0
- package/packages/core/dist/policy/risk-classifier.d.ts.map +1 -0
- package/packages/core/dist/policy/risk-classifier.js +47 -0
- package/packages/core/dist/policy/risk-classifier.js.map +1 -0
- package/packages/core/dist/policy/types.d.ts +131 -0
- package/packages/core/dist/policy/types.d.ts.map +1 -0
- package/packages/core/dist/policy/types.js +8 -0
- package/packages/core/dist/policy/types.js.map +1 -0
- package/LICENSE +0 -21
- package/README.md +0 -243
- package/packages/cli/bin/matimo.cjs +0 -26
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Registry — in-memory store and search for skills
|
|
3
|
+
*
|
|
4
|
+
* Mirrors ToolRegistry but for skills. Provides discovery, search, and filtering.
|
|
5
|
+
* Supports both substring matching (default) and semantic search via pluggable embeddings.
|
|
6
|
+
*/
|
|
7
|
+
import { MatimoError, ErrorCode } from '../errors/matimo-error';
|
|
8
|
+
import { getGlobalMatimoLogger } from '../logging';
|
|
9
|
+
import { TfIdfEmbeddingProvider, cosineSimilarity } from './tfidf-embedding';
|
|
10
|
+
import { parseSkillSections, extractSkillContent, listSkillSections } from './skill-content-parser';
|
|
11
|
+
export class SkillRegistry {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.logger = getGlobalMatimoLogger();
|
|
14
|
+
this.skills = new Map();
|
|
15
|
+
/** Pluggable embedding provider for semantic search */
|
|
16
|
+
this.embeddingProvider = null;
|
|
17
|
+
/** Cached embeddings: skill name → vector */
|
|
18
|
+
this.embeddings = new Map();
|
|
19
|
+
/** Whether embeddings need rebuilding */
|
|
20
|
+
this.embeddingsDirty = true;
|
|
21
|
+
/** Cached parsed content for selective loading */
|
|
22
|
+
this.parsedContent = new Map();
|
|
23
|
+
/**
|
|
24
|
+
* Get or create the default TF-IDF provider.
|
|
25
|
+
*/
|
|
26
|
+
this.defaultProvider = null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Set a custom embedding provider (OpenAI, Cohere, etc.).
|
|
30
|
+
* If not set, a built-in TF-IDF provider is used as fallback.
|
|
31
|
+
*/
|
|
32
|
+
setEmbeddingProvider(provider) {
|
|
33
|
+
this.embeddingProvider = provider;
|
|
34
|
+
this.embeddingsDirty = true;
|
|
35
|
+
this.logger.debug('SkillRegistry: custom embedding provider set');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register a single skill
|
|
39
|
+
*/
|
|
40
|
+
register(skill) {
|
|
41
|
+
if (!skill.name) {
|
|
42
|
+
throw new MatimoError('Skill must have a name', ErrorCode.INVALID_SCHEMA);
|
|
43
|
+
}
|
|
44
|
+
this.skills.set(skill.name, skill);
|
|
45
|
+
this.embeddingsDirty = true;
|
|
46
|
+
// Cache parsed sections for selective loading
|
|
47
|
+
if (skill.body) {
|
|
48
|
+
this.parsedContent.set(skill.name, parseSkillSections(skill.body));
|
|
49
|
+
}
|
|
50
|
+
this.logger.debug('SkillRegistry: skill registered', { name: skill.name });
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Register multiple skills
|
|
54
|
+
*/
|
|
55
|
+
registerAll(skills) {
|
|
56
|
+
for (const skill of skills) {
|
|
57
|
+
this.register(skill);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Get a single skill by name
|
|
62
|
+
*/
|
|
63
|
+
get(name) {
|
|
64
|
+
return this.skills.get(name);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get a single skill by name (throws if not found)
|
|
68
|
+
*/
|
|
69
|
+
getRequired(name) {
|
|
70
|
+
const skill = this.skills.get(name);
|
|
71
|
+
if (!skill) {
|
|
72
|
+
throw new MatimoError(`Skill not found: ${name}`, ErrorCode.TOOL_NOT_FOUND);
|
|
73
|
+
}
|
|
74
|
+
return skill;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get selective skill content — only the sections an agent needs.
|
|
78
|
+
* This prevents dumping entire SKILL.md files into the LLM context.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* // Get only the error handling section, max 500 tokens
|
|
82
|
+
* registry.getSkillContent('postgres-query-operations', {
|
|
83
|
+
* sections: ['Error Handling'],
|
|
84
|
+
* maxTokens: 500,
|
|
85
|
+
* })
|
|
86
|
+
*/
|
|
87
|
+
getSkillContent(name, options) {
|
|
88
|
+
const parsed = this.parsedContent.get(name);
|
|
89
|
+
if (!parsed)
|
|
90
|
+
return null;
|
|
91
|
+
return extractSkillContent(parsed, options);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* List all sections of a skill with their token costs.
|
|
95
|
+
* Agents use this to decide which sections to load.
|
|
96
|
+
*/
|
|
97
|
+
getSkillSections(name) {
|
|
98
|
+
const parsed = this.parsedContent.get(name);
|
|
99
|
+
if (!parsed)
|
|
100
|
+
return null;
|
|
101
|
+
return listSkillSections(parsed);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* List all skills (Level 1 discovery — minimal context)
|
|
105
|
+
*/
|
|
106
|
+
list() {
|
|
107
|
+
return Array.from(this.skills.values()).map((skill) => ({
|
|
108
|
+
name: skill.name,
|
|
109
|
+
description: skill.description,
|
|
110
|
+
version: skill.version,
|
|
111
|
+
license: skill.license,
|
|
112
|
+
metadata: skill.metadata,
|
|
113
|
+
source: skill.source,
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Search skills by keyword, category, difficulty, etc.
|
|
118
|
+
*
|
|
119
|
+
* When `options.semantic` is true, uses embedding-based similarity ranking
|
|
120
|
+
* instead of substring matching. Falls back to built-in TF-IDF if no
|
|
121
|
+
* external embedding provider is configured.
|
|
122
|
+
*/
|
|
123
|
+
search(options = {}) {
|
|
124
|
+
const { query = '', category, difficulty, tags, author, limit = 50, offset = 0 } = options;
|
|
125
|
+
let results = Array.from(this.skills.values());
|
|
126
|
+
// Apply filters first (these are always exact/substring)
|
|
127
|
+
if (category) {
|
|
128
|
+
results = results.filter((skill) => skill.metadata?.category?.toLowerCase() === category.toLowerCase());
|
|
129
|
+
}
|
|
130
|
+
if (difficulty) {
|
|
131
|
+
results = results.filter((skill) => skill.metadata?.difficulty?.toLowerCase() === difficulty.toLowerCase());
|
|
132
|
+
}
|
|
133
|
+
if (tags && tags.length > 0) {
|
|
134
|
+
const metadataTags = tags.map((t) => t.toLowerCase());
|
|
135
|
+
results = results.filter((skill) => {
|
|
136
|
+
const skillTags = (skill.metadata?.tags || '')
|
|
137
|
+
.split(',')
|
|
138
|
+
.map((t) => t.trim().toLowerCase());
|
|
139
|
+
return metadataTags.some((tag) => skillTags.includes(tag));
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (author) {
|
|
143
|
+
results = results.filter((skill) => skill.metadata?.author?.toLowerCase() === author.toLowerCase());
|
|
144
|
+
}
|
|
145
|
+
// Apply query filter (substring or semantic)
|
|
146
|
+
if (query) {
|
|
147
|
+
if (options.semantic) {
|
|
148
|
+
// Semantic search: rank by embedding similarity
|
|
149
|
+
const scored = this.rankBySimilarity(query, results);
|
|
150
|
+
// Precompute a map for O(1) lookup by skill name
|
|
151
|
+
const skillByName = new Map(results.map((skill) => [skill.name, skill]));
|
|
152
|
+
results = scored
|
|
153
|
+
.filter((r) => r.score > 0.1) // Minimum relevance threshold
|
|
154
|
+
.sort((a, b) => b.score - a.score)
|
|
155
|
+
.map((r) => skillByName.get(r.skill.name))
|
|
156
|
+
.filter((skill) => skill !== undefined);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// Substring search (original behavior)
|
|
160
|
+
const lowerQuery = query.toLowerCase();
|
|
161
|
+
results = results.filter((skill) => {
|
|
162
|
+
const nameMatch = skill.name.toLowerCase().includes(lowerQuery);
|
|
163
|
+
const descMatch = skill.description.toLowerCase().includes(lowerQuery);
|
|
164
|
+
return nameMatch || descMatch;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Pagination
|
|
169
|
+
const paged = results.slice(offset, offset + limit);
|
|
170
|
+
return paged.map((skill) => ({
|
|
171
|
+
name: skill.name,
|
|
172
|
+
description: skill.description,
|
|
173
|
+
version: skill.version,
|
|
174
|
+
license: skill.license,
|
|
175
|
+
metadata: skill.metadata,
|
|
176
|
+
source: skill.source,
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Semantic search with relevance scores.
|
|
181
|
+
* Returns ranked results with cosine similarity scores.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* const results = await registry.semanticSearch('How do I handle Postgres connection pooling?');
|
|
185
|
+
* // → [{ skill: { name: 'postgres-query-operations', ... }, score: 0.82 }]
|
|
186
|
+
*/
|
|
187
|
+
async semanticSearch(query, options = {}) {
|
|
188
|
+
const { limit = 10, minScore = 0.1 } = options;
|
|
189
|
+
await this.ensureEmbeddings();
|
|
190
|
+
const provider = this.embeddingProvider || this.getDefaultProvider();
|
|
191
|
+
const queryEmbedding = await provider.embed(query);
|
|
192
|
+
const results = [];
|
|
193
|
+
for (const [name, embedding] of this.embeddings) {
|
|
194
|
+
const skill = this.skills.get(name);
|
|
195
|
+
if (!skill)
|
|
196
|
+
continue;
|
|
197
|
+
const score = cosineSimilarity(queryEmbedding, embedding);
|
|
198
|
+
if (score >= minScore) {
|
|
199
|
+
results.push({
|
|
200
|
+
skill: {
|
|
201
|
+
name: skill.name,
|
|
202
|
+
description: skill.description,
|
|
203
|
+
version: skill.version,
|
|
204
|
+
license: skill.license,
|
|
205
|
+
metadata: skill.metadata,
|
|
206
|
+
source: skill.source,
|
|
207
|
+
},
|
|
208
|
+
score,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get all skills (full definitions)
|
|
216
|
+
*/
|
|
217
|
+
getAll() {
|
|
218
|
+
return Array.from(this.skills.values());
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Check if a skill exists
|
|
222
|
+
*/
|
|
223
|
+
has(name) {
|
|
224
|
+
return this.skills.has(name);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get the count of registered skills
|
|
228
|
+
*/
|
|
229
|
+
count() {
|
|
230
|
+
return this.skills.size;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Clear all skills
|
|
234
|
+
*/
|
|
235
|
+
clear() {
|
|
236
|
+
this.skills.clear();
|
|
237
|
+
this.embeddings.clear();
|
|
238
|
+
this.parsedContent.clear();
|
|
239
|
+
this.embeddingsDirty = true;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Remove a skill
|
|
243
|
+
*/
|
|
244
|
+
remove(name) {
|
|
245
|
+
this.embeddings.delete(name);
|
|
246
|
+
this.parsedContent.delete(name);
|
|
247
|
+
this.embeddingsDirty = true;
|
|
248
|
+
return this.skills.delete(name);
|
|
249
|
+
}
|
|
250
|
+
// ─── Private: Embedding Management ──────────────────────────────────────
|
|
251
|
+
/**
|
|
252
|
+
* Ensure embeddings are computed and up-to-date.
|
|
253
|
+
*/
|
|
254
|
+
async ensureEmbeddings() {
|
|
255
|
+
if (!this.embeddingsDirty)
|
|
256
|
+
return;
|
|
257
|
+
const provider = this.embeddingProvider || this.getDefaultProvider();
|
|
258
|
+
const skills = Array.from(this.skills.values());
|
|
259
|
+
// Build text corpus: name + description + metadata tags
|
|
260
|
+
const texts = skills.map((s) => this.skillToText(s));
|
|
261
|
+
// If using TF-IDF, refit the vocabulary
|
|
262
|
+
if (provider instanceof TfIdfEmbeddingProvider) {
|
|
263
|
+
provider.fit(texts);
|
|
264
|
+
}
|
|
265
|
+
const vectors = await provider.embedBatch(texts);
|
|
266
|
+
this.embeddings.clear();
|
|
267
|
+
for (let i = 0; i < skills.length; i++) {
|
|
268
|
+
this.embeddings.set(skills[i].name, vectors[i]);
|
|
269
|
+
}
|
|
270
|
+
this.embeddingsDirty = false;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Synchronous ranking using TF-IDF (for the non-async search() method).
|
|
274
|
+
*/
|
|
275
|
+
rankBySimilarity(query, candidates) {
|
|
276
|
+
const provider = this.getDefaultProvider();
|
|
277
|
+
// Build corpus from candidates
|
|
278
|
+
const texts = candidates.map((s) => this.skillToText(s));
|
|
279
|
+
provider.fit([...texts, query]); // Include query in vocab
|
|
280
|
+
const queryVec = provider.embedSync(query);
|
|
281
|
+
return candidates.map((skill) => {
|
|
282
|
+
const skillVec = provider.embedSync(this.skillToText(skill));
|
|
283
|
+
return {
|
|
284
|
+
skill: {
|
|
285
|
+
name: skill.name,
|
|
286
|
+
description: skill.description,
|
|
287
|
+
version: skill.version,
|
|
288
|
+
license: skill.license,
|
|
289
|
+
metadata: skill.metadata,
|
|
290
|
+
source: skill.source,
|
|
291
|
+
},
|
|
292
|
+
score: cosineSimilarity(queryVec, skillVec),
|
|
293
|
+
};
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
getDefaultProvider() {
|
|
297
|
+
if (!this.defaultProvider) {
|
|
298
|
+
this.defaultProvider = new TfIdfEmbeddingProvider();
|
|
299
|
+
}
|
|
300
|
+
return this.defaultProvider;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Convert a skill into a searchable text string for embedding.
|
|
304
|
+
*/
|
|
305
|
+
skillToText(skill) {
|
|
306
|
+
const parts = [skill.name.replace(/-/g, ' '), skill.description];
|
|
307
|
+
if (skill.metadata?.tags)
|
|
308
|
+
parts.push(skill.metadata.tags);
|
|
309
|
+
if (skill.metadata?.category)
|
|
310
|
+
parts.push(skill.metadata.category);
|
|
311
|
+
if (skill.allowedTools)
|
|
312
|
+
parts.push(skill.allowedTools.join(' '));
|
|
313
|
+
return parts.join(' ');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=skill-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-registry.js","sourceRoot":"","sources":["../../src/core/skill-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAYpG,MAAM,OAAO,aAAa;IAA1B;QACU,WAAM,GAAG,qBAAqB,EAAE,CAAC;QACjC,WAAM,GAAG,IAAI,GAAG,EAA2B,CAAC;QAEpD,uDAAuD;QAC/C,sBAAiB,GAA6B,IAAI,CAAC;QAC3D,6CAA6C;QACrC,eAAU,GAAG,IAAI,GAAG,EAAoB,CAAC;QACjD,yCAAyC;QACjC,oBAAe,GAAG,IAAI,CAAC;QAC/B,kDAAkD;QAC1C,kBAAa,GAAG,IAAI,GAAG,EAA8B,CAAC;QA2T9D;;WAEG;QACK,oBAAe,GAAkC,IAAI,CAAC;IAkBhE,CAAC;IA9UC;;;OAGG;IACH,oBAAoB,CAAC,QAA2B;QAC9C,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC;QAClC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACpE,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,KAAsB;QAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YAChB,MAAM,IAAI,WAAW,CAAC,wBAAwB,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAE5B,8CAA8C;QAC9C,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,MAAyB;QACnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,IAAY;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,WAAW,CAAC,oBAAoB,IAAI,EAAE,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;;OAUG;IACH,eAAe,CAAC,IAAY,EAAE,OAA6B;QACzD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACH,gBAAgB,CACd,IAAY;QAEZ,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACtD,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,UAA+B,EAAE;QACtC,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;QAE3F,IAAI,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAE/C,yDAAyD;QACzD,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,GAAG,OAAO,CAAC,MAAM,CACtB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,CAC9E,CAAC;QACJ,CAAC;QACD,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,GAAG,OAAO,CAAC,MAAM,CACtB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,UAAU,CAAC,WAAW,EAAE,CAClF,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YACtD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;gBACjC,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC;qBAC3C,KAAK,CAAC,GAAG,CAAC;qBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;gBACtC,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7D,CAAC,CAAC,CAAC;QACL,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,GAAG,OAAO,CAAC,MAAM,CACtB,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,MAAM,CAAC,WAAW,EAAE,CAC1E,CAAC;QACJ,CAAC;QAED,6CAA6C;QAC7C,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,gDAAgD;gBAChD,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBACrD,iDAAiD;gBACjD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAU,CAAC,CAAC,CAAC;gBAClF,OAAO,GAAG,MAAM;qBACb,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,8BAA8B;qBAC3D,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;qBACjC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;qBACzC,MAAM,CAAC,CAAC,KAAK,EAAsC,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;YAChF,CAAC;iBAAM,CAAC;gBACN,uCAAuC;gBACvC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;gBACvC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;oBACjC,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;oBAChE,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;oBACvE,OAAO,SAAS,IAAI,SAAS,CAAC;gBAChC,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,aAAa;QACb,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;QAEpD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,MAAM,EAAE,KAAK,CAAC,MAAM;SACrB,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,cAAc,CAClB,KAAa,EACb,UAAiD,EAAE;QAEnD,MAAM,EAAE,KAAK,GAAG,EAAE,EAAE,QAAQ,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;QAE/C,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAE9B,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACrE,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAEnD,MAAM,OAAO,GAA2B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK;gBAAE,SAAS;YAErB,MAAM,KAAK,GAAG,gBAAgB,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;YAC1D,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;gBACtB,OAAO,CAAC,IAAI,CAAC;oBACX,KAAK,EAAE;wBACL,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,WAAW,EAAE,KAAK,CAAC,WAAW;wBAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,OAAO,EAAE,KAAK,CAAC,OAAO;wBACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;qBACrB;oBACD,KAAK;iBACN,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACnE,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACpB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAY;QACjB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,2EAA2E;IAE3E;;OAEG;IACK,KAAK,CAAC,gBAAgB;QAC5B,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,OAAO;QAElC,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACrE,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAEhD,wDAAwD;QACxD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QAErD,wCAAwC;QACxC,IAAI,QAAQ,YAAY,sBAAsB,EAAE,CAAC;YAC/C,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEjD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,KAAa,EAAE,UAA6B;QACnE,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAE3C,+BAA+B;QAC/B,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACzD,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,yBAAyB;QAE1D,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAE3C,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAC9B,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7D,OAAO;gBACL,KAAK,EAAE;oBACL,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB;gBACD,KAAK,EAAE,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC;aAC5C,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAMO,kBAAkB;QACxB,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1B,IAAI,CAAC,eAAe,GAAG,IAAI,sBAAsB,EAAE,CAAC;QACtD,CAAC;QACD,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,KAAsB;QACxC,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QACjE,IAAI,KAAK,CAAC,QAAQ,EAAE,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1D,IAAI,KAAK,CAAC,QAAQ,EAAE,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAClE,IAAI,KAAK,CAAC,YAAY;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACjE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TF-IDF Embedding Provider — zero-dependency semantic search
|
|
3
|
+
* (Term Frequency–Inverse Document Frequency)
|
|
4
|
+
* Provides a lightweight text-to-vector implementation using TF-IDF (Term
|
|
5
|
+
* Frequency–Inverse Document Frequency) for cosine-similarity ranking. This
|
|
6
|
+
* is good enough for 10–200 skills. For production enterprise deployments,
|
|
7
|
+
* plug in an OpenAI/Cohere `EmbeddingProvider` instead.
|
|
8
|
+
*
|
|
9
|
+
* No external dependencies — works out of the box.
|
|
10
|
+
*/
|
|
11
|
+
import { EmbeddingProvider } from './types';
|
|
12
|
+
/**
|
|
13
|
+
* Simple TF-IDF based embedding provider.
|
|
14
|
+
* Builds a vocabulary from the registered corpus and represents each text as
|
|
15
|
+
* a TF-IDF weighted vector.
|
|
16
|
+
*/
|
|
17
|
+
export declare class TfIdfEmbeddingProvider implements EmbeddingProvider {
|
|
18
|
+
private vocabulary;
|
|
19
|
+
private idf;
|
|
20
|
+
private corpusSize;
|
|
21
|
+
private _dimensions;
|
|
22
|
+
get dimensions(): number;
|
|
23
|
+
/**
|
|
24
|
+
* Build the vocabulary and IDF weights from a corpus of documents.
|
|
25
|
+
* Must be called before `embed()` or `embedBatch()`.
|
|
26
|
+
*/
|
|
27
|
+
fit(documents: string[]): void;
|
|
28
|
+
embed(text: string): Promise<number[]>;
|
|
29
|
+
embedBatch(texts: string[]): Promise<number[][]>;
|
|
30
|
+
/**
|
|
31
|
+
* Synchronous embed for internal use (no async overhead).
|
|
32
|
+
*/
|
|
33
|
+
embedSync(text: string): number[];
|
|
34
|
+
/**
|
|
35
|
+
* Tokenize text into lowercase terms.
|
|
36
|
+
* Splits on non-alphanumeric characters and filters stopwords.
|
|
37
|
+
*/
|
|
38
|
+
private tokenize;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Cosine similarity between two vectors.
|
|
42
|
+
* Returns a value between -1 and 1 (1 = identical, 0 = orthogonal).
|
|
43
|
+
*/
|
|
44
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
45
|
+
//# sourceMappingURL=tfidf-embedding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tfidf-embedding.d.ts","sourceRoot":"","sources":["../../src/core/tfidf-embedding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,iBAAiB;IAC9D,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,GAAG,CAAqC;IAChD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAK;IAExB,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;OAGG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IA2BxB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAItC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAItD;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAsCjC;;;OAGG;IACH,OAAO,CAAC,QAAQ;CAMjB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAejE"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TF-IDF Embedding Provider — zero-dependency semantic search
|
|
3
|
+
* (Term Frequency–Inverse Document Frequency)
|
|
4
|
+
* Provides a lightweight text-to-vector implementation using TF-IDF (Term
|
|
5
|
+
* Frequency–Inverse Document Frequency) for cosine-similarity ranking. This
|
|
6
|
+
* is good enough for 10–200 skills. For production enterprise deployments,
|
|
7
|
+
* plug in an OpenAI/Cohere `EmbeddingProvider` instead.
|
|
8
|
+
*
|
|
9
|
+
* No external dependencies — works out of the box.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Simple TF-IDF based embedding provider.
|
|
13
|
+
* Builds a vocabulary from the registered corpus and represents each text as
|
|
14
|
+
* a TF-IDF weighted vector.
|
|
15
|
+
*/
|
|
16
|
+
export class TfIdfEmbeddingProvider {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.vocabulary = new Map();
|
|
19
|
+
this.idf = new Float64Array(0);
|
|
20
|
+
this.corpusSize = 0;
|
|
21
|
+
this._dimensions = 0;
|
|
22
|
+
}
|
|
23
|
+
get dimensions() {
|
|
24
|
+
return this._dimensions;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the vocabulary and IDF weights from a corpus of documents.
|
|
28
|
+
* Must be called before `embed()` or `embedBatch()`.
|
|
29
|
+
*/
|
|
30
|
+
fit(documents) {
|
|
31
|
+
this.vocabulary.clear();
|
|
32
|
+
this.corpusSize = documents.length;
|
|
33
|
+
// Build vocabulary (unique terms across all documents)
|
|
34
|
+
const docFrequency = new Map();
|
|
35
|
+
for (const doc of documents) {
|
|
36
|
+
const terms = this.tokenize(doc);
|
|
37
|
+
const uniqueTerms = new Set(terms);
|
|
38
|
+
for (const term of uniqueTerms) {
|
|
39
|
+
docFrequency.set(term, (docFrequency.get(term) || 0) + 1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Assign indices and compute IDF
|
|
43
|
+
let idx = 0;
|
|
44
|
+
const idfValues = [];
|
|
45
|
+
for (const [term, df] of docFrequency) {
|
|
46
|
+
this.vocabulary.set(term, idx++);
|
|
47
|
+
// Smooth IDF: log((N + 1) / (df + 1)) + 1
|
|
48
|
+
idfValues.push(Math.log((this.corpusSize + 1) / (df + 1)) + 1);
|
|
49
|
+
}
|
|
50
|
+
this._dimensions = idfValues.length;
|
|
51
|
+
this.idf = new Float64Array(idfValues);
|
|
52
|
+
}
|
|
53
|
+
async embed(text) {
|
|
54
|
+
return this.embedSync(text);
|
|
55
|
+
}
|
|
56
|
+
async embedBatch(texts) {
|
|
57
|
+
return texts.map((t) => this.embedSync(t));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Synchronous embed for internal use (no async overhead).
|
|
61
|
+
*/
|
|
62
|
+
embedSync(text) {
|
|
63
|
+
if (this._dimensions === 0) {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const terms = this.tokenize(text);
|
|
67
|
+
const tf = new Float64Array(this._dimensions);
|
|
68
|
+
// Count term frequencies
|
|
69
|
+
for (const term of terms) {
|
|
70
|
+
const idx = this.vocabulary.get(term);
|
|
71
|
+
if (idx !== undefined) {
|
|
72
|
+
tf[idx]++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Normalize TF (sublinear: 1 + log(tf) if tf > 0)
|
|
76
|
+
for (let i = 0; i < this._dimensions; i++) {
|
|
77
|
+
if (tf[i] > 0) {
|
|
78
|
+
tf[i] = (1 + Math.log(tf[i])) * this.idf[i];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// L2 normalize
|
|
82
|
+
let norm = 0;
|
|
83
|
+
for (let i = 0; i < this._dimensions; i++) {
|
|
84
|
+
norm += tf[i] * tf[i];
|
|
85
|
+
}
|
|
86
|
+
norm = Math.sqrt(norm);
|
|
87
|
+
if (norm > 0) {
|
|
88
|
+
for (let i = 0; i < this._dimensions; i++) {
|
|
89
|
+
tf[i] /= norm;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return Array.from(tf);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Tokenize text into lowercase terms.
|
|
96
|
+
* Splits on non-alphanumeric characters and filters stopwords.
|
|
97
|
+
*/
|
|
98
|
+
tokenize(text) {
|
|
99
|
+
return text
|
|
100
|
+
.toLowerCase()
|
|
101
|
+
.split(/[^a-z0-9]+/)
|
|
102
|
+
.filter((t) => t.length > 1 && !STOPWORDS.has(t));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Cosine similarity between two vectors.
|
|
107
|
+
* Returns a value between -1 and 1 (1 = identical, 0 = orthogonal).
|
|
108
|
+
*/
|
|
109
|
+
export function cosineSimilarity(a, b) {
|
|
110
|
+
if (a.length !== b.length || a.length === 0)
|
|
111
|
+
return 0;
|
|
112
|
+
let dot = 0;
|
|
113
|
+
let normA = 0;
|
|
114
|
+
let normB = 0;
|
|
115
|
+
for (let i = 0; i < a.length; i++) {
|
|
116
|
+
dot += a[i] * b[i];
|
|
117
|
+
normA += a[i] * a[i];
|
|
118
|
+
normB += b[i] * b[i];
|
|
119
|
+
}
|
|
120
|
+
const denominator = Math.sqrt(normA) * Math.sqrt(normB);
|
|
121
|
+
return denominator === 0 ? 0 : dot / denominator;
|
|
122
|
+
}
|
|
123
|
+
/** Common English stopwords to exclude from TF-IDF */
|
|
124
|
+
const STOPWORDS = new Set([
|
|
125
|
+
'a',
|
|
126
|
+
'an',
|
|
127
|
+
'the',
|
|
128
|
+
'and',
|
|
129
|
+
'or',
|
|
130
|
+
'but',
|
|
131
|
+
'in',
|
|
132
|
+
'on',
|
|
133
|
+
'at',
|
|
134
|
+
'to',
|
|
135
|
+
'for',
|
|
136
|
+
'of',
|
|
137
|
+
'with',
|
|
138
|
+
'by',
|
|
139
|
+
'from',
|
|
140
|
+
'is',
|
|
141
|
+
'it',
|
|
142
|
+
'as',
|
|
143
|
+
'be',
|
|
144
|
+
'was',
|
|
145
|
+
'are',
|
|
146
|
+
'this',
|
|
147
|
+
'that',
|
|
148
|
+
'not',
|
|
149
|
+
'do',
|
|
150
|
+
'if',
|
|
151
|
+
'so',
|
|
152
|
+
'no',
|
|
153
|
+
'up',
|
|
154
|
+
'my',
|
|
155
|
+
'we',
|
|
156
|
+
'he',
|
|
157
|
+
'she',
|
|
158
|
+
'they',
|
|
159
|
+
'you',
|
|
160
|
+
'me',
|
|
161
|
+
'us',
|
|
162
|
+
'all',
|
|
163
|
+
'can',
|
|
164
|
+
'had',
|
|
165
|
+
'has',
|
|
166
|
+
'have',
|
|
167
|
+
'will',
|
|
168
|
+
'would',
|
|
169
|
+
'could',
|
|
170
|
+
'should',
|
|
171
|
+
'may',
|
|
172
|
+
'might',
|
|
173
|
+
'shall',
|
|
174
|
+
'been',
|
|
175
|
+
'being',
|
|
176
|
+
'were',
|
|
177
|
+
'did',
|
|
178
|
+
'does',
|
|
179
|
+
'its',
|
|
180
|
+
'than',
|
|
181
|
+
'then',
|
|
182
|
+
'when',
|
|
183
|
+
'what',
|
|
184
|
+
'which',
|
|
185
|
+
'who',
|
|
186
|
+
'how',
|
|
187
|
+
'there',
|
|
188
|
+
'here',
|
|
189
|
+
'about',
|
|
190
|
+
'into',
|
|
191
|
+
'over',
|
|
192
|
+
'after',
|
|
193
|
+
'also',
|
|
194
|
+
'each',
|
|
195
|
+
'just',
|
|
196
|
+
'only',
|
|
197
|
+
'very',
|
|
198
|
+
]);
|
|
199
|
+
//# sourceMappingURL=tfidf-embedding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tfidf-embedding.js","sourceRoot":"","sources":["../../src/core/tfidf-embedding.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,7 +12,9 @@ export declare class ToolLoader {
|
|
|
12
12
|
private static discoveredPathsCache;
|
|
13
13
|
/**
|
|
14
14
|
* Discover packages using only fs and path (no createRequire needed)
|
|
15
|
-
* Searches for tools in node_modules/@matimo/* and workspace packages
|
|
15
|
+
* Searches for tools in node_modules/@matimo/* and workspace packages.
|
|
16
|
+
* Tries process.cwd() first, then falls back to __dirname-based discovery
|
|
17
|
+
* (critical for Claude Desktop where cwd may be '/' on macOS).
|
|
16
18
|
*/
|
|
17
19
|
private getNodeModulesPath;
|
|
18
20
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-loader.d.ts","sourceRoot":"","sources":["../../src/core/tool-loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAA0B,MAAM,UAAU,CAAC;AAGlE;;;;GAIG;AAEH,qBAAa,UAAU;IACrB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAyB;IAC5D
|
|
1
|
+
{"version":3,"file":"tool-loader.d.ts","sourceRoot":"","sources":["../../src/core/tool-loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAA0B,MAAM,UAAU,CAAC;AAGlE;;;;GAIG;AAEH,qBAAa,UAAU;IACrB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAyB;IAC5D;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAqC1B;;;;;OAKG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc;IAgDlD;;;;;OAKG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC;IAkDpE;;;;OAIG;IACH,kBAAkB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc;IAIjD;;;;OAIG;IACH,oBAAoB,IAAI,MAAM,EAAE;IAwFhC;;;OAGG;IACH,MAAM,CAAC,mBAAmB,IAAI,IAAI;IAIlC;;;;OAIG;IACH,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC;CAkB5E;AAED,eAAe,UAAU,CAAC"}
|
|
@@ -11,16 +11,32 @@ import { MatimoError, ErrorCode } from '../errors/matimo-error';
|
|
|
11
11
|
export class ToolLoader {
|
|
12
12
|
/**
|
|
13
13
|
* Discover packages using only fs and path (no createRequire needed)
|
|
14
|
-
* Searches for tools in node_modules/@matimo/* and workspace packages
|
|
14
|
+
* Searches for tools in node_modules/@matimo/* and workspace packages.
|
|
15
|
+
* Tries process.cwd() first, then falls back to __dirname-based discovery
|
|
16
|
+
* (critical for Claude Desktop where cwd may be '/' on macOS).
|
|
15
17
|
*/
|
|
16
18
|
getNodeModulesPath() {
|
|
17
19
|
try {
|
|
18
|
-
//
|
|
20
|
+
// Strategy 1: Walk up from process.cwd()
|
|
19
21
|
let currentPath = process.cwd();
|
|
20
22
|
for (let i = 0; i < 15; i++) {
|
|
21
23
|
const nodeModules = path.join(currentPath, 'node_modules');
|
|
22
24
|
if (fs.existsSync(nodeModules)) {
|
|
23
|
-
|
|
25
|
+
const matimoScope = path.join(nodeModules, '@matimo');
|
|
26
|
+
if (fs.existsSync(matimoScope)) {
|
|
27
|
+
return nodeModules;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
currentPath = path.dirname(currentPath);
|
|
31
|
+
}
|
|
32
|
+
// Strategy 2: Walk up from this file's location (__dirname)
|
|
33
|
+
// When this code is in node_modules/@matimo/core/dist/core/tool-loader.js,
|
|
34
|
+
// walking up will find the node_modules directory directly.
|
|
35
|
+
// When in monorepo at packages/core/src/core/, it will find root node_modules.
|
|
36
|
+
currentPath = __dirname;
|
|
37
|
+
for (let i = 0; i < 10; i++) {
|
|
38
|
+
const nodeModules = path.join(currentPath, 'node_modules');
|
|
39
|
+
if (fs.existsSync(nodeModules)) {
|
|
24
40
|
const matimoScope = path.join(nodeModules, '@matimo');
|
|
25
41
|
if (fs.existsSync(matimoScope)) {
|
|
26
42
|
return nodeModules;
|
|
@@ -154,16 +170,23 @@ export class ToolLoader {
|
|
|
154
170
|
discoveredPaths.push(coreToolsPath);
|
|
155
171
|
}
|
|
156
172
|
}
|
|
157
|
-
// If not found in node_modules, try workspace
|
|
173
|
+
// If not found in node_modules, try workspace (from cwd and __dirname)
|
|
158
174
|
if (discoveredPaths.length === 0) {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (
|
|
163
|
-
discoveredPaths.push(coreToolsPath);
|
|
175
|
+
const searchRoots = [process.cwd(), __dirname];
|
|
176
|
+
let found = false;
|
|
177
|
+
for (const root of searchRoots) {
|
|
178
|
+
if (found)
|
|
164
179
|
break;
|
|
180
|
+
let currentPath = root;
|
|
181
|
+
for (let i = 0; i < 20; i++) {
|
|
182
|
+
const coreToolsPath = path.join(currentPath, 'packages', 'core', 'tools');
|
|
183
|
+
if (fs.existsSync(coreToolsPath)) {
|
|
184
|
+
discoveredPaths.push(coreToolsPath);
|
|
185
|
+
found = true;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
currentPath = path.dirname(currentPath);
|
|
165
189
|
}
|
|
166
|
-
currentPath = path.dirname(currentPath);
|
|
167
190
|
}
|
|
168
191
|
}
|
|
169
192
|
}
|