@sylphx/flow 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/commands/hook-command.ts +10 -230
- package/src/composables/index.ts +0 -1
- package/src/config/servers.ts +35 -78
- package/src/core/interfaces.ts +0 -33
- package/src/domains/index.ts +0 -2
- package/src/index.ts +0 -4
- package/src/services/mcp-service.ts +0 -16
- package/src/targets/claude-code.ts +3 -9
- package/src/targets/functional/claude-code-logic.ts +4 -22
- package/src/targets/opencode.ts +0 -6
- package/src/types/mcp.types.ts +29 -38
- package/src/types/target.types.ts +0 -2
- package/src/types.ts +0 -1
- package/src/commands/codebase-command.ts +0 -168
- package/src/commands/knowledge-command.ts +0 -161
- package/src/composables/useTargetConfig.ts +0 -45
- package/src/core/formatting/bytes.test.ts +0 -115
- package/src/core/validation/limit.test.ts +0 -155
- package/src/core/validation/query.test.ts +0 -44
- package/src/domains/codebase/index.ts +0 -5
- package/src/domains/codebase/tools.ts +0 -139
- package/src/domains/knowledge/index.ts +0 -10
- package/src/domains/knowledge/resources.ts +0 -537
- package/src/domains/knowledge/tools.ts +0 -174
- package/src/services/search/base-indexer.ts +0 -156
- package/src/services/search/codebase-indexer-types.ts +0 -38
- package/src/services/search/codebase-indexer.ts +0 -647
- package/src/services/search/embeddings-provider.ts +0 -455
- package/src/services/search/embeddings.ts +0 -316
- package/src/services/search/functional-indexer.ts +0 -323
- package/src/services/search/index.ts +0 -27
- package/src/services/search/indexer.ts +0 -380
- package/src/services/search/knowledge-indexer.ts +0 -422
- package/src/services/search/semantic-search.ts +0 -244
- package/src/services/search/tfidf.ts +0 -559
- package/src/services/search/unified-search-service.ts +0 -888
- package/src/services/storage/cache-storage.ts +0 -487
- package/src/services/storage/drizzle-storage.ts +0 -581
- package/src/services/storage/index.ts +0 -15
- package/src/services/storage/lancedb-vector-storage.ts +0 -494
- package/src/services/storage/memory-storage.ts +0 -268
- package/src/services/storage/separated-storage.ts +0 -467
- package/src/services/storage/vector-storage.ts +0 -13
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Limit Validation Utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, expect, it } from 'bun:test';
|
|
6
|
-
import { validateLimit } from './limit.js';
|
|
7
|
-
|
|
8
|
-
describe('validateLimit', () => {
|
|
9
|
-
describe('with default parameters (defaultLimit=50, maxLimit=1000)', () => {
|
|
10
|
-
it('returns default limit when undefined', () => {
|
|
11
|
-
const result = validateLimit(undefined);
|
|
12
|
-
expect(result._tag).toBe('Success');
|
|
13
|
-
expect(result._tag === 'Success' && result.value).toBe(50);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('accepts valid number', () => {
|
|
17
|
-
const result = validateLimit(100);
|
|
18
|
-
expect(result._tag).toBe('Success');
|
|
19
|
-
expect(result._tag === 'Success' && result.value).toBe(100);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('accepts valid string number', () => {
|
|
23
|
-
const result = validateLimit('500');
|
|
24
|
-
expect(result._tag).toBe('Success');
|
|
25
|
-
expect(result._tag === 'Success' && result.value).toBe(500);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('accepts limit at max', () => {
|
|
29
|
-
const result = validateLimit(1000);
|
|
30
|
-
expect(result._tag).toBe('Success');
|
|
31
|
-
expect(result._tag === 'Success' && result.value).toBe(1000);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('rejects limit above max', () => {
|
|
35
|
-
const result = validateLimit(1001);
|
|
36
|
-
expect(result._tag).toBe('Failure');
|
|
37
|
-
expect(result._tag === 'Failure' && result.error.message).toBe('Limit cannot exceed 1000');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('rejects zero', () => {
|
|
41
|
-
const result = validateLimit(0);
|
|
42
|
-
expect(result._tag).toBe('Failure');
|
|
43
|
-
expect(result._tag === 'Failure' && result.error.message).toBe(
|
|
44
|
-
'Limit must be a positive number'
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('rejects negative number', () => {
|
|
49
|
-
const result = validateLimit(-10);
|
|
50
|
-
expect(result._tag).toBe('Failure');
|
|
51
|
-
expect(result._tag === 'Failure' && result.error.message).toBe(
|
|
52
|
-
'Limit must be a positive number'
|
|
53
|
-
);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('rejects invalid string', () => {
|
|
57
|
-
const result = validateLimit('invalid');
|
|
58
|
-
expect(result._tag).toBe('Failure');
|
|
59
|
-
expect(result._tag === 'Failure' && result.error.message).toBe(
|
|
60
|
-
'Limit must be a positive number'
|
|
61
|
-
);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('rejects empty string', () => {
|
|
65
|
-
const result = validateLimit('');
|
|
66
|
-
expect(result._tag).toBe('Failure');
|
|
67
|
-
expect(result._tag === 'Failure' && result.error.message).toBe(
|
|
68
|
-
'Limit must be a positive number'
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('with custom default (defaultLimit=10)', () => {
|
|
74
|
-
it('returns custom default when undefined', () => {
|
|
75
|
-
const result = validateLimit(undefined, 10);
|
|
76
|
-
expect(result._tag).toBe('Success');
|
|
77
|
-
expect(result._tag === 'Success' && result.value).toBe(10);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
describe('with custom max (maxLimit=100)', () => {
|
|
82
|
-
it('accepts limit at custom max', () => {
|
|
83
|
-
const result = validateLimit(100, 10, 100);
|
|
84
|
-
expect(result._tag).toBe('Success');
|
|
85
|
-
expect(result._tag === 'Success' && result.value).toBe(100);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('rejects limit above custom max', () => {
|
|
89
|
-
const result = validateLimit(101, 10, 100);
|
|
90
|
-
expect(result._tag).toBe('Failure');
|
|
91
|
-
expect(result._tag === 'Failure' && result.error.message).toBe('Limit cannot exceed 100');
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('knowledge feature defaults (defaultLimit=10, maxLimit=100)', () => {
|
|
96
|
-
it('returns 10 when undefined', () => {
|
|
97
|
-
const result = validateLimit(undefined, 10, 100);
|
|
98
|
-
expect(result._tag).toBe('Success');
|
|
99
|
-
expect(result._tag === 'Success' && result.value).toBe(10);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('accepts 50', () => {
|
|
103
|
-
const result = validateLimit(50, 10, 100);
|
|
104
|
-
expect(result._tag).toBe('Success');
|
|
105
|
-
expect(result._tag === 'Success' && result.value).toBe(50);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('rejects 101', () => {
|
|
109
|
-
const result = validateLimit(101, 10, 100);
|
|
110
|
-
expect(result._tag).toBe('Failure');
|
|
111
|
-
expect(result._tag === 'Failure' && result.error.message).toBe('Limit cannot exceed 100');
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
describe('memory feature defaults (defaultLimit=50, maxLimit=1000)', () => {
|
|
116
|
-
it('returns 50 when undefined', () => {
|
|
117
|
-
const result = validateLimit(undefined, 50, 1000);
|
|
118
|
-
expect(result._tag).toBe('Success');
|
|
119
|
-
expect(result._tag === 'Success' && result.value).toBe(50);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('accepts 500', () => {
|
|
123
|
-
const result = validateLimit(500, 50, 1000);
|
|
124
|
-
expect(result._tag).toBe('Success');
|
|
125
|
-
expect(result._tag === 'Success' && result.value).toBe(500);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('rejects 1001', () => {
|
|
129
|
-
const result = validateLimit(1001, 50, 1000);
|
|
130
|
-
expect(result._tag).toBe('Failure');
|
|
131
|
-
expect(result._tag === 'Failure' && result.error.message).toBe('Limit cannot exceed 1000');
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe('edge cases', () => {
|
|
136
|
-
it('accepts 1 (minimum valid)', () => {
|
|
137
|
-
const result = validateLimit(1);
|
|
138
|
-
expect(result._tag).toBe('Success');
|
|
139
|
-
expect(result._tag === 'Success' && result.value).toBe(1);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('handles string with whitespace', () => {
|
|
143
|
-
const result = validateLimit(' 100 ');
|
|
144
|
-
expect(result._tag).toBe('Success');
|
|
145
|
-
expect(result._tag === 'Success' && result.value).toBe(100);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
it('rejects decimal numbers', () => {
|
|
149
|
-
const result = validateLimit('10.5');
|
|
150
|
-
expect(result._tag).toBe('Success');
|
|
151
|
-
// parseInt truncates to 10
|
|
152
|
-
expect(result._tag === 'Success' && result.value).toBe(10);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Query Validation Utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, expect, it } from 'bun:test';
|
|
6
|
-
import { normalizeQuery } from './query.js';
|
|
7
|
-
|
|
8
|
-
describe('normalizeQuery', () => {
|
|
9
|
-
it('trims leading whitespace', () => {
|
|
10
|
-
expect(normalizeQuery(' hello')).toBe('hello');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('trims trailing whitespace', () => {
|
|
14
|
-
expect(normalizeQuery('hello ')).toBe('hello');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('trims both leading and trailing whitespace', () => {
|
|
18
|
-
expect(normalizeQuery(' hello ')).toBe('hello');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('preserves internal whitespace', () => {
|
|
22
|
-
expect(normalizeQuery('hello world')).toBe('hello world');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('handles empty string', () => {
|
|
26
|
-
expect(normalizeQuery('')).toBe('');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('handles string with only whitespace', () => {
|
|
30
|
-
expect(normalizeQuery(' ')).toBe('');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('handles tabs and newlines', () => {
|
|
34
|
-
expect(normalizeQuery('\t\nhello\t\n')).toBe('hello');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('handles already trimmed string', () => {
|
|
38
|
-
expect(normalizeQuery('hello')).toBe('hello');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('handles multi-line queries', () => {
|
|
42
|
-
expect(normalizeQuery(' line1\nline2 ')).toBe('line1\nline2');
|
|
43
|
-
});
|
|
44
|
-
});
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Codebase tools
|
|
3
|
-
* All tools for working with project source code and files
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
-
import { z } from 'zod';
|
|
8
|
-
import { getSearchService } from '../../services/search/unified-search-service.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Register codebase search tool
|
|
12
|
-
*/
|
|
13
|
-
export function registerCodebaseSearchTool(server: McpServer): void {
|
|
14
|
-
server.registerTool(
|
|
15
|
-
'codebase_search',
|
|
16
|
-
{
|
|
17
|
-
description: `Search project source files, documentation, and code. Use this to find implementations, functions, classes, or any code-related content.
|
|
18
|
-
|
|
19
|
-
**IMPORTANT: Use this tool PROACTIVELY before starting work, not reactively when stuck.**
|
|
20
|
-
|
|
21
|
-
This tool searches across all codebase files and returns the most relevant matches with content snippets.
|
|
22
|
-
|
|
23
|
-
When to use this tool (BEFORE starting work):
|
|
24
|
-
- **Before implementation**: Find existing patterns, similar functions, or reusable components
|
|
25
|
-
- **Before refactoring**: Understand current implementation and dependencies
|
|
26
|
-
- **Before adding features**: Check for existing similar functionality or conflicting code
|
|
27
|
-
- **Before debugging**: Search for error messages, function names, or related code
|
|
28
|
-
- **Before writing tests**: Find existing test patterns and test utilities
|
|
29
|
-
|
|
30
|
-
The search includes:
|
|
31
|
-
- Source code files (.ts, .js, .tsx, .jsx, etc.)
|
|
32
|
-
- Configuration files (.json, .yaml, .toml, etc.)
|
|
33
|
-
- Documentation files (.md, .txt, etc.)
|
|
34
|
-
- Build and deployment files
|
|
35
|
-
|
|
36
|
-
**Best Practice**: Search the codebase BEFORE writing new code to avoid duplication and follow existing patterns.`,
|
|
37
|
-
inputSchema: {
|
|
38
|
-
query: z
|
|
39
|
-
.string()
|
|
40
|
-
.describe('Search query - use natural language, function names, or technical terms'),
|
|
41
|
-
limit: z
|
|
42
|
-
.number()
|
|
43
|
-
.default(10)
|
|
44
|
-
.optional()
|
|
45
|
-
.describe('Maximum number of results to return (default: 10)'),
|
|
46
|
-
include_content: z
|
|
47
|
-
.boolean()
|
|
48
|
-
.default(true)
|
|
49
|
-
.optional()
|
|
50
|
-
.describe('Include file content snippets in results (default: true)'),
|
|
51
|
-
file_extensions: z
|
|
52
|
-
.array(z.string())
|
|
53
|
-
.optional()
|
|
54
|
-
.describe('Filter by file extensions (e.g., [".ts", ".tsx", ".js"])'),
|
|
55
|
-
path_filter: z
|
|
56
|
-
.string()
|
|
57
|
-
.optional()
|
|
58
|
-
.describe('Filter by path pattern (e.g., "src/components", "tests", "docs")'),
|
|
59
|
-
exclude_paths: z
|
|
60
|
-
.array(z.string())
|
|
61
|
-
.optional()
|
|
62
|
-
.describe(
|
|
63
|
-
'Exclude paths containing these patterns (e.g., ["node_modules", ".git", "dist"])'
|
|
64
|
-
),
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
async ({
|
|
68
|
-
query,
|
|
69
|
-
limit = 10,
|
|
70
|
-
include_content = true,
|
|
71
|
-
file_extensions,
|
|
72
|
-
path_filter,
|
|
73
|
-
exclude_paths,
|
|
74
|
-
}) => {
|
|
75
|
-
try {
|
|
76
|
-
// Use UnifiedSearchService - same logic as CLI
|
|
77
|
-
const searchService = getSearchService();
|
|
78
|
-
await searchService.initialize();
|
|
79
|
-
|
|
80
|
-
// Check codebase status
|
|
81
|
-
const status = await searchService.getStatus();
|
|
82
|
-
|
|
83
|
-
// If indexing in progress, show progress
|
|
84
|
-
if (status.codebase.isIndexing) {
|
|
85
|
-
const progressBar =
|
|
86
|
-
'█'.repeat(Math.floor(status.codebase.progress / 5)) +
|
|
87
|
-
'░'.repeat(20 - Math.floor(status.codebase.progress / 5));
|
|
88
|
-
return {
|
|
89
|
-
content: [
|
|
90
|
-
{
|
|
91
|
-
type: 'text',
|
|
92
|
-
text: `⏳ **Codebase Indexing In Progress**\n\nThe codebase is currently being indexed. Please wait...\n\n**Progress:** ${status.codebase.progress}%\n\`${progressBar}\`\n\n**Status:**\n- Files indexed: ${status.codebase.progress > 0 ? Math.floor((status.codebase.fileCount * status.codebase.progress) / 100) : 0}/${status.codebase.fileCount}\n${status.codebase.currentFile ? `- Current file: \`${status.codebase.currentFile}\`` : ''}\n\n**Estimated time:** ${status.codebase.progress > 0 ? 'Less than 1 minute' : 'Starting...'}\n\n💡 **Tip:** Try your search again in a few seconds.`,
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (!status.codebase.indexed) {
|
|
99
|
-
return {
|
|
100
|
-
content: [
|
|
101
|
-
{
|
|
102
|
-
type: 'text',
|
|
103
|
-
text: `📭 **Codebase Not Indexed**\n\nThe codebase has not been indexed yet.\n\n**To fix:**\n- Run: \`sylphx codebase reindex\` from the command line\n- This will create a search index for all source files\n\n**Why this is needed:**\nThe first time you use codebase search, you need to build an index of all files. This only needs to be done once (or when files change significantly).`,
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Perform search using unified service
|
|
110
|
-
const result = await searchService.searchCodebase(query, {
|
|
111
|
-
limit,
|
|
112
|
-
include_content,
|
|
113
|
-
file_extensions,
|
|
114
|
-
path_filter,
|
|
115
|
-
exclude_paths,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Return MCP-formatted results
|
|
119
|
-
return searchService.formatResultsForMCP(result.results, query, result.totalIndexed);
|
|
120
|
-
} catch (error) {
|
|
121
|
-
return {
|
|
122
|
-
content: [
|
|
123
|
-
{
|
|
124
|
-
type: 'text',
|
|
125
|
-
text: `✗ Codebase search error: ${(error as Error).message}`,
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Register all codebase tools
|
|
136
|
-
*/
|
|
137
|
-
export function registerCodebaseTools(server: McpServer): void {
|
|
138
|
-
registerCodebaseSearchTool(server);
|
|
139
|
-
}
|