codeep 1.2.17 → 1.2.18
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 +20 -7
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.js +21 -17
- package/dist/renderer/App.d.ts +1 -5
- package/dist/renderer/App.js +106 -486
- package/dist/renderer/agentExecution.d.ts +36 -0
- package/dist/renderer/agentExecution.js +394 -0
- package/dist/renderer/commands.d.ts +16 -0
- package/dist/renderer/commands.js +838 -0
- package/dist/renderer/handlers.d.ts +87 -0
- package/dist/renderer/handlers.js +260 -0
- package/dist/renderer/highlight.d.ts +18 -0
- package/dist/renderer/highlight.js +130 -0
- package/dist/renderer/main.d.ts +4 -2
- package/dist/renderer/main.js +103 -1550
- package/dist/utils/agent.d.ts +5 -15
- package/dist/utils/agent.js +9 -693
- package/dist/utils/agentChat.d.ts +46 -0
- package/dist/utils/agentChat.js +343 -0
- package/dist/utils/agentStream.d.ts +23 -0
- package/dist/utils/agentStream.js +216 -0
- package/dist/utils/keychain.js +3 -2
- package/dist/utils/learning.js +9 -3
- package/dist/utils/mcpIntegration.d.ts +61 -0
- package/dist/utils/mcpIntegration.js +154 -0
- package/dist/utils/project.js +8 -3
- package/dist/utils/skills.js +21 -11
- package/dist/utils/smartContext.d.ts +4 -0
- package/dist/utils/smartContext.js +51 -14
- package/dist/utils/toolExecution.d.ts +27 -0
- package/dist/utils/toolExecution.js +525 -0
- package/dist/utils/toolParsing.d.ts +18 -0
- package/dist/utils/toolParsing.js +302 -0
- package/dist/utils/tools.d.ts +11 -24
- package/dist/utils/tools.js +22 -1187
- package/package.json +3 -1
- package/dist/config/config.test.d.ts +0 -1
- package/dist/config/config.test.js +0 -157
- package/dist/config/providers.test.d.ts +0 -1
- package/dist/config/providers.test.js +0 -187
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/index.js +0 -4
- package/dist/hooks/useAgent.d.ts +0 -29
- package/dist/hooks/useAgent.js +0 -148
- package/dist/utils/agent.test.d.ts +0 -1
- package/dist/utils/agent.test.js +0 -315
- package/dist/utils/git.test.d.ts +0 -1
- package/dist/utils/git.test.js +0 -193
- package/dist/utils/gitignore.test.d.ts +0 -1
- package/dist/utils/gitignore.test.js +0 -167
- package/dist/utils/project.test.d.ts +0 -1
- package/dist/utils/project.test.js +0 -212
- package/dist/utils/ratelimit.test.d.ts +0 -1
- package/dist/utils/ratelimit.test.js +0 -131
- package/dist/utils/retry.test.d.ts +0 -1
- package/dist/utils/retry.test.js +0 -163
- package/dist/utils/smartContext.test.d.ts +0 -1
- package/dist/utils/smartContext.test.js +0 -382
- package/dist/utils/tools.test.d.ts +0 -1
- package/dist/utils/tools.test.js +0 -681
- package/dist/utils/validation.test.d.ts +0 -1
- package/dist/utils/validation.test.js +0 -164
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) integration for Z.AI and MiniMax.
|
|
3
|
+
*
|
|
4
|
+
* Provides config discovery and API call helpers used by toolExecution.ts.
|
|
5
|
+
*/
|
|
6
|
+
export interface McpContentItem {
|
|
7
|
+
text?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MinimaxApiResponse {
|
|
10
|
+
content?: McpContentItem[];
|
|
11
|
+
}
|
|
12
|
+
export interface ZaiMcpResponse {
|
|
13
|
+
error?: {
|
|
14
|
+
message?: string;
|
|
15
|
+
};
|
|
16
|
+
result?: {
|
|
17
|
+
content?: McpContentItem[];
|
|
18
|
+
} | string;
|
|
19
|
+
}
|
|
20
|
+
export declare const ZAI_MCP_TOOLS: string[];
|
|
21
|
+
export declare const ZAI_PROVIDER_IDS: string[];
|
|
22
|
+
export declare const MINIMAX_MCP_TOOLS: string[];
|
|
23
|
+
export declare const MINIMAX_PROVIDER_IDS: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Find a Z.AI provider that has an API key configured.
|
|
26
|
+
* Returns the provider ID and API key, or null if none found.
|
|
27
|
+
* Prefers the active provider if it's Z.AI, otherwise checks all Z.AI providers.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getZaiMcpConfig(): {
|
|
30
|
+
providerId: string;
|
|
31
|
+
apiKey: string;
|
|
32
|
+
endpoints: {
|
|
33
|
+
webSearch: string;
|
|
34
|
+
webReader: string;
|
|
35
|
+
zread: string;
|
|
36
|
+
};
|
|
37
|
+
} | null;
|
|
38
|
+
/**
|
|
39
|
+
* Check if Z.AI MCP tools are available (user has any Z.AI API key)
|
|
40
|
+
*/
|
|
41
|
+
export declare function hasZaiMcpAccess(): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Find a MiniMax provider that has an API key configured.
|
|
44
|
+
* Returns the base host URL and API key, or null if none found.
|
|
45
|
+
*/
|
|
46
|
+
export declare function getMinimaxMcpConfig(): {
|
|
47
|
+
host: string;
|
|
48
|
+
apiKey: string;
|
|
49
|
+
} | null;
|
|
50
|
+
/**
|
|
51
|
+
* Check if MiniMax MCP tools are available
|
|
52
|
+
*/
|
|
53
|
+
export declare function hasMinimaxMcpAccess(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Call a MiniMax MCP REST API endpoint
|
|
56
|
+
*/
|
|
57
|
+
export declare function callMinimaxApi(host: string, path: string, body: Record<string, unknown>, apiKey: string): Promise<string>;
|
|
58
|
+
/**
|
|
59
|
+
* Call a Z.AI MCP endpoint via JSON-RPC 2.0
|
|
60
|
+
*/
|
|
61
|
+
export declare function callZaiMcp(endpoint: string, toolName: string, args: Record<string, unknown>, apiKey: string): Promise<string>;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) integration for Z.AI and MiniMax.
|
|
3
|
+
*
|
|
4
|
+
* Provides config discovery and API call helpers used by toolExecution.ts.
|
|
5
|
+
*/
|
|
6
|
+
import { config, getApiKey } from '../config/index.js';
|
|
7
|
+
import { getProviderMcpEndpoints, PROVIDERS } from '../config/providers.js';
|
|
8
|
+
// Z.AI MCP tool names (available when user has any Z.AI API key)
|
|
9
|
+
export const ZAI_MCP_TOOLS = ['web_search', 'web_read', 'github_read'];
|
|
10
|
+
// Z.AI provider IDs that have MCP endpoints
|
|
11
|
+
export const ZAI_PROVIDER_IDS = ['z.ai', 'z.ai-cn'];
|
|
12
|
+
// MiniMax MCP tool names (available when user has any MiniMax API key)
|
|
13
|
+
export const MINIMAX_MCP_TOOLS = ['minimax_web_search', 'minimax_understand_image'];
|
|
14
|
+
// MiniMax provider IDs
|
|
15
|
+
export const MINIMAX_PROVIDER_IDS = ['minimax', 'minimax-cn'];
|
|
16
|
+
/**
|
|
17
|
+
* Find a Z.AI provider that has an API key configured.
|
|
18
|
+
* Returns the provider ID and API key, or null if none found.
|
|
19
|
+
* Prefers the active provider if it's Z.AI, otherwise checks all Z.AI providers.
|
|
20
|
+
*/
|
|
21
|
+
export function getZaiMcpConfig() {
|
|
22
|
+
// First check if active provider is Z.AI
|
|
23
|
+
const activeProvider = config.get('provider');
|
|
24
|
+
if (ZAI_PROVIDER_IDS.includes(activeProvider)) {
|
|
25
|
+
const key = getApiKey(activeProvider);
|
|
26
|
+
const endpoints = getProviderMcpEndpoints(activeProvider);
|
|
27
|
+
if (key && endpoints?.webSearch && endpoints?.webReader && endpoints?.zread) {
|
|
28
|
+
return { providerId: activeProvider, apiKey: key, endpoints: endpoints };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Otherwise check all Z.AI providers for a configured key
|
|
32
|
+
for (const pid of ZAI_PROVIDER_IDS) {
|
|
33
|
+
const key = getApiKey(pid);
|
|
34
|
+
const endpoints = getProviderMcpEndpoints(pid);
|
|
35
|
+
if (key && endpoints?.webSearch && endpoints?.webReader && endpoints?.zread) {
|
|
36
|
+
return { providerId: pid, apiKey: key, endpoints: endpoints };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Check if Z.AI MCP tools are available (user has any Z.AI API key)
|
|
43
|
+
*/
|
|
44
|
+
export function hasZaiMcpAccess() {
|
|
45
|
+
return getZaiMcpConfig() !== null;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Find a MiniMax provider that has an API key configured.
|
|
49
|
+
* Returns the base host URL and API key, or null if none found.
|
|
50
|
+
*/
|
|
51
|
+
export function getMinimaxMcpConfig() {
|
|
52
|
+
// First check if active provider is MiniMax
|
|
53
|
+
const activeProvider = config.get('provider');
|
|
54
|
+
if (MINIMAX_PROVIDER_IDS.includes(activeProvider)) {
|
|
55
|
+
const key = getApiKey(activeProvider);
|
|
56
|
+
if (key) {
|
|
57
|
+
const provider = PROVIDERS[activeProvider];
|
|
58
|
+
const baseUrl = provider?.protocols?.openai?.baseUrl;
|
|
59
|
+
if (baseUrl) {
|
|
60
|
+
const host = baseUrl.replace(/\/v1\/?$/, '');
|
|
61
|
+
return { host, apiKey: key };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Otherwise check all MiniMax providers
|
|
66
|
+
for (const pid of MINIMAX_PROVIDER_IDS) {
|
|
67
|
+
const key = getApiKey(pid);
|
|
68
|
+
if (key) {
|
|
69
|
+
const provider = PROVIDERS[pid];
|
|
70
|
+
const baseUrl = provider?.protocols?.openai?.baseUrl;
|
|
71
|
+
if (baseUrl) {
|
|
72
|
+
const host = baseUrl.replace(/\/v1\/?$/, '');
|
|
73
|
+
return { host, apiKey: key };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if MiniMax MCP tools are available
|
|
81
|
+
*/
|
|
82
|
+
export function hasMinimaxMcpAccess() {
|
|
83
|
+
return getMinimaxMcpConfig() !== null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Call a MiniMax MCP REST API endpoint
|
|
87
|
+
*/
|
|
88
|
+
export async function callMinimaxApi(host, path, body, apiKey) {
|
|
89
|
+
const controller = new AbortController();
|
|
90
|
+
const timeout = setTimeout(() => controller.abort(), 60000);
|
|
91
|
+
try {
|
|
92
|
+
const response = await fetch(`${host}${path}`, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
headers: {
|
|
95
|
+
'Content-Type': 'application/json',
|
|
96
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify(body),
|
|
99
|
+
signal: controller.signal,
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
const errorText = await response.text().catch(() => '');
|
|
103
|
+
throw new Error(`MiniMax API error ${response.status}: ${errorText || response.statusText}`);
|
|
104
|
+
}
|
|
105
|
+
const data = await response.json();
|
|
106
|
+
if (data.content && Array.isArray(data.content)) {
|
|
107
|
+
return data.content.map((c) => c.text || '').join('\n');
|
|
108
|
+
}
|
|
109
|
+
return JSON.stringify(data);
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Call a Z.AI MCP endpoint via JSON-RPC 2.0
|
|
117
|
+
*/
|
|
118
|
+
export async function callZaiMcp(endpoint, toolName, args, apiKey) {
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const timeout = setTimeout(() => controller.abort(), 60000);
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch(endpoint, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: {
|
|
125
|
+
'Content-Type': 'application/json',
|
|
126
|
+
'Accept': 'application/json',
|
|
127
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
128
|
+
},
|
|
129
|
+
body: JSON.stringify({
|
|
130
|
+
jsonrpc: '2.0',
|
|
131
|
+
id: Date.now().toString(),
|
|
132
|
+
method: 'tools/call',
|
|
133
|
+
params: { name: toolName, arguments: args },
|
|
134
|
+
}),
|
|
135
|
+
signal: controller.signal,
|
|
136
|
+
});
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
const errorText = await response.text().catch(() => '');
|
|
139
|
+
throw new Error(`MCP error ${response.status}: ${errorText || response.statusText}`);
|
|
140
|
+
}
|
|
141
|
+
const data = await response.json();
|
|
142
|
+
if (data.error) {
|
|
143
|
+
throw new Error(data.error.message || JSON.stringify(data.error));
|
|
144
|
+
}
|
|
145
|
+
const result = data.result;
|
|
146
|
+
if (result && typeof result === 'object' && Array.isArray(result.content)) {
|
|
147
|
+
return result.content.map((c) => c.text || '').join('\n');
|
|
148
|
+
}
|
|
149
|
+
return typeof result === 'string' ? result : JSON.stringify(result);
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
clearTimeout(timeout);
|
|
153
|
+
}
|
|
154
|
+
}
|
package/dist/utils/project.js
CHANGED
|
@@ -57,9 +57,14 @@ export function isProjectDirectory(dir = process.cwd()) {
|
|
|
57
57
|
*/
|
|
58
58
|
export function getProjectType(dir = process.cwd()) {
|
|
59
59
|
if (existsSync(join(dir, 'package.json'))) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
try {
|
|
61
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'));
|
|
62
|
+
if (pkg.dependencies?.typescript || pkg.devDependencies?.typescript || existsSync(join(dir, 'tsconfig.json'))) {
|
|
63
|
+
return 'TypeScript/Node.js';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Corrupt package.json — fall through to return JavaScript/Node.js
|
|
63
68
|
}
|
|
64
69
|
return 'JavaScript/Node.js';
|
|
65
70
|
}
|
package/dist/utils/skills.js
CHANGED
|
@@ -671,9 +671,6 @@ export function parseSkillChain(input) {
|
|
|
671
671
|
*/
|
|
672
672
|
export function parseSkillArgs(args, skill) {
|
|
673
673
|
const result = {};
|
|
674
|
-
if (!args.trim()) {
|
|
675
|
-
return result;
|
|
676
|
-
}
|
|
677
674
|
// Pattern to match key=value or key="value with spaces" or just "value"
|
|
678
675
|
const keyValuePattern = /(\w+)=(?:"([^"]+)"|'([^']+)'|(\S+))/g;
|
|
679
676
|
const quotedPattern = /^["'](.+)["']$/;
|
|
@@ -710,20 +707,33 @@ export function parseSkillArgs(args, skill) {
|
|
|
710
707
|
}
|
|
711
708
|
/**
|
|
712
709
|
* Sanitize text for safe use inside shell commands.
|
|
713
|
-
* Strips markdown formatting and
|
|
710
|
+
* Strips markdown formatting and removes shell metacharacters to prevent
|
|
711
|
+
* command injection via $(), backtick subshells, semicolons, pipes, etc.
|
|
714
712
|
*/
|
|
715
713
|
function sanitizeForShell(text) {
|
|
716
|
-
|
|
714
|
+
const firstLine = text
|
|
717
715
|
// Strip markdown code blocks
|
|
718
716
|
.replace(/```[\s\S]*?```/g, '')
|
|
719
|
-
// Strip inline
|
|
720
|
-
.replace(/`
|
|
717
|
+
// Strip inline backtick code spans (remove content too, not just markers)
|
|
718
|
+
.replace(/`[^`]*`/g, '')
|
|
721
719
|
// Strip bold/italic markers
|
|
722
720
|
.replace(/\*{1,3}([^*]+)\*{1,3}/g, '$1')
|
|
723
|
-
// Take only the first non-empty line
|
|
724
|
-
.split('\n').map(l => l.trim()).filter(Boolean)[0] || text.trim()
|
|
725
|
-
|
|
726
|
-
|
|
721
|
+
// Take only the first non-empty line
|
|
722
|
+
.split('\n').map(l => l.trim()).filter(Boolean)[0] || text.trim();
|
|
723
|
+
return firstLine
|
|
724
|
+
// Remove $(...) subshell expansion
|
|
725
|
+
.replace(/\$\([^)]*\)/g, '')
|
|
726
|
+
// Remove ${...} variable/subshell expansion
|
|
727
|
+
.replace(/\$\{[^}]*\}/g, '')
|
|
728
|
+
// Remove bare $var variable references
|
|
729
|
+
.replace(/\$\w+/g, '')
|
|
730
|
+
// Remove command chaining operators
|
|
731
|
+
.replace(/[;|]/g, '')
|
|
732
|
+
// Remove newlines and null bytes
|
|
733
|
+
.replace(/[\n\r\0]/g, ' ')
|
|
734
|
+
// Escape double quotes for safe embedding in "..." shell strings
|
|
735
|
+
.replace(/"/g, '\\"')
|
|
736
|
+
.trim();
|
|
727
737
|
}
|
|
728
738
|
/**
|
|
729
739
|
* Interpolate parameters into skill step content
|
|
@@ -15,6 +15,10 @@ export interface SmartContextResult {
|
|
|
15
15
|
totalSize: number;
|
|
16
16
|
truncated: boolean;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Clear the import resolution cache (useful between invocations in tests).
|
|
20
|
+
*/
|
|
21
|
+
export declare function clearImportResolutionCache(): void;
|
|
18
22
|
/**
|
|
19
23
|
* Gather smart context for a target file or task
|
|
20
24
|
*/
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { existsSync, readFileSync, statSync } from 'fs';
|
|
5
5
|
import { join, dirname, basename, extname, relative } from 'path';
|
|
6
6
|
import { loadIgnoreRules, isIgnored } from './gitignore.js';
|
|
7
|
+
import { logger } from './logger.js';
|
|
7
8
|
// Max context size (characters)
|
|
8
9
|
const MAX_CONTEXT_SIZE = 50000;
|
|
9
10
|
const MAX_FILES = 15;
|
|
@@ -82,24 +83,44 @@ function extractImports(content, ext) {
|
|
|
82
83
|
}
|
|
83
84
|
return imports;
|
|
84
85
|
}
|
|
86
|
+
// Cache for resolveImportPath — avoids redundant disk lookups across import graphs
|
|
87
|
+
const importResolutionCache = new Map();
|
|
85
88
|
/**
|
|
86
|
-
* Resolve import path to actual file path
|
|
89
|
+
* Resolve import path to actual file path.
|
|
90
|
+
* Results are cached by (fromFile, importPath) to avoid O(n²) disk I/O.
|
|
87
91
|
*/
|
|
88
92
|
function resolveImportPath(importPath, fromFile, projectRoot) {
|
|
93
|
+
const cacheKey = `${fromFile}|${importPath}`;
|
|
94
|
+
if (importResolutionCache.has(cacheKey)) {
|
|
95
|
+
return importResolutionCache.get(cacheKey);
|
|
96
|
+
}
|
|
89
97
|
const fromDir = dirname(fromFile);
|
|
90
98
|
const ext = extname(fromFile);
|
|
99
|
+
let result;
|
|
91
100
|
// Skip external packages
|
|
92
101
|
if (!importPath.startsWith('.') && !importPath.startsWith('/')) {
|
|
93
102
|
// Could be a local alias like @/components
|
|
94
103
|
if (importPath.startsWith('@/') || importPath.startsWith('~/')) {
|
|
95
104
|
const aliasPath = importPath.replace(/^[@~]\//, 'src/');
|
|
96
|
-
|
|
105
|
+
result = resolveWithExtensions(join(projectRoot, aliasPath), ext);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
result = null;
|
|
97
109
|
}
|
|
98
|
-
return null;
|
|
99
110
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
else {
|
|
112
|
+
// Resolve relative path
|
|
113
|
+
const resolved = join(fromDir, importPath);
|
|
114
|
+
result = resolveWithExtensions(resolved, ext);
|
|
115
|
+
}
|
|
116
|
+
importResolutionCache.set(cacheKey, result);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Clear the import resolution cache (useful between invocations in tests).
|
|
121
|
+
*/
|
|
122
|
+
export function clearImportResolutionCache() {
|
|
123
|
+
importResolutionCache.clear();
|
|
103
124
|
}
|
|
104
125
|
/**
|
|
105
126
|
* Try to resolve path with various extensions
|
|
@@ -167,7 +188,9 @@ function findRelatedByNaming(filePath, projectRoot) {
|
|
|
167
188
|
size: stat.size,
|
|
168
189
|
});
|
|
169
190
|
}
|
|
170
|
-
catch {
|
|
191
|
+
catch (err) {
|
|
192
|
+
logger.debug('smartContext: statSync failed for main file', { path: basePath, err: String(err) });
|
|
193
|
+
}
|
|
171
194
|
}
|
|
172
195
|
}
|
|
173
196
|
}
|
|
@@ -185,7 +208,9 @@ function findRelatedByNaming(filePath, projectRoot) {
|
|
|
185
208
|
size: stat.size,
|
|
186
209
|
});
|
|
187
210
|
}
|
|
188
|
-
catch {
|
|
211
|
+
catch (err) {
|
|
212
|
+
logger.debug('smartContext: statSync failed for related file', { path: relatedPath, err: String(err) });
|
|
213
|
+
}
|
|
189
214
|
}
|
|
190
215
|
}
|
|
191
216
|
return related;
|
|
@@ -217,7 +242,9 @@ function findTypeDefinitions(projectRoot, imports) {
|
|
|
217
242
|
size: stat.size,
|
|
218
243
|
});
|
|
219
244
|
}
|
|
220
|
-
catch {
|
|
245
|
+
catch (err) {
|
|
246
|
+
logger.debug('smartContext: statSync failed for type definition', { path: fullPath, err: String(err) });
|
|
247
|
+
}
|
|
221
248
|
}
|
|
222
249
|
}
|
|
223
250
|
return related;
|
|
@@ -250,7 +277,9 @@ function findConfigFiles(projectRoot) {
|
|
|
250
277
|
size: stat.size,
|
|
251
278
|
});
|
|
252
279
|
}
|
|
253
|
-
catch {
|
|
280
|
+
catch (err) {
|
|
281
|
+
logger.debug('smartContext: statSync failed for config file', { path: fullPath, err: String(err) });
|
|
282
|
+
}
|
|
254
283
|
}
|
|
255
284
|
}
|
|
256
285
|
return related;
|
|
@@ -294,7 +323,9 @@ export function gatherSmartContext(targetFile, projectContext, taskDescription)
|
|
|
294
323
|
size: impStat.size,
|
|
295
324
|
});
|
|
296
325
|
}
|
|
297
|
-
catch {
|
|
326
|
+
catch (err) {
|
|
327
|
+
logger.debug('smartContext: statSync failed for import', { path: resolved, err: String(err) });
|
|
328
|
+
}
|
|
298
329
|
}
|
|
299
330
|
}
|
|
300
331
|
// Find related by naming
|
|
@@ -305,7 +336,9 @@ export function gatherSmartContext(targetFile, projectContext, taskDescription)
|
|
|
305
336
|
}
|
|
306
337
|
}
|
|
307
338
|
}
|
|
308
|
-
catch {
|
|
339
|
+
catch (err) {
|
|
340
|
+
logger.debug('smartContext: failed to process target file', { path: targetPath, err: String(err) });
|
|
341
|
+
}
|
|
309
342
|
}
|
|
310
343
|
}
|
|
311
344
|
// Find type definitions
|
|
@@ -360,7 +393,9 @@ export function gatherSmartContext(targetFile, projectContext, taskDescription)
|
|
|
360
393
|
truncated = true;
|
|
361
394
|
}
|
|
362
395
|
}
|
|
363
|
-
catch {
|
|
396
|
+
catch (err) {
|
|
397
|
+
logger.debug('smartContext: readFileSync failed for context file', { path: file.path, err: String(err) });
|
|
398
|
+
}
|
|
364
399
|
}
|
|
365
400
|
else if (file.content) {
|
|
366
401
|
totalSize += file.content.length;
|
|
@@ -400,7 +435,9 @@ function extractMentionedFiles(task, projectRoot) {
|
|
|
400
435
|
});
|
|
401
436
|
}
|
|
402
437
|
}
|
|
403
|
-
catch {
|
|
438
|
+
catch (err) {
|
|
439
|
+
logger.debug('smartContext: statSync failed for mentioned file', { path: fullPath, err: String(err) });
|
|
440
|
+
}
|
|
404
441
|
}
|
|
405
442
|
}
|
|
406
443
|
return related;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool execution - runs agent tool calls against the filesystem and shell.
|
|
3
|
+
*
|
|
4
|
+
* validatePath() ensures all file operations stay within the project root.
|
|
5
|
+
* executeTool() dispatches to individual tool handlers.
|
|
6
|
+
* listDirectory() and htmlToText() are private helpers.
|
|
7
|
+
* createActionLog() converts a ToolCall+ToolResult into a history ActionLog.
|
|
8
|
+
*/
|
|
9
|
+
import { ToolCall, ToolResult, ActionLog } from './tools';
|
|
10
|
+
/**
|
|
11
|
+
* Validate path is within project root.
|
|
12
|
+
* Uses realpathSync to resolve symlinks, preventing symlink traversal attacks
|
|
13
|
+
* where a symlink inside the project could point to files outside it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validatePath(path: string, projectRoot: string): {
|
|
16
|
+
valid: boolean;
|
|
17
|
+
absolutePath: string;
|
|
18
|
+
error?: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Execute a tool call and return the result.
|
|
22
|
+
*/
|
|
23
|
+
export declare function executeTool(toolCall: ToolCall, projectRoot: string): Promise<ToolResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Create action log from tool result
|
|
26
|
+
*/
|
|
27
|
+
export declare function createActionLog(toolCall: ToolCall, result: ToolResult): ActionLog;
|