@nanocollective/nanocoder 1.14.3 → 1.15.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/README.md +31 -1
- package/dist/ai-sdk-client.d.ts +22 -0
- package/dist/ai-sdk-client.d.ts.map +1 -0
- package/dist/ai-sdk-client.js +389 -0
- package/dist/ai-sdk-client.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +1 -1
- package/dist/app.js.map +1 -1
- package/dist/client-factory.d.ts.map +1 -1
- package/dist/client-factory.js +5 -5
- package/dist/client-factory.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/recommendations.js +1 -1
- package/dist/commands/recommendations.js.map +1 -1
- package/dist/commands/streaming.d.ts +3 -0
- package/dist/commands/streaming.d.ts.map +1 -0
- package/dist/commands/streaming.js +23 -0
- package/dist/commands/streaming.js.map +1 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +17 -3
- package/dist/commands.js.map +1 -1
- package/dist/components/assistant-message.d.ts +0 -1
- package/dist/components/assistant-message.d.ts.map +1 -1
- package/dist/components/assistant-message.js +70 -122
- package/dist/components/assistant-message.js.map +1 -1
- package/dist/components/thinking-indicator.js +1 -1
- package/dist/components/thinking-indicator.js.map +1 -1
- package/dist/components/user-input.d.ts.map +1 -1
- package/dist/components/user-input.js +135 -27
- package/dist/components/user-input.js.map +1 -1
- package/dist/components/user-message.d.ts.map +1 -1
- package/dist/components/user-message.js +34 -1
- package/dist/components/user-message.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/index.spec.d.ts +2 -0
- package/dist/config/index.spec.d.ts.map +1 -0
- package/dist/config/index.spec.js +99 -0
- package/dist/config/index.spec.js.map +1 -0
- package/dist/config/preferences.d.ts +2 -0
- package/dist/config/preferences.d.ts.map +1 -1
- package/dist/config/preferences.js +10 -0
- package/dist/config/preferences.js.map +1 -1
- package/dist/hooks/useAppInitialization.d.ts.map +1 -1
- package/dist/hooks/useAppInitialization.js +2 -1
- package/dist/hooks/useAppInitialization.js.map +1 -1
- package/dist/hooks/useChatHandler.d.ts +2 -0
- package/dist/hooks/useChatHandler.d.ts.map +1 -1
- package/dist/hooks/useChatHandler.js +59 -9
- package/dist/hooks/useChatHandler.js.map +1 -1
- package/dist/mcp/mcp-client.d.ts +20 -1
- package/dist/mcp/mcp-client.d.ts.map +1 -1
- package/dist/mcp/mcp-client.js +57 -0
- package/dist/mcp/mcp-client.js.map +1 -1
- package/dist/message-handler.d.ts.map +1 -1
- package/dist/message-handler.js +7 -2
- package/dist/message-handler.js.map +1 -1
- package/dist/tool-calling/index.d.ts +1 -1
- package/dist/tool-calling/index.d.ts.map +1 -1
- package/dist/tool-calling/index.js +1 -1
- package/dist/tool-calling/index.js.map +1 -1
- package/dist/tool-calling/json-parser.d.ts +19 -2
- package/dist/tool-calling/json-parser.d.ts.map +1 -1
- package/dist/tool-calling/json-parser.js +65 -28
- package/dist/tool-calling/json-parser.js.map +1 -1
- package/dist/tool-calling/json-parser.spec.d.ts +2 -0
- package/dist/tool-calling/json-parser.spec.d.ts.map +1 -0
- package/dist/tool-calling/json-parser.spec.js +518 -0
- package/dist/tool-calling/json-parser.spec.js.map +1 -0
- package/dist/tool-calling/tool-parser.d.ts +20 -0
- package/dist/tool-calling/tool-parser.d.ts.map +1 -0
- package/dist/tool-calling/tool-parser.js +58 -0
- package/dist/tool-calling/tool-parser.js.map +1 -0
- package/dist/tool-calling/tool-parser.spec.d.ts +2 -0
- package/dist/tool-calling/tool-parser.spec.d.ts.map +1 -0
- package/dist/tool-calling/tool-parser.spec.js +250 -0
- package/dist/tool-calling/tool-parser.spec.js.map +1 -0
- package/dist/tool-calling/xml-parser.d.ts +17 -0
- package/dist/tool-calling/xml-parser.d.ts.map +1 -1
- package/dist/tool-calling/xml-parser.js +101 -13
- package/dist/tool-calling/xml-parser.js.map +1 -1
- package/dist/tool-calling/xml-parser.spec.d.ts +2 -0
- package/dist/tool-calling/xml-parser.spec.d.ts.map +1 -0
- package/dist/tool-calling/xml-parser.spec.js +437 -0
- package/dist/tool-calling/xml-parser.spec.js.map +1 -0
- package/dist/tools/create-file.d.ts.map +1 -1
- package/dist/tools/create-file.js +26 -23
- package/dist/tools/create-file.js.map +1 -1
- package/dist/tools/delete-lines.d.ts.map +1 -1
- package/dist/tools/delete-lines.js +29 -27
- package/dist/tools/delete-lines.js.map +1 -1
- package/dist/tools/execute-bash.d.ts.map +1 -1
- package/dist/tools/execute-bash.js +21 -19
- package/dist/tools/execute-bash.js.map +1 -1
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +21 -19
- package/dist/tools/fetch-url.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +8 -6
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/insert-lines.d.ts.map +1 -1
- package/dist/tools/insert-lines.js +29 -27
- package/dist/tools/insert-lines.js.map +1 -1
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +23 -19
- package/dist/tools/read-file.js.map +1 -1
- package/dist/tools/read-many-files.d.ts.map +1 -1
- package/dist/tools/read-many-files.js +24 -20
- package/dist/tools/read-many-files.js.map +1 -1
- package/dist/tools/replace-lines.d.ts.map +1 -1
- package/dist/tools/replace-lines.js +33 -31
- package/dist/tools/replace-lines.js.map +1 -1
- package/dist/tools/search-files.d.ts.map +1 -1
- package/dist/tools/search-files.js +33 -31
- package/dist/tools/search-files.js.map +1 -1
- package/dist/tools/tool-manager.d.ts +35 -19
- package/dist/tools/tool-manager.d.ts.map +1 -1
- package/dist/tools/tool-manager.js +63 -33
- package/dist/tools/tool-manager.js.map +1 -1
- package/dist/tools/tool-registry.d.ts +121 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +195 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +25 -23
- package/dist/tools/web-search.js.map +1 -1
- package/dist/types/config.d.ts +2 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/core.d.ts +58 -3
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/core.js +2 -0
- package/dist/types/core.js.map +1 -1
- package/dist/utils/file-autocomplete.d.ts +31 -0
- package/dist/utils/file-autocomplete.d.ts.map +1 -0
- package/dist/utils/file-autocomplete.js +156 -0
- package/dist/utils/file-autocomplete.js.map +1 -0
- package/dist/utils/file-autocomplete.spec.d.ts +2 -0
- package/dist/utils/file-autocomplete.spec.d.ts.map +1 -0
- package/dist/utils/file-autocomplete.spec.js +142 -0
- package/dist/utils/file-autocomplete.spec.js.map +1 -0
- package/dist/utils/file-content-loader.d.ts +31 -0
- package/dist/utils/file-content-loader.d.ts.map +1 -0
- package/dist/utils/file-content-loader.js +142 -0
- package/dist/utils/file-content-loader.js.map +1 -0
- package/dist/utils/file-content-loader.spec.d.ts +2 -0
- package/dist/utils/file-content-loader.spec.d.ts.map +1 -0
- package/dist/utils/file-content-loader.spec.js +140 -0
- package/dist/utils/file-content-loader.spec.js.map +1 -0
- package/dist/utils/file-mention-handler.d.ts +21 -0
- package/dist/utils/file-mention-handler.d.ts.map +1 -0
- package/dist/utils/file-mention-handler.js +59 -0
- package/dist/utils/file-mention-handler.js.map +1 -0
- package/dist/utils/file-mention-handler.spec.d.ts +2 -0
- package/dist/utils/file-mention-handler.spec.d.ts.map +1 -0
- package/dist/utils/file-mention-handler.spec.js +147 -0
- package/dist/utils/file-mention-handler.spec.js.map +1 -0
- package/dist/utils/file-mention-parser.d.ts +40 -0
- package/dist/utils/file-mention-parser.d.ts.map +1 -0
- package/dist/utils/file-mention-parser.js +122 -0
- package/dist/utils/file-mention-parser.js.map +1 -0
- package/dist/utils/file-mention-parser.spec.d.ts +2 -0
- package/dist/utils/file-mention-parser.spec.d.ts.map +1 -0
- package/dist/utils/file-mention-parser.spec.js +149 -0
- package/dist/utils/file-mention-parser.spec.js.map +1 -0
- package/dist/utils/fuzzy-matching.d.ts +13 -0
- package/dist/utils/fuzzy-matching.d.ts.map +1 -0
- package/dist/utils/fuzzy-matching.js +127 -0
- package/dist/utils/fuzzy-matching.js.map +1 -0
- package/dist/utils/fuzzy-matching.spec.d.ts +2 -0
- package/dist/utils/fuzzy-matching.spec.d.ts.map +1 -0
- package/dist/utils/fuzzy-matching.spec.js +123 -0
- package/dist/utils/fuzzy-matching.spec.js.map +1 -0
- package/dist/utils/prompt-assembly.spec.js +100 -2
- package/dist/utils/prompt-assembly.spec.js.map +1 -1
- package/dist/utils/prompt-processor.d.ts +2 -2
- package/dist/utils/prompt-processor.d.ts.map +1 -1
- package/dist/utils/prompt-processor.js +24 -41
- package/dist/utils/prompt-processor.js.map +1 -1
- package/package.json +8 -5
- package/dist/langgraph-client.d.ts +0 -19
- package/dist/langgraph-client.d.ts.map +0 -1
- package/dist/langgraph-client.js +0 -295
- package/dist/langgraph-client.js.map +0 -1
- package/dist/mcp/mcp-tool-adapter.d.ts +0 -22
- package/dist/mcp/mcp-tool-adapter.d.ts.map +0 -1
- package/dist/mcp/mcp-tool-adapter.js +0 -50
- package/dist/mcp/mcp-tool-adapter.js.map +0 -1
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { parseFileMentions, isValidFilePath, resolveFilePath, parseLineRange, } from './file-mention-parser.js';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
console.log(`\nfile-mention-parser.spec.ts`);
|
|
5
|
+
// Test parseFileMentions()
|
|
6
|
+
test('parses single file mention', t => {
|
|
7
|
+
const result = parseFileMentions('Check @app.tsx');
|
|
8
|
+
t.is(result.length, 1);
|
|
9
|
+
t.is(result[0].filePath, 'app.tsx');
|
|
10
|
+
t.is(result[0].rawText, '@app.tsx');
|
|
11
|
+
t.is(result[0].startIndex, 6);
|
|
12
|
+
t.is(result[0].endIndex, 14);
|
|
13
|
+
t.is(result[0].lineRange, undefined);
|
|
14
|
+
});
|
|
15
|
+
test('parses file with path', t => {
|
|
16
|
+
const result = parseFileMentions('Check @src/components/Button.tsx');
|
|
17
|
+
t.is(result.length, 1);
|
|
18
|
+
t.is(result[0].filePath, 'src/components/Button.tsx');
|
|
19
|
+
t.is(result[0].rawText, '@src/components/Button.tsx');
|
|
20
|
+
});
|
|
21
|
+
test('parses file with single line number', t => {
|
|
22
|
+
const result = parseFileMentions('@app.tsx:10');
|
|
23
|
+
t.is(result.length, 1);
|
|
24
|
+
t.is(result[0].filePath, 'app.tsx');
|
|
25
|
+
t.deepEqual(result[0].lineRange, { start: 10, end: undefined });
|
|
26
|
+
});
|
|
27
|
+
test('parses file with line range', t => {
|
|
28
|
+
const result = parseFileMentions('@app.tsx:10-20');
|
|
29
|
+
t.is(result.length, 1);
|
|
30
|
+
t.is(result[0].filePath, 'app.tsx');
|
|
31
|
+
t.deepEqual(result[0].lineRange, { start: 10, end: 20 });
|
|
32
|
+
});
|
|
33
|
+
test('parses multiple file mentions', t => {
|
|
34
|
+
const result = parseFileMentions('Compare @a.ts and @b.ts');
|
|
35
|
+
t.is(result.length, 2);
|
|
36
|
+
t.is(result[0].filePath, 'a.ts');
|
|
37
|
+
t.is(result[1].filePath, 'b.ts');
|
|
38
|
+
});
|
|
39
|
+
test('parses file mentions with different line ranges', t => {
|
|
40
|
+
const result = parseFileMentions('Check @app.tsx:1-5 and @utils.ts:10-15');
|
|
41
|
+
t.is(result.length, 2);
|
|
42
|
+
t.deepEqual(result[0].lineRange, { start: 1, end: 5 });
|
|
43
|
+
t.deepEqual(result[1].lineRange, { start: 10, end: 15 });
|
|
44
|
+
});
|
|
45
|
+
test('handles text without file mentions', t => {
|
|
46
|
+
const result = parseFileMentions('This is just regular text');
|
|
47
|
+
t.is(result.length, 0);
|
|
48
|
+
});
|
|
49
|
+
test('ignores @ symbols in email addresses', t => {
|
|
50
|
+
const result = parseFileMentions('Email: user@example.com');
|
|
51
|
+
// Should not match email addresses (they have spaces or are at word boundaries)
|
|
52
|
+
// However, this might match "example.com" - let's verify behavior
|
|
53
|
+
t.true(result.length <= 1);
|
|
54
|
+
if (result.length === 1) {
|
|
55
|
+
t.is(result[0].filePath, 'example.com');
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
test('rejects invalid line ranges in file mentions', t => {
|
|
59
|
+
// Line range where end < start should not have lineRange
|
|
60
|
+
const result = parseFileMentions('@app.tsx:20-10');
|
|
61
|
+
t.is(result.length, 1);
|
|
62
|
+
t.is(result[0].lineRange, undefined);
|
|
63
|
+
});
|
|
64
|
+
test('rejects zero or negative line numbers', t => {
|
|
65
|
+
const result1 = parseFileMentions('@app.tsx:0');
|
|
66
|
+
t.is(result1[0].lineRange, undefined);
|
|
67
|
+
const result2 = parseFileMentions('@app.tsx:0-10');
|
|
68
|
+
t.is(result2[0].lineRange, undefined);
|
|
69
|
+
});
|
|
70
|
+
test('handles complex file paths', t => {
|
|
71
|
+
const result = parseFileMentions('@src/components/ui/Button/index.tsx:100-200');
|
|
72
|
+
t.is(result.length, 1);
|
|
73
|
+
t.is(result[0].filePath, 'src/components/ui/Button/index.tsx');
|
|
74
|
+
t.deepEqual(result[0].lineRange, { start: 100, end: 200 });
|
|
75
|
+
});
|
|
76
|
+
// Test isValidFilePath()
|
|
77
|
+
test('accepts valid relative paths', t => {
|
|
78
|
+
t.true(isValidFilePath('app.tsx'));
|
|
79
|
+
t.true(isValidFilePath('src/app.tsx'));
|
|
80
|
+
t.true(isValidFilePath('src/components/Button.tsx'));
|
|
81
|
+
});
|
|
82
|
+
test('rejects directory traversal attempts', t => {
|
|
83
|
+
t.false(isValidFilePath('../../etc/passwd'));
|
|
84
|
+
t.false(isValidFilePath('../../../secret.txt'));
|
|
85
|
+
t.false(isValidFilePath('src/../../../etc/passwd'));
|
|
86
|
+
});
|
|
87
|
+
test('rejects absolute paths', t => {
|
|
88
|
+
t.false(isValidFilePath('/etc/passwd'));
|
|
89
|
+
t.false(isValidFilePath('/home/user/file.txt'));
|
|
90
|
+
t.false(isValidFilePath('C:\\Windows\\System32\\file.txt'));
|
|
91
|
+
});
|
|
92
|
+
test('rejects empty or whitespace paths', t => {
|
|
93
|
+
t.false(isValidFilePath(''));
|
|
94
|
+
t.false(isValidFilePath(' '));
|
|
95
|
+
});
|
|
96
|
+
test('rejects paths with null bytes', t => {
|
|
97
|
+
t.false(isValidFilePath('file.txt\0'));
|
|
98
|
+
t.false(isValidFilePath('file\0.txt'));
|
|
99
|
+
});
|
|
100
|
+
test('rejects paths starting with slashes', t => {
|
|
101
|
+
t.false(isValidFilePath('/file.txt'));
|
|
102
|
+
t.false(isValidFilePath('\\file.txt'));
|
|
103
|
+
});
|
|
104
|
+
// Test resolveFilePath()
|
|
105
|
+
test('resolves relative path to absolute', t => {
|
|
106
|
+
const cwd = '/home/user/project';
|
|
107
|
+
const resolved = resolveFilePath('src/app.tsx', cwd);
|
|
108
|
+
t.is(resolved, path.join(cwd, 'src/app.tsx'));
|
|
109
|
+
});
|
|
110
|
+
test('throws on invalid file paths', t => {
|
|
111
|
+
const cwd = '/home/user/project';
|
|
112
|
+
t.throws(() => resolveFilePath('../../etc/passwd', cwd), {
|
|
113
|
+
message: /Invalid file path/,
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
test('throws when resolved path escapes project directory', t => {
|
|
117
|
+
const cwd = '/home/user/project';
|
|
118
|
+
// Even if validation passes, resolve should catch escaping
|
|
119
|
+
t.throws(() => resolveFilePath('/etc/passwd', cwd), {
|
|
120
|
+
message: /Invalid file path/,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
test('resolves nested paths correctly', t => {
|
|
124
|
+
const cwd = '/home/user/project';
|
|
125
|
+
const resolved = resolveFilePath('src/components/ui/Button.tsx', cwd);
|
|
126
|
+
t.is(resolved, path.join(cwd, 'src/components/ui/Button.tsx'));
|
|
127
|
+
});
|
|
128
|
+
// Test parseLineRange()
|
|
129
|
+
test('parses single line number', t => {
|
|
130
|
+
const result = parseLineRange('10');
|
|
131
|
+
t.deepEqual(result, { start: 10, end: undefined });
|
|
132
|
+
});
|
|
133
|
+
test('parses line range', t => {
|
|
134
|
+
const result = parseLineRange('10-20');
|
|
135
|
+
t.deepEqual(result, { start: 10, end: 20 });
|
|
136
|
+
});
|
|
137
|
+
test('rejects invalid line ranges', t => {
|
|
138
|
+
t.is(parseLineRange('20-10'), null); // end < start
|
|
139
|
+
t.is(parseLineRange('0'), null); // zero
|
|
140
|
+
t.is(parseLineRange('-5'), null); // negative
|
|
141
|
+
t.is(parseLineRange('abc'), null); // non-numeric
|
|
142
|
+
t.is(parseLineRange(''), null); // empty
|
|
143
|
+
});
|
|
144
|
+
test('rejects malformed ranges', t => {
|
|
145
|
+
t.is(parseLineRange('10-20-30'), null); // too many parts
|
|
146
|
+
t.is(parseLineRange('10-'), null); // missing end
|
|
147
|
+
t.is(parseLineRange('-20'), null); // missing start
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=file-mention-parser.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-mention-parser.spec.js","sourceRoot":"","sources":["../../source/utils/file-mention-parser.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fuzzy match scoring algorithm
|
|
3
|
+
* Returns a score from 0 to 1000 (higher = better match)
|
|
4
|
+
*
|
|
5
|
+
* This can be used for matching file paths, command names, or any other strings.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fuzzyScore(text: string, query: string): number;
|
|
8
|
+
/**
|
|
9
|
+
* Fuzzy score specifically for file paths
|
|
10
|
+
* Gives higher priority to filename matches over directory matches
|
|
11
|
+
*/
|
|
12
|
+
export declare function fuzzyScoreFilePath(filePath: string, query: string): number;
|
|
13
|
+
//# sourceMappingURL=fuzzy-matching.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fuzzy-matching.d.ts","sourceRoot":"","sources":["../../source/utils/fuzzy-matching.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA2D9D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA0E1E"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fuzzy match scoring algorithm
|
|
3
|
+
* Returns a score from 0 to 1000 (higher = better match)
|
|
4
|
+
*
|
|
5
|
+
* This can be used for matching file paths, command names, or any other strings.
|
|
6
|
+
*/
|
|
7
|
+
export function fuzzyScore(text, query) {
|
|
8
|
+
if (!query) {
|
|
9
|
+
return 0;
|
|
10
|
+
}
|
|
11
|
+
const lowerText = text.toLowerCase();
|
|
12
|
+
const lowerQuery = query.toLowerCase();
|
|
13
|
+
// Exact match (highest score)
|
|
14
|
+
if (lowerText === lowerQuery) {
|
|
15
|
+
return 1000;
|
|
16
|
+
}
|
|
17
|
+
// Text ends with query
|
|
18
|
+
if (lowerText.endsWith(lowerQuery)) {
|
|
19
|
+
return 850;
|
|
20
|
+
}
|
|
21
|
+
// Text starts with query
|
|
22
|
+
if (lowerText.startsWith(lowerQuery)) {
|
|
23
|
+
return 800;
|
|
24
|
+
}
|
|
25
|
+
// Text contains query as substring
|
|
26
|
+
if (lowerText.includes(lowerQuery)) {
|
|
27
|
+
return 700;
|
|
28
|
+
}
|
|
29
|
+
// Sequential character match (fuzzy)
|
|
30
|
+
// All query characters appear in order in the text
|
|
31
|
+
let textIndex = 0;
|
|
32
|
+
let queryIndex = 0;
|
|
33
|
+
let lastMatchIndex = -1;
|
|
34
|
+
let consecutiveMatches = 0;
|
|
35
|
+
while (textIndex < lowerText.length && queryIndex < lowerQuery.length) {
|
|
36
|
+
if (lowerText[textIndex] === lowerQuery[queryIndex]) {
|
|
37
|
+
// Bonus for consecutive matches
|
|
38
|
+
if (textIndex === lastMatchIndex + 1) {
|
|
39
|
+
consecutiveMatches++;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
consecutiveMatches = 1;
|
|
43
|
+
}
|
|
44
|
+
lastMatchIndex = textIndex;
|
|
45
|
+
queryIndex++;
|
|
46
|
+
}
|
|
47
|
+
textIndex++;
|
|
48
|
+
}
|
|
49
|
+
// If all query characters matched
|
|
50
|
+
if (queryIndex === lowerQuery.length) {
|
|
51
|
+
// Score based on match density and consecutive matches
|
|
52
|
+
const matchDensity = lowerQuery.length / lowerText.length;
|
|
53
|
+
const consecutiveBonus = consecutiveMatches * 50;
|
|
54
|
+
return Math.min(500 + matchDensity * 100 + consecutiveBonus, 699);
|
|
55
|
+
}
|
|
56
|
+
// No match
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Fuzzy score specifically for file paths
|
|
61
|
+
* Gives higher priority to filename matches over directory matches
|
|
62
|
+
*/
|
|
63
|
+
export function fuzzyScoreFilePath(filePath, query) {
|
|
64
|
+
if (!query) {
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
const lowerPath = filePath.toLowerCase();
|
|
68
|
+
const lowerQuery = query.toLowerCase();
|
|
69
|
+
// Exact match (highest score)
|
|
70
|
+
if (lowerPath === lowerQuery) {
|
|
71
|
+
return 1000;
|
|
72
|
+
}
|
|
73
|
+
// Exact match of filename (without path)
|
|
74
|
+
const filename = filePath.split('/').pop() || '';
|
|
75
|
+
if (filename.toLowerCase() === lowerQuery) {
|
|
76
|
+
return 900;
|
|
77
|
+
}
|
|
78
|
+
// Path ends with query
|
|
79
|
+
if (lowerPath.endsWith(lowerQuery)) {
|
|
80
|
+
return 850;
|
|
81
|
+
}
|
|
82
|
+
// Filename starts with query
|
|
83
|
+
if (filename.toLowerCase().startsWith(lowerQuery)) {
|
|
84
|
+
return 800;
|
|
85
|
+
}
|
|
86
|
+
// Path starts with query
|
|
87
|
+
if (lowerPath.startsWith(lowerQuery)) {
|
|
88
|
+
return 750;
|
|
89
|
+
}
|
|
90
|
+
// Filename contains query as substring
|
|
91
|
+
if (filename.toLowerCase().includes(lowerQuery)) {
|
|
92
|
+
return 700;
|
|
93
|
+
}
|
|
94
|
+
// Path contains query as substring
|
|
95
|
+
if (lowerPath.includes(lowerQuery)) {
|
|
96
|
+
return 600;
|
|
97
|
+
}
|
|
98
|
+
// Sequential character match (fuzzy)
|
|
99
|
+
let pathIndex = 0;
|
|
100
|
+
let queryIndex = 0;
|
|
101
|
+
let lastMatchIndex = -1;
|
|
102
|
+
let consecutiveMatches = 0;
|
|
103
|
+
while (pathIndex < lowerPath.length && queryIndex < lowerQuery.length) {
|
|
104
|
+
if (lowerPath[pathIndex] === lowerQuery[queryIndex]) {
|
|
105
|
+
// Bonus for consecutive matches
|
|
106
|
+
if (pathIndex === lastMatchIndex + 1) {
|
|
107
|
+
consecutiveMatches++;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
consecutiveMatches = 1;
|
|
111
|
+
}
|
|
112
|
+
lastMatchIndex = pathIndex;
|
|
113
|
+
queryIndex++;
|
|
114
|
+
}
|
|
115
|
+
pathIndex++;
|
|
116
|
+
}
|
|
117
|
+
// If all query characters matched
|
|
118
|
+
if (queryIndex === lowerQuery.length) {
|
|
119
|
+
// Score based on match density and consecutive matches
|
|
120
|
+
const matchDensity = lowerQuery.length / lowerPath.length;
|
|
121
|
+
const consecutiveBonus = consecutiveMatches * 50;
|
|
122
|
+
return Math.min(500 + matchDensity * 100 + consecutiveBonus, 599);
|
|
123
|
+
}
|
|
124
|
+
// No match
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=fuzzy-matching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fuzzy-matching.js","sourceRoot":"","sources":["../../source/utils/fuzzy-matching.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fuzzy-matching.spec.d.ts","sourceRoot":"","sources":["../../source/utils/fuzzy-matching.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { fuzzyScore, fuzzyScoreFilePath } from './fuzzy-matching.js';
|
|
3
|
+
// Tests for fuzzyScore (general text matching)
|
|
4
|
+
test('fuzzyScore - exact match returns highest score', t => {
|
|
5
|
+
t.is(fuzzyScore('help', 'help'), 1000);
|
|
6
|
+
t.is(fuzzyScore('status', 'status'), 1000);
|
|
7
|
+
});
|
|
8
|
+
test('fuzzyScore - case insensitive matching', t => {
|
|
9
|
+
t.is(fuzzyScore('Help', 'help'), 1000);
|
|
10
|
+
t.is(fuzzyScore('STATUS', 'status'), 1000);
|
|
11
|
+
t.is(fuzzyScore('help', 'HELP'), 1000);
|
|
12
|
+
});
|
|
13
|
+
test('fuzzyScore - prefix match', t => {
|
|
14
|
+
const score = fuzzyScore('help', 'hel');
|
|
15
|
+
t.true(score > 0);
|
|
16
|
+
t.true(score >= 800);
|
|
17
|
+
});
|
|
18
|
+
test('fuzzyScore - substring match', t => {
|
|
19
|
+
const score = fuzzyScore('status', 'tat');
|
|
20
|
+
t.true(score > 0);
|
|
21
|
+
t.true(score >= 700);
|
|
22
|
+
});
|
|
23
|
+
test('fuzzyScore - sequential character match', t => {
|
|
24
|
+
const score = fuzzyScore('provider', 'pvdr');
|
|
25
|
+
t.true(score > 0);
|
|
26
|
+
t.true(score < 700); // Should be lower than substring match
|
|
27
|
+
});
|
|
28
|
+
test('fuzzyScore - no match returns 0', t => {
|
|
29
|
+
t.is(fuzzyScore('help', 'xyz'), 0);
|
|
30
|
+
t.is(fuzzyScore('status', 'abc'), 0);
|
|
31
|
+
});
|
|
32
|
+
test('fuzzyScore - empty query returns 0', t => {
|
|
33
|
+
t.is(fuzzyScore('help', ''), 0);
|
|
34
|
+
t.is(fuzzyScore('anything', ''), 0);
|
|
35
|
+
});
|
|
36
|
+
test('fuzzyScore - ranks exact match higher than prefix', t => {
|
|
37
|
+
const exactScore = fuzzyScore('help', 'help');
|
|
38
|
+
const prefixScore = fuzzyScore('helper', 'help');
|
|
39
|
+
t.true(exactScore > prefixScore);
|
|
40
|
+
});
|
|
41
|
+
test('fuzzyScore - ranks prefix higher than substring', t => {
|
|
42
|
+
const prefixScore = fuzzyScore('helper', 'help');
|
|
43
|
+
const substringScore = fuzzyScore('unhelpful', 'help');
|
|
44
|
+
t.true(prefixScore > substringScore);
|
|
45
|
+
});
|
|
46
|
+
test('fuzzyScore - ranks substring higher than fuzzy', t => {
|
|
47
|
+
const substringScore = fuzzyScore('helper', 'elp');
|
|
48
|
+
const fuzzyScore1 = fuzzyScore('enable-lp', 'elp');
|
|
49
|
+
t.true(substringScore > fuzzyScore1);
|
|
50
|
+
});
|
|
51
|
+
// Tests for fuzzyScoreFilePath (file path specific matching)
|
|
52
|
+
test('fuzzyScoreFilePath - exact filename match scores high', t => {
|
|
53
|
+
const score = fuzzyScoreFilePath('src/utils/helper.ts', 'helper.ts');
|
|
54
|
+
t.true(score >= 900);
|
|
55
|
+
});
|
|
56
|
+
test('fuzzyScoreFilePath - filename prefix scores higher than path prefix', t => {
|
|
57
|
+
const filenameScore = fuzzyScoreFilePath('src/utils/helper.ts', 'help');
|
|
58
|
+
const pathScore = fuzzyScoreFilePath('helper/src/utils/file.ts', 'help');
|
|
59
|
+
t.true(filenameScore > pathScore);
|
|
60
|
+
});
|
|
61
|
+
test('fuzzyScoreFilePath - filename substring matches correctly', t => {
|
|
62
|
+
const filenameScore = fuzzyScoreFilePath('src/utils/my-helper.ts', 'help');
|
|
63
|
+
const pathScore = fuzzyScoreFilePath('helper/src/utils/file.ts', 'help');
|
|
64
|
+
// Both should have scores, but path prefix might score higher than filename substring
|
|
65
|
+
t.true(filenameScore > 0);
|
|
66
|
+
t.true(pathScore > 0);
|
|
67
|
+
});
|
|
68
|
+
test('fuzzyScoreFilePath - handles paths with multiple slashes', t => {
|
|
69
|
+
const score = fuzzyScoreFilePath('a/b/c/d/file.ts', 'file');
|
|
70
|
+
t.true(score > 0);
|
|
71
|
+
});
|
|
72
|
+
test('fuzzyScoreFilePath - case insensitive for paths', t => {
|
|
73
|
+
const score1 = fuzzyScoreFilePath('src/Utils/Helper.ts', 'helper');
|
|
74
|
+
const score2 = fuzzyScoreFilePath('src/utils/helper.ts', 'HELPER');
|
|
75
|
+
t.true(score1 > 0);
|
|
76
|
+
t.true(score2 > 0);
|
|
77
|
+
});
|
|
78
|
+
// Command-specific test scenarios
|
|
79
|
+
test('command matching - /h matches help, status does not', t => {
|
|
80
|
+
const helpScore = fuzzyScore('help', 'h');
|
|
81
|
+
const statusScore = fuzzyScore('status', 'h');
|
|
82
|
+
t.true(helpScore > 0);
|
|
83
|
+
t.is(statusScore, 0);
|
|
84
|
+
});
|
|
85
|
+
test('command matching - /st matches status', t => {
|
|
86
|
+
const score = fuzzyScore('status', 'st');
|
|
87
|
+
t.true(score > 0);
|
|
88
|
+
t.true(score >= 800); // Should be prefix match
|
|
89
|
+
});
|
|
90
|
+
test('command matching - /mod matches model', t => {
|
|
91
|
+
const modelScore = fuzzyScore('model', 'mod');
|
|
92
|
+
const recommendationsScore = fuzzyScore('recommendations', 'mod');
|
|
93
|
+
t.true(modelScore > 0);
|
|
94
|
+
// recommendations doesn't contain 'mod' as substring, so it should be 0 or fuzzy match
|
|
95
|
+
// model should score higher (prefix match)
|
|
96
|
+
t.true(modelScore > recommendationsScore);
|
|
97
|
+
});
|
|
98
|
+
test('command matching - fuzzy matching for /pvd matches provider', t => {
|
|
99
|
+
const score = fuzzyScore('provider', 'pvd');
|
|
100
|
+
t.true(score > 0);
|
|
101
|
+
});
|
|
102
|
+
test('command matching - /init matches init higher than initialization', t => {
|
|
103
|
+
const initScore = fuzzyScore('init', 'init');
|
|
104
|
+
const initializationScore = fuzzyScore('initialization', 'init');
|
|
105
|
+
t.true(initScore > initializationScore);
|
|
106
|
+
});
|
|
107
|
+
// Edge cases
|
|
108
|
+
test('fuzzyScore - single character queries work', t => {
|
|
109
|
+
const score1 = fuzzyScore('help', 'h');
|
|
110
|
+
const score2 = fuzzyScore('status', 's');
|
|
111
|
+
t.true(score1 > 0);
|
|
112
|
+
t.true(score2 > 0);
|
|
113
|
+
});
|
|
114
|
+
test('fuzzyScore - longer text with short query', t => {
|
|
115
|
+
const score = fuzzyScore('very-long-command-name-here', 'vlc');
|
|
116
|
+
t.true(score > 0);
|
|
117
|
+
});
|
|
118
|
+
test('fuzzyScoreFilePath - works with Windows-style paths', t => {
|
|
119
|
+
// While the function uses /, testing that it handles edge cases
|
|
120
|
+
const score = fuzzyScoreFilePath('src\\utils\\file.ts', 'file');
|
|
121
|
+
t.true(score > 0);
|
|
122
|
+
});
|
|
123
|
+
//# sourceMappingURL=fuzzy-matching.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fuzzy-matching.spec.js","sourceRoot":"","sources":["../../source/utils/fuzzy-matching.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,12 +5,23 @@ console.log(`\nprompt-assembly.spec.ts`);
|
|
|
5
5
|
function assemblePrompt(inputState) {
|
|
6
6
|
let assembledPrompt = inputState.displayValue;
|
|
7
7
|
// Replace each placeholder with its full content
|
|
8
|
-
Object.entries(inputState.placeholderContent).forEach(([
|
|
8
|
+
Object.entries(inputState.placeholderContent).forEach(([placeholderId, placeholder]) => {
|
|
9
9
|
if (placeholder.type === 'paste') {
|
|
10
|
-
const placeholderPattern = `\\[Paste #${
|
|
10
|
+
const placeholderPattern = `\\[Paste #${placeholderId}: \\d+ chars\\]`;
|
|
11
11
|
const regex = new RegExp(placeholderPattern, 'g');
|
|
12
12
|
assembledPrompt = assembledPrompt.replace(regex, placeholder.content);
|
|
13
13
|
}
|
|
14
|
+
else if (placeholder.type === 'file') {
|
|
15
|
+
// For file placeholders: [@filepath] or [@filepath:10-20]
|
|
16
|
+
const escapedPath = placeholder.displayText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
17
|
+
const regex = new RegExp(escapedPath, 'g');
|
|
18
|
+
// Format file content with header (mimicking prompt-processor.ts)
|
|
19
|
+
const fileName = placeholder.filePath.split('/').pop() || placeholder.filePath;
|
|
20
|
+
const header = `=== File: ${fileName} ===`;
|
|
21
|
+
const footer = '='.repeat(header.length);
|
|
22
|
+
const formattedContent = `${header}\n${placeholder.content}\n${footer}`;
|
|
23
|
+
assembledPrompt = assembledPrompt.replace(regex, formattedContent);
|
|
24
|
+
}
|
|
14
25
|
});
|
|
15
26
|
return assembledPrompt;
|
|
16
27
|
}
|
|
@@ -78,4 +89,91 @@ test('extractPlaceholderIds returns empty for no placeholders', t => {
|
|
|
78
89
|
const result = extractPlaceholderIds(displayValue);
|
|
79
90
|
t.deepEqual(result, []);
|
|
80
91
|
});
|
|
92
|
+
// FILE placeholder tests
|
|
93
|
+
test('assemblePrompt replaces file placeholder with formatted content', t => {
|
|
94
|
+
const inputState = {
|
|
95
|
+
displayValue: 'Check this file: [@src/app.tsx]',
|
|
96
|
+
placeholderContent: {
|
|
97
|
+
file_1: {
|
|
98
|
+
type: PlaceholderType.FILE,
|
|
99
|
+
displayText: '[@src/app.tsx]',
|
|
100
|
+
filePath: '/Users/test/project/src/app.tsx',
|
|
101
|
+
content: ' 1: import React from "react";\n 2: export function App() {}',
|
|
102
|
+
fileSize: 100,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
const result = assemblePrompt(inputState);
|
|
107
|
+
t.true(result.includes('=== File: app.tsx ==='));
|
|
108
|
+
t.true(result.includes('import React from "react"'));
|
|
109
|
+
// Footer should be same length as header
|
|
110
|
+
t.true(result.includes('='.repeat('=== File: app.tsx ==='.length)));
|
|
111
|
+
});
|
|
112
|
+
test('assemblePrompt handles file placeholder with line range', t => {
|
|
113
|
+
const inputState = {
|
|
114
|
+
displayValue: 'Review [@app.tsx:10-20]',
|
|
115
|
+
placeholderContent: {
|
|
116
|
+
file_1: {
|
|
117
|
+
type: PlaceholderType.FILE,
|
|
118
|
+
displayText: '[@app.tsx:10-20]',
|
|
119
|
+
filePath: '/Users/test/app.tsx',
|
|
120
|
+
content: ' 10: function test() {\n 11: return true;\n 12: }',
|
|
121
|
+
fileSize: 50,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
const result = assemblePrompt(inputState);
|
|
126
|
+
t.true(result.includes('=== File: app.tsx ==='));
|
|
127
|
+
t.true(result.includes('function test()'));
|
|
128
|
+
});
|
|
129
|
+
test('assemblePrompt handles multiple file placeholders', t => {
|
|
130
|
+
const inputState = {
|
|
131
|
+
displayValue: 'Compare [@a.ts] with [@b.ts]',
|
|
132
|
+
placeholderContent: {
|
|
133
|
+
file_1: {
|
|
134
|
+
type: PlaceholderType.FILE,
|
|
135
|
+
displayText: '[@a.ts]',
|
|
136
|
+
filePath: '/project/a.ts',
|
|
137
|
+
content: ' 1: const a = 1;',
|
|
138
|
+
fileSize: 20,
|
|
139
|
+
},
|
|
140
|
+
file_2: {
|
|
141
|
+
type: PlaceholderType.FILE,
|
|
142
|
+
displayText: '[@b.ts]',
|
|
143
|
+
filePath: '/project/b.ts',
|
|
144
|
+
content: ' 1: const b = 2;',
|
|
145
|
+
fileSize: 20,
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
const result = assemblePrompt(inputState);
|
|
150
|
+
t.true(result.includes('=== File: a.ts ==='));
|
|
151
|
+
t.true(result.includes('const a = 1'));
|
|
152
|
+
t.true(result.includes('=== File: b.ts ==='));
|
|
153
|
+
t.true(result.includes('const b = 2'));
|
|
154
|
+
});
|
|
155
|
+
test('assemblePrompt handles mixed paste and file placeholders', t => {
|
|
156
|
+
const inputState = {
|
|
157
|
+
displayValue: 'Text [Paste #123: 20 chars] and [@file.ts]',
|
|
158
|
+
placeholderContent: {
|
|
159
|
+
'123': {
|
|
160
|
+
type: PlaceholderType.PASTE,
|
|
161
|
+
displayText: '[Paste #123: 20 chars]',
|
|
162
|
+
content: 'pasted code',
|
|
163
|
+
originalSize: 20,
|
|
164
|
+
},
|
|
165
|
+
file_1: {
|
|
166
|
+
type: PlaceholderType.FILE,
|
|
167
|
+
displayText: '[@file.ts]',
|
|
168
|
+
filePath: '/project/file.ts',
|
|
169
|
+
content: ' 1: export const x = 1;',
|
|
170
|
+
fileSize: 30,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
const result = assemblePrompt(inputState);
|
|
175
|
+
t.true(result.includes('pasted code'));
|
|
176
|
+
t.true(result.includes('=== File: file.ts ==='));
|
|
177
|
+
t.true(result.includes('export const x = 1'));
|
|
178
|
+
});
|
|
81
179
|
//# sourceMappingURL=prompt-assembly.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-assembly.spec.js","sourceRoot":"","sources":["../../source/utils/prompt-assembly.spec.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"prompt-assembly.spec.js","sourceRoot":"","sources":["../../source/utils/prompt-assembly.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AISDKCoreTool } from '../types/index.js';
|
|
2
2
|
import type { InputState } from '../types/hooks.js';
|
|
3
3
|
/**
|
|
4
4
|
* Process the main prompt template by injecting dynamic tool documentation and system info
|
|
5
5
|
*/
|
|
6
|
-
export declare function processPromptTemplate(tools:
|
|
6
|
+
export declare function processPromptTemplate(tools: Record<string, AISDKCoreTool>): string;
|
|
7
7
|
/**
|
|
8
8
|
* Assemble the final prompt by replacing all placeholders with their full content
|
|
9
9
|
* This function is called before sending the prompt to the AI
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt-processor.d.ts","sourceRoot":"","sources":["../../source/utils/prompt-processor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,
|
|
1
|
+
{"version":3,"file":"prompt-processor.d.ts","sourceRoot":"","sources":["../../source/utils/prompt-processor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAoE/C;;GAEG;AACH,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAClC,MAAM,CAsCR;AAsED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAqD7D"}
|