@burtson-labs/agent-core 1.6.13

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 (195) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +88 -0
  3. package/dist/index.d.ts +16 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +52 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/mcp/activation.d.ts +60 -0
  8. package/dist/mcp/activation.d.ts.map +1 -0
  9. package/dist/mcp/activation.js +139 -0
  10. package/dist/mcp/activation.js.map +1 -0
  11. package/dist/mcp/clientPool.d.ts +202 -0
  12. package/dist/mcp/clientPool.d.ts.map +1 -0
  13. package/dist/mcp/clientPool.js +469 -0
  14. package/dist/mcp/clientPool.js.map +1 -0
  15. package/dist/mcp/index.d.ts +18 -0
  16. package/dist/mcp/index.d.ts.map +1 -0
  17. package/dist/mcp/index.js +28 -0
  18. package/dist/mcp/index.js.map +1 -0
  19. package/dist/mcp/server.d.ts +43 -0
  20. package/dist/mcp/server.d.ts.map +1 -0
  21. package/dist/mcp/server.js +130 -0
  22. package/dist/mcp/server.js.map +1 -0
  23. package/dist/mcp/toolAdapter.d.ts +57 -0
  24. package/dist/mcp/toolAdapter.d.ts.map +1 -0
  25. package/dist/mcp/toolAdapter.js +223 -0
  26. package/dist/mcp/toolAdapter.js.map +1 -0
  27. package/dist/mcp/types.d.ts +122 -0
  28. package/dist/mcp/types.d.ts.map +1 -0
  29. package/dist/mcp/types.js +15 -0
  30. package/dist/mcp/types.js.map +1 -0
  31. package/dist/providers/deterministic-provider.d.ts +21 -0
  32. package/dist/providers/deterministic-provider.d.ts.map +1 -0
  33. package/dist/providers/deterministic-provider.js +80 -0
  34. package/dist/providers/deterministic-provider.js.map +1 -0
  35. package/dist/providers/provider-client.d.ts +12 -0
  36. package/dist/providers/provider-client.d.ts.map +1 -0
  37. package/dist/providers/provider-client.js +11 -0
  38. package/dist/providers/provider-client.js.map +1 -0
  39. package/dist/runtime/AgentRuntime.d.ts +67 -0
  40. package/dist/runtime/AgentRuntime.d.ts.map +1 -0
  41. package/dist/runtime/AgentRuntime.js +382 -0
  42. package/dist/runtime/AgentRuntime.js.map +1 -0
  43. package/dist/security/secretPatterns.d.ts +76 -0
  44. package/dist/security/secretPatterns.d.ts.map +1 -0
  45. package/dist/security/secretPatterns.js +290 -0
  46. package/dist/security/secretPatterns.js.map +1 -0
  47. package/dist/tools/ask-user-tool.d.ts +19 -0
  48. package/dist/tools/ask-user-tool.d.ts.map +1 -0
  49. package/dist/tools/ask-user-tool.js +148 -0
  50. package/dist/tools/ask-user-tool.js.map +1 -0
  51. package/dist/tools/compactMessages.d.ts +52 -0
  52. package/dist/tools/compactMessages.d.ts.map +1 -0
  53. package/dist/tools/compactMessages.js +158 -0
  54. package/dist/tools/compactMessages.js.map +1 -0
  55. package/dist/tools/core-tools.d.ts +29 -0
  56. package/dist/tools/core-tools.d.ts.map +1 -0
  57. package/dist/tools/core-tools.js +2214 -0
  58. package/dist/tools/core-tools.js.map +1 -0
  59. package/dist/tools/git-tools.d.ts +32 -0
  60. package/dist/tools/git-tools.d.ts.map +1 -0
  61. package/dist/tools/git-tools.js +330 -0
  62. package/dist/tools/git-tools.js.map +1 -0
  63. package/dist/tools/index.d.ts +15 -0
  64. package/dist/tools/index.d.ts.map +1 -0
  65. package/dist/tools/index.js +31 -0
  66. package/dist/tools/index.js.map +1 -0
  67. package/dist/tools/language-adapters.d.ts +48 -0
  68. package/dist/tools/language-adapters.d.ts.map +1 -0
  69. package/dist/tools/language-adapters.js +299 -0
  70. package/dist/tools/language-adapters.js.map +1 -0
  71. package/dist/tools/loop/compactionTrigger.d.ts +47 -0
  72. package/dist/tools/loop/compactionTrigger.d.ts.map +1 -0
  73. package/dist/tools/loop/compactionTrigger.js +32 -0
  74. package/dist/tools/loop/compactionTrigger.js.map +1 -0
  75. package/dist/tools/loop/finalAnswerNudges.d.ts +68 -0
  76. package/dist/tools/loop/finalAnswerNudges.d.ts.map +1 -0
  77. package/dist/tools/loop/finalAnswerNudges.js +87 -0
  78. package/dist/tools/loop/finalAnswerNudges.js.map +1 -0
  79. package/dist/tools/loop/goalAnchor.d.ts +72 -0
  80. package/dist/tools/loop/goalAnchor.d.ts.map +1 -0
  81. package/dist/tools/loop/goalAnchor.js +76 -0
  82. package/dist/tools/loop/goalAnchor.js.map +1 -0
  83. package/dist/tools/loop/llmStream.d.ts +70 -0
  84. package/dist/tools/loop/llmStream.d.ts.map +1 -0
  85. package/dist/tools/loop/llmStream.js +181 -0
  86. package/dist/tools/loop/llmStream.js.map +1 -0
  87. package/dist/tools/loop/parallelExecute.d.ts +57 -0
  88. package/dist/tools/loop/parallelExecute.d.ts.map +1 -0
  89. package/dist/tools/loop/parallelExecute.js +54 -0
  90. package/dist/tools/loop/parallelExecute.js.map +1 -0
  91. package/dist/tools/loop/singleToolExecute.d.ts +71 -0
  92. package/dist/tools/loop/singleToolExecute.d.ts.map +1 -0
  93. package/dist/tools/loop/singleToolExecute.js +139 -0
  94. package/dist/tools/loop/singleToolExecute.js.map +1 -0
  95. package/dist/tools/loop/toolCallNormalize.d.ts +57 -0
  96. package/dist/tools/loop/toolCallNormalize.d.ts.map +1 -0
  97. package/dist/tools/loop/toolCallNormalize.js +99 -0
  98. package/dist/tools/loop/toolCallNormalize.js.map +1 -0
  99. package/dist/tools/loop/turnSetup.d.ts +43 -0
  100. package/dist/tools/loop/turnSetup.d.ts.map +1 -0
  101. package/dist/tools/loop/turnSetup.js +48 -0
  102. package/dist/tools/loop/turnSetup.js.map +1 -0
  103. package/dist/tools/ocr.d.ts +52 -0
  104. package/dist/tools/ocr.d.ts.map +1 -0
  105. package/dist/tools/ocr.js +238 -0
  106. package/dist/tools/ocr.js.map +1 -0
  107. package/dist/tools/post-edit-checks.d.ts +46 -0
  108. package/dist/tools/post-edit-checks.d.ts.map +1 -0
  109. package/dist/tools/post-edit-checks.js +236 -0
  110. package/dist/tools/post-edit-checks.js.map +1 -0
  111. package/dist/tools/skill-loader.d.ts +94 -0
  112. package/dist/tools/skill-loader.d.ts.map +1 -0
  113. package/dist/tools/skill-loader.js +422 -0
  114. package/dist/tools/skill-loader.js.map +1 -0
  115. package/dist/tools/skill-registry.d.ts +44 -0
  116. package/dist/tools/skill-registry.d.ts.map +1 -0
  117. package/dist/tools/skill-registry.js +118 -0
  118. package/dist/tools/skill-registry.js.map +1 -0
  119. package/dist/tools/skill-types.d.ts +38 -0
  120. package/dist/tools/skill-types.d.ts.map +1 -0
  121. package/dist/tools/skill-types.js +10 -0
  122. package/dist/tools/skill-types.js.map +1 -0
  123. package/dist/tools/skills/code-review-skill.d.ts +9 -0
  124. package/dist/tools/skills/code-review-skill.d.ts.map +1 -0
  125. package/dist/tools/skills/code-review-skill.js +66 -0
  126. package/dist/tools/skills/code-review-skill.js.map +1 -0
  127. package/dist/tools/skills/core-skill.d.ts +13 -0
  128. package/dist/tools/skills/core-skill.d.ts.map +1 -0
  129. package/dist/tools/skills/core-skill.js +23 -0
  130. package/dist/tools/skills/core-skill.js.map +1 -0
  131. package/dist/tools/skills/git-skill.d.ts +10 -0
  132. package/dist/tools/skills/git-skill.d.ts.map +1 -0
  133. package/dist/tools/skills/git-skill.js +30 -0
  134. package/dist/tools/skills/git-skill.js.map +1 -0
  135. package/dist/tools/skills/index.d.ts +17 -0
  136. package/dist/tools/skills/index.d.ts.map +1 -0
  137. package/dist/tools/skills/index.js +49 -0
  138. package/dist/tools/skills/index.js.map +1 -0
  139. package/dist/tools/skills/interaction-skill.d.ts +14 -0
  140. package/dist/tools/skills/interaction-skill.d.ts.map +1 -0
  141. package/dist/tools/skills/interaction-skill.js +24 -0
  142. package/dist/tools/skills/interaction-skill.js.map +1 -0
  143. package/dist/tools/skills/mail-search-skill.d.ts +25 -0
  144. package/dist/tools/skills/mail-search-skill.d.ts.map +1 -0
  145. package/dist/tools/skills/mail-search-skill.js +343 -0
  146. package/dist/tools/skills/mail-search-skill.js.map +1 -0
  147. package/dist/tools/skills/plan-skill.d.ts +10 -0
  148. package/dist/tools/skills/plan-skill.d.ts.map +1 -0
  149. package/dist/tools/skills/plan-skill.js +126 -0
  150. package/dist/tools/skills/plan-skill.js.map +1 -0
  151. package/dist/tools/skills/semantic-search-skill.d.ts +22 -0
  152. package/dist/tools/skills/semantic-search-skill.d.ts.map +1 -0
  153. package/dist/tools/skills/semantic-search-skill.js +244 -0
  154. package/dist/tools/skills/semantic-search-skill.js.map +1 -0
  155. package/dist/tools/skills/test-gen-skill.d.ts +9 -0
  156. package/dist/tools/skills/test-gen-skill.d.ts.map +1 -0
  157. package/dist/tools/skills/test-gen-skill.js +123 -0
  158. package/dist/tools/skills/test-gen-skill.js.map +1 -0
  159. package/dist/tools/tool-registry.d.ts +60 -0
  160. package/dist/tools/tool-registry.d.ts.map +1 -0
  161. package/dist/tools/tool-registry.js +200 -0
  162. package/dist/tools/tool-registry.js.map +1 -0
  163. package/dist/tools/tool-types.d.ts +281 -0
  164. package/dist/tools/tool-types.d.ts.map +1 -0
  165. package/dist/tools/tool-types.js +10 -0
  166. package/dist/tools/tool-types.js.map +1 -0
  167. package/dist/tools/tool-use-loop.d.ts +231 -0
  168. package/dist/tools/tool-use-loop.d.ts.map +1 -0
  169. package/dist/tools/tool-use-loop.js +2057 -0
  170. package/dist/tools/tool-use-loop.js.map +1 -0
  171. package/dist/tools/tool-use-parser.d.ts +78 -0
  172. package/dist/tools/tool-use-parser.d.ts.map +1 -0
  173. package/dist/tools/tool-use-parser.js +427 -0
  174. package/dist/tools/tool-use-parser.js.map +1 -0
  175. package/dist/tools/toolAvailabilityDetector.d.ts +48 -0
  176. package/dist/tools/toolAvailabilityDetector.d.ts.map +1 -0
  177. package/dist/tools/toolAvailabilityDetector.js +156 -0
  178. package/dist/tools/toolAvailabilityDetector.js.map +1 -0
  179. package/dist/tools/unified-patch.d.ts +87 -0
  180. package/dist/tools/unified-patch.d.ts.map +1 -0
  181. package/dist/tools/unified-patch.js +217 -0
  182. package/dist/tools/unified-patch.js.map +1 -0
  183. package/dist/types/agent.d.ts +69 -0
  184. package/dist/types/agent.d.ts.map +1 -0
  185. package/dist/types/agent.js +54 -0
  186. package/dist/types/agent.js.map +1 -0
  187. package/dist/types/tasks.d.ts +22 -0
  188. package/dist/types/tasks.d.ts.map +1 -0
  189. package/dist/types/tasks.js +3 -0
  190. package/dist/types/tasks.js.map +1 -0
  191. package/dist/utils/event-emitter.d.ts +13 -0
  192. package/dist/utils/event-emitter.d.ts.map +1 -0
  193. package/dist/utils/event-emitter.js +54 -0
  194. package/dist/utils/event-emitter.js.map +1 -0
  195. package/package.json +33 -0
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ /**
3
+ * Semantic search skill — auto-activated when users ask about code concepts,
4
+ * architecture, or need to find code by meaning rather than literal text.
5
+ *
6
+ * Uses Ollama's nomic-embed-text model for local embeddings. Indexes workspace
7
+ * files on first search and caches vectors in memory for the session.
8
+ *
9
+ * Requires Ollama running locally with nomic-embed-text installed:
10
+ * ollama pull nomic-embed-text
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.semanticSearchSkill = void 0;
14
+ exports.configureSemanticSearchOllamaUrl = configureSemanticSearchOllamaUrl;
15
+ exports.resetSemanticIndex = resetSemanticIndex;
16
+ let store = [];
17
+ let indexedPaths = new Set();
18
+ let ollamaBaseUrl = 'http://localhost:11434';
19
+ async function embed(text) {
20
+ const response = await fetch(`${ollamaBaseUrl}/api/embeddings`, {
21
+ method: 'POST',
22
+ headers: { 'Content-Type': 'application/json' },
23
+ body: JSON.stringify({ model: 'nomic-embed-text', prompt: text }),
24
+ signal: AbortSignal.timeout(10000)
25
+ });
26
+ if (!response.ok) {
27
+ throw new Error(`Embedding failed: ${response.status}`);
28
+ }
29
+ const data = await response.json();
30
+ if (!Array.isArray(data.embedding)) {
31
+ throw new Error('Embedding response missing vector');
32
+ }
33
+ return data.embedding;
34
+ }
35
+ function cosineSimilarity(a, b) {
36
+ if (a.length !== b.length || a.length === 0)
37
+ return 0;
38
+ let dot = 0, normA = 0, normB = 0;
39
+ for (let i = 0; i < a.length; i++) {
40
+ dot += a[i] * b[i];
41
+ normA += a[i] * a[i];
42
+ normB += b[i] * b[i];
43
+ }
44
+ const denom = Math.sqrt(normA) * Math.sqrt(normB);
45
+ return denom === 0 ? 0 : dot / denom;
46
+ }
47
+ function chunkText(text, maxChars = 800) {
48
+ if (text.length <= maxChars)
49
+ return [text];
50
+ const chunks = [];
51
+ const lines = text.split('\n');
52
+ let current = '';
53
+ for (const line of lines) {
54
+ if ((current + line).length > maxChars && current.length > 0) {
55
+ chunks.push(current.trim());
56
+ current = '';
57
+ }
58
+ current += line + '\n';
59
+ }
60
+ if (current.trim())
61
+ chunks.push(current.trim());
62
+ return chunks;
63
+ }
64
+ async function indexFile(path, content) {
65
+ if (indexedPaths.has(path))
66
+ return;
67
+ const chunks = chunkText(content);
68
+ for (const chunk of chunks) {
69
+ try {
70
+ const vector = await embed(chunk);
71
+ store.push({ path, content: chunk, vector });
72
+ }
73
+ catch {
74
+ // Skip failed chunks silently
75
+ }
76
+ }
77
+ indexedPaths.add(path);
78
+ }
79
+ const semanticSearchTool = {
80
+ name: 'semantic_search',
81
+ description: 'Search the codebase by meaning, not just text. Finds code related to a concept even when the exact words differ. Automatically indexes workspace files on first use. Use this when search_code (regex) misses what you need.',
82
+ parameters: [
83
+ { name: 'query', description: 'Natural language description of what you are looking for (e.g. "authentication middleware", "database connection pooling", "error boundary component")', required: true },
84
+ { name: 'file_glob', description: 'Optional glob to restrict which files are searched (e.g. "src/**/*.ts"). Defaults to all .ts/.tsx/.js/.jsx/.py files.' },
85
+ { name: 'top_k', description: 'Number of results to return (default: 6)' }
86
+ ],
87
+ async execute(params, ctx) {
88
+ const query = params.query?.trim();
89
+ if (!query)
90
+ return { output: 'Error: query parameter is required', isError: true };
91
+ const topK = Math.min(parseInt(params.top_k ?? '6', 10) || 6, 15);
92
+ const glob = params.file_glob ?? '**/*.{ts,tsx,js,jsx,py}';
93
+ // If the store is empty, index workspace files first
94
+ if (store.length === 0) {
95
+ try {
96
+ const files = await ctx.listFiles(glob);
97
+ const toIndex = files.slice(0, 50); // Cap at 50 files for speed
98
+ for (const file of toIndex) {
99
+ try {
100
+ const absPath = file.startsWith('/') ||
101
+ file.startsWith('~') ||
102
+ /^[A-Za-z]:[\\/]/.test(file) ||
103
+ file.startsWith('\\\\')
104
+ ? file
105
+ : `${ctx.workspaceRoot}/${file}`;
106
+ const content = await ctx.readFile(absPath);
107
+ if (content.length > 0 && content.length < 50000) {
108
+ await indexFile(file, content);
109
+ }
110
+ }
111
+ catch {
112
+ // Skip unreadable files
113
+ }
114
+ }
115
+ if (store.length === 0) {
116
+ return { output: 'No files could be indexed. Is nomic-embed-text installed? Run: ollama pull nomic-embed-text', isError: true };
117
+ }
118
+ }
119
+ catch (err) {
120
+ return {
121
+ output: `Embedding search failed: ${err instanceof Error ? err.message : String(err)}. Ensure Ollama is running with nomic-embed-text.`,
122
+ isError: true
123
+ };
124
+ }
125
+ }
126
+ // Search
127
+ try {
128
+ const queryVector = await embed(query);
129
+ const scored = store.map(chunk => ({
130
+ path: chunk.path,
131
+ content: chunk.content,
132
+ score: cosineSimilarity(queryVector, chunk.vector)
133
+ }));
134
+ scored.sort((a, b) => b.score - a.score);
135
+ // Deduplicate by path, keeping best score per file
136
+ const seen = new Map();
137
+ for (const item of scored) {
138
+ if (!seen.has(item.path)) {
139
+ seen.set(item.path, item);
140
+ }
141
+ if (seen.size >= topK)
142
+ break;
143
+ }
144
+ const results = Array.from(seen.values());
145
+ if (results.length === 0) {
146
+ return { output: `No relevant results found for: "${query}"` };
147
+ }
148
+ const output = results.map((r, i) => {
149
+ const preview = r.content.slice(0, 500);
150
+ return `### ${i + 1}. ${r.path} (score: ${r.score.toFixed(3)})\n\`\`\`\n${preview}${r.content.length > 500 ? '\n...' : ''}\n\`\`\``;
151
+ }).join('\n\n');
152
+ return { output: `Found ${results.length} relevant files for "${query}":\n\n${output}` };
153
+ }
154
+ catch (err) {
155
+ return {
156
+ output: `Search failed: ${err instanceof Error ? err.message : String(err)}`,
157
+ isError: true
158
+ };
159
+ }
160
+ }
161
+ };
162
+ const indexWorkspaceTool = {
163
+ name: 'index_workspace',
164
+ description: 'Index workspace files for semantic search. Run this before semantic_search if you want to search more files or specific directories.',
165
+ parameters: [
166
+ { name: 'glob', description: 'Glob pattern of files to index (default: "**/*.{ts,tsx,js,jsx,py}")' },
167
+ { name: 'max_files', description: 'Maximum number of files to index (default: 50)' }
168
+ ],
169
+ async execute(params, ctx) {
170
+ const glob = params.glob ?? '**/*.{ts,tsx,js,jsx,py}';
171
+ const maxFiles = Math.min(parseInt(params.max_files ?? '50', 10) || 50, 100);
172
+ try {
173
+ const files = await ctx.listFiles(glob);
174
+ const toIndex = files.slice(0, maxFiles);
175
+ let indexed = 0;
176
+ let skipped = 0;
177
+ for (const file of toIndex) {
178
+ if (indexedPaths.has(file)) {
179
+ skipped++;
180
+ continue;
181
+ }
182
+ try {
183
+ const absPath = file.startsWith('/') ||
184
+ file.startsWith('~') ||
185
+ /^[A-Za-z]:[\\/]/.test(file) ||
186
+ file.startsWith('\\\\')
187
+ ? file
188
+ : `${ctx.workspaceRoot}/${file}`;
189
+ const content = await ctx.readFile(absPath);
190
+ if (content.length > 0 && content.length < 50000) {
191
+ await indexFile(file, content);
192
+ indexed++;
193
+ }
194
+ }
195
+ catch {
196
+ // Skip unreadable files
197
+ }
198
+ }
199
+ return {
200
+ output: `Indexed ${indexed} files (${skipped} already indexed, ${store.length} total chunks). Semantic search is ready.`
201
+ };
202
+ }
203
+ catch (err) {
204
+ return {
205
+ output: `Indexing failed: ${err instanceof Error ? err.message : String(err)}`,
206
+ isError: true
207
+ };
208
+ }
209
+ }
210
+ };
211
+ exports.semanticSearchSkill = {
212
+ id: 'search/semantic',
213
+ name: 'Semantic Search',
214
+ version: '1.0.0',
215
+ description: 'Search codebase by meaning using local Ollama embeddings (nomic-embed-text). Finds conceptually related code.',
216
+ instructions: 'Use semantic_search when you need to find code by concept (e.g. "authentication logic", "data validation") rather than exact text. Use search_code for literal/regex matches. The index is built automatically on first search.',
217
+ activation: 'auto',
218
+ triggerPatterns: [
219
+ /\bfind.*related\b/i,
220
+ /\bwhere.*handle/i,
221
+ /\bhow.*implement/i,
222
+ /\bwhat.*does\b/i,
223
+ /\bunderstand\b/i,
224
+ /\barchitecture\b/i,
225
+ /\bexplain.*code\b/i,
226
+ /\bsemantic/i
227
+ ],
228
+ tools: [semanticSearchTool, indexWorkspaceTool]
229
+ };
230
+ /**
231
+ * Configure the Ollama base URL for the embedding client.
232
+ * Call this before the skill is used if Ollama is not on localhost.
233
+ */
234
+ function configureSemanticSearchOllamaUrl(url) {
235
+ ollamaBaseUrl = url.replace(/\/+$/, '');
236
+ }
237
+ /**
238
+ * Reset the in-memory index (e.g. on workspace change).
239
+ */
240
+ function resetSemanticIndex() {
241
+ store = [];
242
+ indexedPaths = new Set();
243
+ }
244
+ //# sourceMappingURL=semantic-search-skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-search-skill.js","sourceRoot":"","sources":["../../../src/tools/skills/semantic-search-skill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Test generation skill — auto-activated when the user mentions tests, specs, or coverage.
3
+ *
4
+ * Provides tools for discovering test frameworks and running test suites,
5
+ * giving the model the context it needs to generate or fix tests.
6
+ */
7
+ import type { SkillManifest } from '../skill-types';
8
+ export declare const testGenSkill: SkillManifest;
9
+ //# sourceMappingURL=test-gen-skill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-gen-skill.d.ts","sourceRoot":"","sources":["../../../src/tools/skills/test-gen-skill.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AA6GpD,eAAO,MAAM,YAAY,EAAE,aAS1B,CAAC"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /**
3
+ * Test generation skill — auto-activated when the user mentions tests, specs, or coverage.
4
+ *
5
+ * Provides tools for discovering test frameworks and running test suites,
6
+ * giving the model the context it needs to generate or fix tests.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.testGenSkill = void 0;
10
+ const runTestsTool = {
11
+ name: 'run_tests',
12
+ description: 'Run the project test suite and return results. Auto-detects the test runner (vitest, jest, mocha, pytest, cargo test).',
13
+ parameters: [
14
+ { name: 'filter', description: 'Optional test name or file pattern to filter (e.g. "auth", "src/utils/*.test.ts")' },
15
+ { name: 'runner', description: 'Override the test runner (e.g. "vitest", "jest", "pytest"). Auto-detected if omitted.' }
16
+ ],
17
+ async execute(params, ctx) {
18
+ const runner = params.runner?.trim();
19
+ let cmd;
20
+ let args;
21
+ if (runner) {
22
+ cmd = runner;
23
+ args = ['run'];
24
+ if (params.filter)
25
+ args.push(params.filter);
26
+ }
27
+ else {
28
+ // Auto-detect: check for common test runner config files
29
+ const detectors = [
30
+ { files: ['vitest.config.ts', 'vitest.config.js'], cmd: 'npx', args: ['vitest', 'run'] },
31
+ { files: ['jest.config.ts', 'jest.config.js', 'jest.config.mjs'], cmd: 'npx', args: ['jest'] },
32
+ { files: ['pytest.ini', 'pyproject.toml', 'setup.cfg'], cmd: 'python3', args: ['-m', 'pytest'] },
33
+ { files: ['Cargo.toml'], cmd: 'cargo', args: ['test'] },
34
+ ];
35
+ let detected = false;
36
+ for (const detector of detectors) {
37
+ for (const file of detector.files) {
38
+ try {
39
+ const files = await ctx.listFiles(file);
40
+ if (files.length > 0) {
41
+ cmd = detector.cmd;
42
+ args = [...detector.args];
43
+ if (params.filter)
44
+ args.push(params.filter);
45
+ detected = true;
46
+ break;
47
+ }
48
+ }
49
+ catch {
50
+ // file doesn't exist, try next
51
+ }
52
+ }
53
+ if (detected)
54
+ break;
55
+ }
56
+ if (!detected) {
57
+ // Fallback: try npx vitest run
58
+ cmd = 'npx';
59
+ args = ['vitest', 'run'];
60
+ if (params.filter)
61
+ args.push(params.filter);
62
+ }
63
+ }
64
+ try {
65
+ const result = await ctx.runCommand(cmd, args, ctx.workspaceRoot);
66
+ const combined = [
67
+ result.stdout.trim() ? result.stdout.trim() : '',
68
+ result.stderr.trim() ? `stderr:\n${result.stderr.trim()}` : '',
69
+ `exit code: ${result.exitCode}`
70
+ ].filter(Boolean).join('\n\n');
71
+ return {
72
+ output: combined.slice(0, 16000),
73
+ isError: result.exitCode !== 0
74
+ };
75
+ }
76
+ catch (err) {
77
+ return { output: `Error running tests: ${err instanceof Error ? err.message : String(err)}`, isError: true };
78
+ }
79
+ }
80
+ };
81
+ const listTestFilesTool = {
82
+ name: 'list_test_files',
83
+ description: 'Find all test files in the workspace. Searches for common test file patterns (*.test.ts, *.spec.ts, test_*.py, *_test.go).',
84
+ parameters: [
85
+ { name: 'cwd', description: 'Subdirectory to search in (optional, defaults to whole workspace)' }
86
+ ],
87
+ async execute(params, ctx) {
88
+ const patterns = [
89
+ '**/*.test.ts', '**/*.test.tsx', '**/*.test.js', '**/*.test.jsx',
90
+ '**/*.spec.ts', '**/*.spec.tsx', '**/*.spec.js', '**/*.spec.jsx',
91
+ '**/test_*.py', '**/*_test.py', '**/*_test.go',
92
+ ];
93
+ const allFiles = [];
94
+ const cwd = params.cwd
95
+ ? `${ctx.workspaceRoot}/${params.cwd}`
96
+ : ctx.workspaceRoot;
97
+ for (const pattern of patterns) {
98
+ try {
99
+ const files = await ctx.listFiles(pattern, cwd);
100
+ allFiles.push(...files);
101
+ }
102
+ catch {
103
+ // pattern matched nothing
104
+ }
105
+ }
106
+ const unique = [...new Set(allFiles)].sort();
107
+ if (unique.length === 0) {
108
+ return { output: 'No test files found.' };
109
+ }
110
+ return { output: `${unique.length} test file(s) found:\n\n${unique.join('\n')}` };
111
+ }
112
+ };
113
+ exports.testGenSkill = {
114
+ id: 'testing/test-gen',
115
+ name: 'Testing',
116
+ version: '1.0.0',
117
+ description: 'Run tests, find test files, and assist with test generation.',
118
+ instructions: 'When writing tests, first use list_test_files to understand existing test patterns. Use run_tests to verify your changes. Match the existing test style and framework.',
119
+ activation: 'auto',
120
+ triggerPatterns: [/\btest/i, /\bspec\b/i, /\bcoverage\b/i, /\bunit\s+test/i],
121
+ tools: [runTestsTool, listTestFilesTool]
122
+ };
123
+ //# sourceMappingURL=test-gen-skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-gen-skill.js","sourceRoot":"","sources":["../../../src/tools/skills/test-gen-skill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { AgentTool } from './tool-types';
2
+ /**
3
+ * Registry of available agent tools.
4
+ *
5
+ * Builds XML-format tool definitions for text-based tool calling,
6
+ * usable with models that don't support native function calling
7
+ * (gemma3, bandit-core, most 7-27B models).
8
+ */
9
+ export declare class ToolRegistry {
10
+ private readonly tools;
11
+ register(tool: AgentTool): this;
12
+ registerAll(tools: AgentTool[]): this;
13
+ get(name: string): AgentTool | undefined;
14
+ getAll(): AgentTool[];
15
+ has(name: string): boolean;
16
+ get size(): number;
17
+ /**
18
+ * Builds the tool definitions block injected into the system prompt.
19
+ *
20
+ * Format used for text-based tool calling (XML, compatible with Gemma3/bandit-core):
21
+ *
22
+ * You have access to these tools:
23
+ * <tool name="read_file">
24
+ * <description>...</description>
25
+ * <param name="path" required="true">...</param>
26
+ * </tool>
27
+ * ...
28
+ * To use a tool, respond with ONLY:
29
+ * <tool_call>{"name": "tool_name", "params": {"key": "value"}}</tool_call>
30
+ *
31
+ * When you have finished using tools and have a final answer, respond normally.
32
+ */
33
+ buildSystemPromptBlock(): string;
34
+ /**
35
+ * Builds tool definitions in JSON schema format for models with native tool calling.
36
+ * Compatible with Ollama's `tools: [...]` field.
37
+ *
38
+ * Parameter types: each AgentToolParameter may carry an optional
39
+ * `schema` field that holds JSON-Schema type info. When present we
40
+ * render the full shape (objects with properties, arrays with item
41
+ * types, enums) so the provider tells the model "this param is an
42
+ * object with these fields" instead of the legacy "every param is a
43
+ * string" flattening. Tools without `schema` default to `type: string`
44
+ * — matches every in-tree tool today and keeps the contract for
45
+ * adapter-less consumers.
46
+ */
47
+ buildNativeToolsSchema(): Array<{
48
+ type: 'function';
49
+ function: {
50
+ name: string;
51
+ description: string;
52
+ parameters: {
53
+ type: 'object';
54
+ properties: Record<string, Record<string, unknown>>;
55
+ required: string[];
56
+ };
57
+ };
58
+ }>;
59
+ }
60
+ //# sourceMappingURL=tool-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-registry.d.ts","sourceRoot":"","sources":["../../src/tools/tool-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAgD,MAAM,cAAc,CAAC;AAE5F;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IAEtD,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAK/B,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI;IAOrC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIxC,MAAM,IAAI,SAAS,EAAE;IAIrB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;;;;;;;;;;;OAeG;IACH,sBAAsB,IAAI,MAAM;IAyChC;;;;;;;;;;;;OAYG;IACH,sBAAsB,IAAI,KAAK,CAAC;QAC9B,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE;gBACV,IAAI,EAAE,QAAQ,CAAC;gBACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;gBACpD,QAAQ,EAAE,MAAM,EAAE,CAAC;aACpB,CAAC;SACH,CAAC;KACH,CAAC;CAgBH"}
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ToolRegistry = void 0;
4
+ /**
5
+ * Registry of available agent tools.
6
+ *
7
+ * Builds XML-format tool definitions for text-based tool calling,
8
+ * usable with models that don't support native function calling
9
+ * (gemma3, bandit-core, most 7-27B models).
10
+ */
11
+ class ToolRegistry {
12
+ constructor() {
13
+ this.tools = new Map();
14
+ }
15
+ register(tool) {
16
+ this.tools.set(tool.name, tool);
17
+ return this;
18
+ }
19
+ registerAll(tools) {
20
+ for (const tool of tools) {
21
+ this.register(tool);
22
+ }
23
+ return this;
24
+ }
25
+ get(name) {
26
+ return this.tools.get(name);
27
+ }
28
+ getAll() {
29
+ return [...this.tools.values()];
30
+ }
31
+ has(name) {
32
+ return this.tools.has(name);
33
+ }
34
+ get size() {
35
+ return this.tools.size;
36
+ }
37
+ /**
38
+ * Builds the tool definitions block injected into the system prompt.
39
+ *
40
+ * Format used for text-based tool calling (XML, compatible with Gemma3/bandit-core):
41
+ *
42
+ * You have access to these tools:
43
+ * <tool name="read_file">
44
+ * <description>...</description>
45
+ * <param name="path" required="true">...</param>
46
+ * </tool>
47
+ * ...
48
+ * To use a tool, respond with ONLY:
49
+ * <tool_call>{"name": "tool_name", "params": {"key": "value"}}</tool_call>
50
+ *
51
+ * When you have finished using tools and have a final answer, respond normally.
52
+ */
53
+ buildSystemPromptBlock() {
54
+ if (this.tools.size === 0)
55
+ return '';
56
+ const toolDefs = this.getAll().map(tool => {
57
+ const params = tool.parameters.map(p => {
58
+ // Surface the JSON-Schema-derived type hint inline in the
59
+ // description so the model knows when to emit a nested object
60
+ // or an array instead of a bare string. Without this hint the
61
+ // XML-prompt format describes every param as opaque text,
62
+ // which is what produced the "Expected object, received
63
+ // string" failures on createFilter / modifyMessageLabels.
64
+ const typeHint = formatParamTypeHint(p.schema);
65
+ const desc = typeHint ? `${typeHint} ${p.description}` : p.description;
66
+ return ` <param name="${p.name}"${p.required ? ' required="true"' : ''}>${desc}</param>`;
67
+ }).join('\n');
68
+ return [
69
+ `<tool name="${tool.name}">`,
70
+ ` <description>${tool.description}</description>`,
71
+ params,
72
+ `</tool>`
73
+ ].join('\n');
74
+ }).join('\n\n');
75
+ return [
76
+ '## Available Tools',
77
+ '',
78
+ 'You have access to the following tools to help you complete tasks:',
79
+ '',
80
+ toolDefs,
81
+ '',
82
+ '## How to Use Tools',
83
+ '',
84
+ 'To call a tool, respond with ONLY a tool call on its own line:',
85
+ '<tool_call>{"name": "tool_name", "params": {"param1": "value1"}}</tool_call>',
86
+ '',
87
+ 'Wait for the tool result before continuing.',
88
+ 'When you have all the information needed and are ready to give your final response,',
89
+ 'respond normally without any <tool_call> tags.',
90
+ ].join('\n');
91
+ }
92
+ /**
93
+ * Builds tool definitions in JSON schema format for models with native tool calling.
94
+ * Compatible with Ollama's `tools: [...]` field.
95
+ *
96
+ * Parameter types: each AgentToolParameter may carry an optional
97
+ * `schema` field that holds JSON-Schema type info. When present we
98
+ * render the full shape (objects with properties, arrays with item
99
+ * types, enums) so the provider tells the model "this param is an
100
+ * object with these fields" instead of the legacy "every param is a
101
+ * string" flattening. Tools without `schema` default to `type: string`
102
+ * — matches every in-tree tool today and keeps the contract for
103
+ * adapter-less consumers.
104
+ */
105
+ buildNativeToolsSchema() {
106
+ return this.getAll().map(tool => ({
107
+ type: 'function',
108
+ function: {
109
+ name: tool.name,
110
+ description: tool.description,
111
+ parameters: {
112
+ type: 'object',
113
+ properties: Object.fromEntries(tool.parameters.map(p => [p.name, renderParamForNativeSchema(p)])),
114
+ required: tool.parameters.filter(p => p.required).map(p => p.name)
115
+ }
116
+ }
117
+ }));
118
+ }
119
+ }
120
+ exports.ToolRegistry = ToolRegistry;
121
+ /**
122
+ * Translate an AgentToolParameter to the JSON-Schema-shaped fragment
123
+ * Ollama (and other OpenAI-compatible native-tools providers) want in
124
+ * the `parameters.properties[<name>]` slot. When the param carries a
125
+ * `schema` field, expand it into a real typed declaration; otherwise
126
+ * fall back to the legacy `{ type: "string", description }` shape so
127
+ * existing in-tree tools render identically.
128
+ *
129
+ * Recursive: nested object properties and array item shapes are
130
+ * expanded the same way, so a `createFilter` param with `criteria:
131
+ * { type: object, properties: { from, to, subject, query, ... } }`
132
+ * renders correctly all the way through.
133
+ */
134
+ function renderParamForNativeSchema(p) {
135
+ const baseDescription = p.description;
136
+ if (!p.schema) {
137
+ return { type: 'string', description: baseDescription };
138
+ }
139
+ const rendered = renderSchemaFragment(p.schema);
140
+ // Top-level description from the AgentToolParameter wins so the
141
+ // agent sees the rich human-readable description we wrote at the
142
+ // tool definition (which often summarizes the whole param), not
143
+ // a nested per-property blurb.
144
+ rendered.description = baseDescription;
145
+ return rendered;
146
+ }
147
+ /**
148
+ * Build a short inline hint like "(object: {from, to, subject})" or
149
+ * "(array of string)" that prefixes the param description in the
150
+ * non-native system prompt block. Without a hint the model treats
151
+ * every param as opaque text. With it the model knows which params
152
+ * need JSON-encoded objects/arrays vs bare strings — which is the
153
+ * difference between createFilter working and Google rejecting the
154
+ * request with "Expected object, received string."
155
+ */
156
+ function formatParamTypeHint(schema) {
157
+ if (!schema || !schema.type || schema.type === 'string')
158
+ return '';
159
+ if (schema.type === 'object') {
160
+ const keys = schema.properties ? Object.keys(schema.properties).slice(0, 6) : [];
161
+ const more = schema.properties && Object.keys(schema.properties).length > 6 ? ', …' : '';
162
+ return keys.length > 0
163
+ ? `(object — pass JSON like {"${keys.join('": …, "')}": …}${more})`
164
+ : '(object — pass a JSON object)';
165
+ }
166
+ if (schema.type === 'array') {
167
+ const itemType = schema.items?.type ?? 'value';
168
+ return `(array of ${itemType} — pass JSON like ["..."])`;
169
+ }
170
+ if (schema.type === 'integer' || schema.type === 'number') {
171
+ return `(${schema.type})`;
172
+ }
173
+ if (schema.type === 'boolean') {
174
+ return '(boolean — true or false)';
175
+ }
176
+ return `(${schema.type})`;
177
+ }
178
+ function renderSchemaFragment(s) {
179
+ const out = {};
180
+ if (s.type)
181
+ out.type = s.type;
182
+ if (s.description)
183
+ out.description = s.description;
184
+ if (s.enum)
185
+ out.enum = s.enum;
186
+ if (s.type === 'object' && s.properties) {
187
+ out.properties = Object.fromEntries(Object.entries(s.properties).map(([k, v]) => [k, renderSchemaFragment(v)]));
188
+ if (s.required && s.required.length > 0) {
189
+ out.required = s.required;
190
+ }
191
+ // Defaulting additionalProperties:false here would be safer but
192
+ // some MCP servers depend on extra fields passing through; leave
193
+ // unset so the provider doesn't reject valid calls.
194
+ }
195
+ else if (s.type === 'array' && s.items) {
196
+ out.items = renderSchemaFragment(s.items);
197
+ }
198
+ return out;
199
+ }
200
+ //# sourceMappingURL=tool-registry.js.map