@hubblecommerce/overmind-core 0.1.4 → 0.1.6
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/dist/src/integrations/confluence/confluence.client.test.d.ts +2 -0
- package/dist/src/integrations/confluence/confluence.client.test.d.ts.map +1 -0
- package/dist/src/integrations/confluence/confluence.client.test.js +320 -0
- package/dist/src/integrations/gitlab/gitlab.client.d.ts +8 -0
- package/dist/src/integrations/gitlab/gitlab.client.d.ts.map +1 -1
- package/dist/src/integrations/gitlab/gitlab.client.js +20 -0
- package/dist/src/integrations/gitlab/gitlab.client.test.d.ts +2 -0
- package/dist/src/integrations/gitlab/gitlab.client.test.d.ts.map +1 -0
- package/dist/src/integrations/gitlab/gitlab.client.test.js +62 -0
- package/dist/src/integrations/jira/jira.client.test.d.ts +2 -0
- package/dist/src/integrations/jira/jira.client.test.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira.client.test.js +171 -0
- package/dist/src/llm/anthropic-retry-wrapper.test.d.ts +2 -0
- package/dist/src/llm/anthropic-retry-wrapper.test.d.ts.map +1 -0
- package/dist/src/llm/anthropic-retry-wrapper.test.js +125 -0
- package/dist/src/processors/confluence-document.processor.test.d.ts +2 -0
- package/dist/src/processors/confluence-document.processor.test.d.ts.map +1 -0
- package/dist/src/processors/confluence-document.processor.test.js +202 -0
- package/dist/src/processors/confluence-html-parser.test.d.ts +2 -0
- package/dist/src/processors/confluence-html-parser.test.d.ts.map +1 -0
- package/dist/src/processors/confluence-html-parser.test.js +214 -0
- package/dist/src/tools/confluence-search.tool.d.ts +6 -6
- package/dist/src/utils/repomix-search.d.ts +31 -0
- package/dist/src/utils/repomix-search.d.ts.map +1 -0
- package/dist/src/utils/repomix-search.js +80 -0
- package/dist/src/utils/repomix-search.test.d.ts +2 -0
- package/dist/src/utils/repomix-search.test.d.ts.map +1 -0
- package/dist/src/utils/repomix-search.test.js +75 -0
- package/package.json +11 -2
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repomix search utilities — pure string/regex operations, no filesystem dependency.
|
|
3
|
+
* Core search logic adapted from repomix (https://github.com/yamadashy/repomix)
|
|
4
|
+
* src/mcp/tools/grepRepomixOutputTool.ts
|
|
5
|
+
*/
|
|
6
|
+
// --- Core search functions (from repomix) ---
|
|
7
|
+
function createRegexPattern(pattern, ignoreCase) {
|
|
8
|
+
const flags = ignoreCase ? 'gi' : 'g';
|
|
9
|
+
try {
|
|
10
|
+
return new RegExp(pattern, flags);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
throw new Error(`Invalid regular expression pattern: ${pattern}. ${error instanceof Error ? error.message : String(error)}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function searchInLines(lines, pattern, ignoreCase) {
|
|
17
|
+
const regex = createRegexPattern(pattern, ignoreCase);
|
|
18
|
+
const matches = [];
|
|
19
|
+
for (let i = 0; i < lines.length; i++) {
|
|
20
|
+
const line = lines[i];
|
|
21
|
+
const match = line.match(regex);
|
|
22
|
+
if (match) {
|
|
23
|
+
matches.push({
|
|
24
|
+
lineNumber: i + 1,
|
|
25
|
+
line,
|
|
26
|
+
matchedText: match[0],
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return matches;
|
|
31
|
+
}
|
|
32
|
+
function formatSearchResults(lines, matches, beforeLines, afterLines) {
|
|
33
|
+
if (matches.length === 0) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const resultLines = [];
|
|
37
|
+
const addedLines = new Set();
|
|
38
|
+
for (const match of matches) {
|
|
39
|
+
const start = Math.max(0, match.lineNumber - 1 - beforeLines);
|
|
40
|
+
const end = Math.min(lines.length - 1, match.lineNumber - 1 + afterLines);
|
|
41
|
+
if (resultLines.length > 0 && start > Math.min(...addedLines) + 1) {
|
|
42
|
+
resultLines.push('--');
|
|
43
|
+
}
|
|
44
|
+
for (let i = start; i <= end; i++) {
|
|
45
|
+
if (!addedLines.has(i)) {
|
|
46
|
+
const lineNum = i + 1;
|
|
47
|
+
const prefix = i === match.lineNumber - 1 ? `${lineNum}:` : `${lineNum}-`;
|
|
48
|
+
resultLines.push(`${prefix}${lines[i]}`);
|
|
49
|
+
addedLines.add(i);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return resultLines;
|
|
54
|
+
}
|
|
55
|
+
// --- Public API ---
|
|
56
|
+
/**
|
|
57
|
+
* Search a repomix XML string for lines matching a pattern.
|
|
58
|
+
* Returns matching lines with optional context.
|
|
59
|
+
*/
|
|
60
|
+
export function searchRepomix(xml, pattern, options) {
|
|
61
|
+
const ignoreCase = options?.ignoreCase ?? false;
|
|
62
|
+
const contextLines = options?.contextLines ?? 0;
|
|
63
|
+
const lines = xml.split('\n');
|
|
64
|
+
const matches = searchInLines(lines, pattern, ignoreCase);
|
|
65
|
+
const formattedOutput = formatSearchResults(lines, matches, contextLines, contextLines);
|
|
66
|
+
return { matches, formattedOutput };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Extract the content of a specific file block from repomix XML.
|
|
70
|
+
* Looks for `<file path="filePath">...</file>` and returns the inner content.
|
|
71
|
+
* Returns null if the file is not found.
|
|
72
|
+
*/
|
|
73
|
+
export function getRepomixFile(xml, filePath) {
|
|
74
|
+
const escapedPath = filePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
75
|
+
const regex = new RegExp(`<file\\s+path="${escapedPath}"[^>]*>\\n?([\\s\\S]*?)\\n?</file>`, 'm');
|
|
76
|
+
const match = xml.match(regex);
|
|
77
|
+
if (!match?.[1])
|
|
78
|
+
return null;
|
|
79
|
+
return match[1];
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repomix-search.test.d.ts","sourceRoot":"","sources":["../../../src/utils/repomix-search.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { searchRepomix, getRepomixFile } from './repomix-search.js';
|
|
3
|
+
const SAMPLE_XML = `<file path="src/index.ts">
|
|
4
|
+
import { App } from './app';
|
|
5
|
+
|
|
6
|
+
const app = new App();
|
|
7
|
+
app.start();
|
|
8
|
+
</file>
|
|
9
|
+
|
|
10
|
+
<file path="README.md">
|
|
11
|
+
# My Project
|
|
12
|
+
|
|
13
|
+
This is a sample project with authentication.
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
Run \`npm install\` to get started.
|
|
18
|
+
</file>
|
|
19
|
+
|
|
20
|
+
<file path="src/auth/login.ts">
|
|
21
|
+
export function login(username: string, password: string) {
|
|
22
|
+
return fetch('/api/auth/login', {
|
|
23
|
+
method: 'POST',
|
|
24
|
+
body: JSON.stringify({ username, password }),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
</file>`;
|
|
28
|
+
describe('searchRepomix', () => {
|
|
29
|
+
it('returns matching lines with file context', () => {
|
|
30
|
+
const results = searchRepomix(SAMPLE_XML, 'auth');
|
|
31
|
+
expect(results.matches.length).toBeGreaterThan(0);
|
|
32
|
+
expect(results.matches.some(m => m.line.includes('auth'))).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
it('returns empty matches for non-existent pattern', () => {
|
|
35
|
+
const results = searchRepomix(SAMPLE_XML, 'nonexistent_xyz_pattern');
|
|
36
|
+
expect(results.matches).toHaveLength(0);
|
|
37
|
+
});
|
|
38
|
+
it('supports case-insensitive search', () => {
|
|
39
|
+
const results = searchRepomix(SAMPLE_XML, 'APP', { ignoreCase: true });
|
|
40
|
+
expect(results.matches.length).toBeGreaterThan(0);
|
|
41
|
+
});
|
|
42
|
+
it('is case-sensitive by default', () => {
|
|
43
|
+
const results = searchRepomix(SAMPLE_XML, 'APP');
|
|
44
|
+
expect(results.matches).toHaveLength(0);
|
|
45
|
+
});
|
|
46
|
+
it('supports context lines', () => {
|
|
47
|
+
const results = searchRepomix(SAMPLE_XML, 'login', { contextLines: 1 });
|
|
48
|
+
expect(results.formattedOutput.length).toBeGreaterThan(results.matches.length);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('getRepomixFile', () => {
|
|
52
|
+
it('extracts file content by path', () => {
|
|
53
|
+
const content = getRepomixFile(SAMPLE_XML, 'README.md');
|
|
54
|
+
expect(content).not.toBeNull();
|
|
55
|
+
expect(content).toContain('# My Project');
|
|
56
|
+
expect(content).toContain('npm install');
|
|
57
|
+
});
|
|
58
|
+
it('returns null for non-existent file path', () => {
|
|
59
|
+
const content = getRepomixFile(SAMPLE_XML, 'nonexistent.ts');
|
|
60
|
+
expect(content).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
it('extracts the correct file when multiple files exist', () => {
|
|
63
|
+
const content = getRepomixFile(SAMPLE_XML, 'src/auth/login.ts');
|
|
64
|
+
expect(content).not.toBeNull();
|
|
65
|
+
expect(content).toContain('export function login');
|
|
66
|
+
expect(content).not.toContain('# My Project');
|
|
67
|
+
});
|
|
68
|
+
it('returns the content without the file tags', () => {
|
|
69
|
+
const content = getRepomixFile(SAMPLE_XML, 'src/index.ts');
|
|
70
|
+
expect(content).not.toBeNull();
|
|
71
|
+
expect(content).not.toContain('<file');
|
|
72
|
+
expect(content).not.toContain('</file>');
|
|
73
|
+
expect(content).toContain("import { App }");
|
|
74
|
+
});
|
|
75
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubblecommerce/overmind-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared infrastructure package for the Overmind AI agent system",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"./tools/get-current-date": {
|
|
50
50
|
"types": "./dist/src/tools/get-current-date.tool.d.ts",
|
|
51
51
|
"default": "./dist/src/tools/get-current-date.tool.js"
|
|
52
|
+
},
|
|
53
|
+
"./utils/repomix-search": {
|
|
54
|
+
"types": "./dist/src/utils/repomix-search.d.ts",
|
|
55
|
+
"default": "./dist/src/utils/repomix-search.js"
|
|
52
56
|
}
|
|
53
57
|
},
|
|
54
58
|
"files": [
|
|
@@ -67,6 +71,9 @@
|
|
|
67
71
|
"zod": "^3.25.76"
|
|
68
72
|
},
|
|
69
73
|
"scripts": {
|
|
74
|
+
"test": "vitest run",
|
|
75
|
+
"test:watch": "vitest",
|
|
76
|
+
"test:coverage": "vitest run --coverage",
|
|
70
77
|
"build": "tsc",
|
|
71
78
|
"prepack": "npm run build",
|
|
72
79
|
"typecheck": "tsc --noEmit",
|
|
@@ -84,12 +91,14 @@
|
|
|
84
91
|
"@types/node": "^24.6.1",
|
|
85
92
|
"@types/pg": "^8.15.5",
|
|
86
93
|
"@types/turndown": "^5.0.5",
|
|
94
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
87
95
|
"eslint": "^9.36.0",
|
|
88
96
|
"husky": "^9.0.0",
|
|
89
97
|
"lint-staged": "^15.0.0",
|
|
90
98
|
"tsx": "^4.20.6",
|
|
91
99
|
"typescript": "^5.9.3",
|
|
92
|
-
"typescript-eslint": "^8.45.0"
|
|
100
|
+
"typescript-eslint": "^8.45.0",
|
|
101
|
+
"vitest": "^4.1.2"
|
|
93
102
|
},
|
|
94
103
|
"lint-staged": {
|
|
95
104
|
"*.ts": "eslint --fix"
|