aiexecode 1.0.157
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/LICENSE +68 -0
- package/README.md +347 -0
- package/config_template/mcp_config.json +3 -0
- package/config_template/package_name_store.json +5 -0
- package/config_template/settings.json +5 -0
- package/index.js +879 -0
- package/mcp-agent-lib/example/01-basic-usage.js +82 -0
- package/mcp-agent-lib/example/02-quick-start.js +52 -0
- package/mcp-agent-lib/example/03-http-server.js +76 -0
- package/mcp-agent-lib/example/04-multiple-servers.js +117 -0
- package/mcp-agent-lib/example/05-error-handling.js +116 -0
- package/mcp-agent-lib/example/06-resources-and-prompts.js +174 -0
- package/mcp-agent-lib/example/07-advanced-configuration.js +191 -0
- package/mcp-agent-lib/example/08-real-world-chatbot.js +331 -0
- package/mcp-agent-lib/example/README.md +346 -0
- package/mcp-agent-lib/index.js +19 -0
- package/mcp-agent-lib/init.sh +3 -0
- package/mcp-agent-lib/package-lock.json +1216 -0
- package/mcp-agent-lib/package.json +53 -0
- package/mcp-agent-lib/sampleFastMCPClient/client.py +25 -0
- package/mcp-agent-lib/sampleFastMCPClient/run.sh +3 -0
- package/mcp-agent-lib/sampleFastMCPServer/run.sh +3 -0
- package/mcp-agent-lib/sampleFastMCPServer/server.py +12 -0
- package/mcp-agent-lib/sampleFastMCPServerElicitationRequest/run.sh +3 -0
- package/mcp-agent-lib/sampleFastMCPServerElicitationRequest/server.py +43 -0
- package/mcp-agent-lib/sampleFastMCPServerRootsRequest/server.py +63 -0
- package/mcp-agent-lib/sampleMCPHost/index.js +386 -0
- package/mcp-agent-lib/sampleMCPHost/mcp_config.json +24 -0
- package/mcp-agent-lib/sampleMCPHostFeatures/elicitation.js +151 -0
- package/mcp-agent-lib/sampleMCPHostFeatures/index.js +166 -0
- package/mcp-agent-lib/sampleMCPHostFeatures/roots.js +197 -0
- package/mcp-agent-lib/src/mcp_client.js +1860 -0
- package/mcp-agent-lib/src/mcp_message_logger.js +517 -0
- package/package.json +72 -0
- package/payload_viewer/out/404/index.html +1 -0
- package/payload_viewer/out/404.html +1 -0
- package/payload_viewer/out/_next/static/chunks/060f9a97930f3d04.js +1 -0
- package/payload_viewer/out/_next/static/chunks/103c802c8f4a5ea1.js +1 -0
- package/payload_viewer/out/_next/static/chunks/16474fd6c6910c45.js +1 -0
- package/payload_viewer/out/_next/static/chunks/17722e3ac4e00587.js +1 -0
- package/payload_viewer/out/_next/static/chunks/305b077a9873cf54.js +1 -0
- package/payload_viewer/out/_next/static/chunks/4c1d05c6741c2bdd.js +5 -0
- package/payload_viewer/out/_next/static/chunks/538cc02e54714b23.js +1 -0
- package/payload_viewer/out/_next/static/chunks/6251fa5907d2b226.js +5 -0
- package/payload_viewer/out/_next/static/chunks/a6dad97d9634a72d.js +1 -0
- package/payload_viewer/out/_next/static/chunks/b6c0459f3789d25c.js +1 -0
- package/payload_viewer/out/_next/static/chunks/b75131b58f8ca46a.css +3 -0
- package/payload_viewer/out/_next/static/chunks/bd2dcf98c9b362f6.js +1 -0
- package/payload_viewer/out/_next/static/chunks/c8a542ae21335479.js +1 -0
- package/payload_viewer/out/_next/static/chunks/cdd12d5c1a5a6064.js +1 -0
- package/payload_viewer/out/_next/static/chunks/e411019f55d87c42.js +1 -0
- package/payload_viewer/out/_next/static/chunks/e60ef129113f6e24.js +1 -0
- package/payload_viewer/out/_next/static/chunks/f1ac9047ac4a3fde.js +1 -0
- package/payload_viewer/out/_next/static/chunks/turbopack-0ac29803ce3c3c7a.js +3 -0
- package/payload_viewer/out/_next/static/chunks/turbopack-89db4c64206a73e4.js +3 -0
- package/payload_viewer/out/_next/static/chunks/turbopack-a5b8235fa59d7119.js +3 -0
- package/payload_viewer/out/_next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
- package/payload_viewer/out/_next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
- package/payload_viewer/out/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
- package/payload_viewer/out/_next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
- package/payload_viewer/out/_next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
- package/payload_viewer/out/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
- package/payload_viewer/out/_next/static/media/favicon.0b3bf435.ico +0 -0
- package/payload_viewer/out/_next/static/uqQYtKpKV7kCSkUbLgdfJ/_buildManifest.js +14 -0
- package/payload_viewer/out/_next/static/uqQYtKpKV7kCSkUbLgdfJ/_clientMiddlewareManifest.json +1 -0
- package/payload_viewer/out/_next/static/uqQYtKpKV7kCSkUbLgdfJ/_ssgManifest.js +1 -0
- package/payload_viewer/out/favicon.ico +0 -0
- package/payload_viewer/out/file.svg +1 -0
- package/payload_viewer/out/globe.svg +1 -0
- package/payload_viewer/out/index.html +1 -0
- package/payload_viewer/out/index.txt +23 -0
- package/payload_viewer/out/next.svg +1 -0
- package/payload_viewer/out/vercel.svg +1 -0
- package/payload_viewer/out/window.svg +1 -0
- package/payload_viewer/web_server.js +861 -0
- package/prompts/completion_judge.txt +128 -0
- package/prompts/orchestrator.txt +1213 -0
- package/src/LLMClient/client.js +1375 -0
- package/src/LLMClient/converters/input-normalizer.js +238 -0
- package/src/LLMClient/converters/responses-to-claude.js +503 -0
- package/src/LLMClient/converters/responses-to-gemini.js +648 -0
- package/src/LLMClient/converters/responses-to-ollama.js +348 -0
- package/src/LLMClient/converters/responses-to-zai.js +667 -0
- package/src/LLMClient/errors.js +398 -0
- package/src/LLMClient/index.js +36 -0
- package/src/ai_based/completion_judge.js +421 -0
- package/src/ai_based/orchestrator.js +527 -0
- package/src/ai_based/pip_package_installer.js +173 -0
- package/src/ai_based/pip_package_lookup.js +197 -0
- package/src/cli/mcp_cli.js +70 -0
- package/src/cli/mcp_commands.js +255 -0
- package/src/commands/agents.js +18 -0
- package/src/commands/apikey.js +55 -0
- package/src/commands/bg.js +140 -0
- package/src/commands/commands.js +56 -0
- package/src/commands/debug.js +54 -0
- package/src/commands/exit.js +19 -0
- package/src/commands/help.js +35 -0
- package/src/commands/mcp.js +128 -0
- package/src/commands/model.js +176 -0
- package/src/commands/setup.js +13 -0
- package/src/commands/skills.js +51 -0
- package/src/commands/tools.js +165 -0
- package/src/commands/viewer.js +147 -0
- package/src/config/ai_models.js +312 -0
- package/src/config/config.js +10 -0
- package/src/config/constants.js +71 -0
- package/src/config/feature_flags.js +15 -0
- package/src/frontend/App.js +1263 -0
- package/src/frontend/README.md +81 -0
- package/src/frontend/components/AutocompleteMenu.js +47 -0
- package/src/frontend/components/BackgroundProcessList.js +175 -0
- package/src/frontend/components/BlankLine.js +62 -0
- package/src/frontend/components/ConversationItem.js +893 -0
- package/src/frontend/components/CurrentModelView.js +43 -0
- package/src/frontend/components/FileDiffViewer.js +616 -0
- package/src/frontend/components/Footer.js +25 -0
- package/src/frontend/components/Header.js +42 -0
- package/src/frontend/components/HelpView.js +154 -0
- package/src/frontend/components/Input.js +344 -0
- package/src/frontend/components/LoadingIndicator.js +31 -0
- package/src/frontend/components/ModelListView.js +49 -0
- package/src/frontend/components/ModelUpdatedView.js +22 -0
- package/src/frontend/components/SessionSpinner.js +66 -0
- package/src/frontend/components/SetupWizard.js +242 -0
- package/src/frontend/components/StreamOutput.js +34 -0
- package/src/frontend/components/TodoList.js +56 -0
- package/src/frontend/components/ToolApprovalPrompt.js +452 -0
- package/src/frontend/design/themeColors.js +42 -0
- package/src/frontend/hooks/useCompletion.js +84 -0
- package/src/frontend/hooks/useFileCompletion.js +467 -0
- package/src/frontend/hooks/useKeypress.js +145 -0
- package/src/frontend/index.js +65 -0
- package/src/frontend/utils/GridRenderer.js +140 -0
- package/src/frontend/utils/InlineFormatter.js +156 -0
- package/src/frontend/utils/diffUtils.js +235 -0
- package/src/frontend/utils/inputBuffer.js +441 -0
- package/src/frontend/utils/markdownParser.js +377 -0
- package/src/frontend/utils/outputRedirector.js +47 -0
- package/src/frontend/utils/renderInkComponent.js +42 -0
- package/src/frontend/utils/syntaxHighlighter.js +149 -0
- package/src/frontend/utils/toolUIFormatter.js +261 -0
- package/src/system/agents_loader.js +170 -0
- package/src/system/ai_request.js +737 -0
- package/src/system/background_process.js +317 -0
- package/src/system/code_executer.js +1233 -0
- package/src/system/command_loader.js +40 -0
- package/src/system/command_parser.js +133 -0
- package/src/system/conversation_state.js +265 -0
- package/src/system/conversation_trimmer.js +265 -0
- package/src/system/custom_command_loader.js +395 -0
- package/src/system/file_integrity.js +466 -0
- package/src/system/import_analyzer.py +174 -0
- package/src/system/log.js +82 -0
- package/src/system/mcp_integration.js +304 -0
- package/src/system/output_helper.js +89 -0
- package/src/system/session.js +1393 -0
- package/src/system/session_memory.js +481 -0
- package/src/system/skill_loader.js +324 -0
- package/src/system/system_info.js +483 -0
- package/src/system/tool_approval.js +160 -0
- package/src/system/tool_registry.js +184 -0
- package/src/system/ui_events.js +279 -0
- package/src/tools/code_editor.js +792 -0
- package/src/tools/file_reader.js +385 -0
- package/src/tools/glob.js +263 -0
- package/src/tools/response_message.js +30 -0
- package/src/tools/ripgrep.js +554 -0
- package/src/tools/skill_tool.js +122 -0
- package/src/tools/todo_write.js +182 -0
- package/src/tools/web_download.py +74 -0
- package/src/tools/web_downloader.js +83 -0
- package/src/util/clone.js +174 -0
- package/src/util/config.js +203 -0
- package/src/util/config_migration.js +174 -0
- package/src/util/debug_log.js +49 -0
- package/src/util/exit_handler.js +53 -0
- package/src/util/file_reference_parser.js +132 -0
- package/src/util/mcp_config_manager.js +159 -0
- package/src/util/output_formatter.js +50 -0
- package/src/util/path_helper.js +27 -0
- package/src/util/path_validator.js +178 -0
- package/src/util/prompt_loader.js +184 -0
- package/src/util/rag_helper.js +101 -0
- package/src/util/safe_fs.js +645 -0
- package/src/util/setup_wizard.js +62 -0
- package/src/util/text_formatter.js +33 -0
- package/src/util/version_check.js +116 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool UI Formatter
|
|
3
|
+
* 도구 스키마에서 UI 포맷팅 로직을 분리하여 tools → frontend 의존성을 제거합니다.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { theme } from '../design/themeColors.js';
|
|
7
|
+
import { toDisplayPath } from '../../util/path_helper.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 도구별 UI 포맷터 정의
|
|
11
|
+
* 각 도구의 ui_display 설정을 중앙에서 관리합니다.
|
|
12
|
+
*/
|
|
13
|
+
export const toolUIFormatters = {
|
|
14
|
+
// ============================================
|
|
15
|
+
// File Reader
|
|
16
|
+
// ============================================
|
|
17
|
+
read_file: {
|
|
18
|
+
show_tool_call: true,
|
|
19
|
+
show_tool_result: true,
|
|
20
|
+
display_name: 'Read',
|
|
21
|
+
format_tool_call: (args) => {
|
|
22
|
+
return `(${toDisplayPath(args.filePath)})`;
|
|
23
|
+
},
|
|
24
|
+
format_tool_result: (result) => {
|
|
25
|
+
if (result.operation_successful) {
|
|
26
|
+
const lines = result.total_line_count || 0;
|
|
27
|
+
return {
|
|
28
|
+
type: 'formatted',
|
|
29
|
+
parts: [
|
|
30
|
+
{ text: 'Read ', style: {} },
|
|
31
|
+
{ text: String(lines), style: { color: theme.brand.light, bold: true } },
|
|
32
|
+
{ text: ` line${lines !== 1 ? 's' : ''}`, style: {} }
|
|
33
|
+
]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return result.error_message || 'Error reading file';
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
read_file_range: {
|
|
41
|
+
show_tool_call: true,
|
|
42
|
+
show_tool_result: true,
|
|
43
|
+
display_name: 'Read',
|
|
44
|
+
format_tool_call: (args) => {
|
|
45
|
+
return `(${toDisplayPath(args.filePath)}, lines ${args.startLine}-${args.endLine})`;
|
|
46
|
+
},
|
|
47
|
+
format_tool_result: (result) => {
|
|
48
|
+
if (result.operation_successful) {
|
|
49
|
+
const lineCount = result.file_content ? result.file_content.split('\n').length : 0;
|
|
50
|
+
return {
|
|
51
|
+
type: 'formatted',
|
|
52
|
+
parts: [
|
|
53
|
+
{ text: 'Read ', style: {} },
|
|
54
|
+
{ text: String(lineCount), style: { color: theme.brand.light, bold: true } },
|
|
55
|
+
{ text: ` line${lineCount !== 1 ? 's' : ''}`, style: {} }
|
|
56
|
+
]
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return result.error_message || 'Error reading file';
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// ============================================
|
|
64
|
+
// Code Editor
|
|
65
|
+
// ============================================
|
|
66
|
+
write_file: {
|
|
67
|
+
show_tool_call: true,
|
|
68
|
+
show_tool_result: true,
|
|
69
|
+
display_name: 'Write',
|
|
70
|
+
format_tool_call: (args) => {
|
|
71
|
+
return `(${toDisplayPath(args.file_path)})`;
|
|
72
|
+
},
|
|
73
|
+
format_tool_result: (result) => {
|
|
74
|
+
if (result.operation_successful) {
|
|
75
|
+
const lines = result.total_line_count || 0;
|
|
76
|
+
const action = result.file_existed ? 'Overwrote' : 'Created';
|
|
77
|
+
return {
|
|
78
|
+
type: 'formatted',
|
|
79
|
+
parts: [
|
|
80
|
+
{ text: `${action} `, style: {} },
|
|
81
|
+
{ text: String(lines), style: { color: theme.brand.light, bold: true } },
|
|
82
|
+
{ text: ` line${lines !== 1 ? 's' : ''}`, style: {} }
|
|
83
|
+
]
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return result.error_message || 'Error writing file';
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
edit_file_replace: {
|
|
91
|
+
show_tool_call: true,
|
|
92
|
+
show_tool_result: true,
|
|
93
|
+
display_name: 'Replace',
|
|
94
|
+
format_tool_call: (args) => {
|
|
95
|
+
return `(${toDisplayPath(args.file_path)})`;
|
|
96
|
+
},
|
|
97
|
+
format_tool_result: (result) => {
|
|
98
|
+
if (result.operation_successful) {
|
|
99
|
+
const count = result.replacement_count || 0;
|
|
100
|
+
return {
|
|
101
|
+
type: 'formatted',
|
|
102
|
+
parts: [
|
|
103
|
+
{ text: 'Replaced ', style: {} },
|
|
104
|
+
{ text: String(count), style: { color: theme.brand.light, bold: true } },
|
|
105
|
+
{ text: ` occurrence${count !== 1 ? 's' : ''}`, style: {} }
|
|
106
|
+
]
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return result.error_message || 'Error replacing string';
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
edit_file_range: {
|
|
114
|
+
show_tool_call: true,
|
|
115
|
+
show_tool_result: true,
|
|
116
|
+
display_name: 'Edit',
|
|
117
|
+
format_tool_call: (args) => {
|
|
118
|
+
return `(${toDisplayPath(args.file_path)}, lines ${args.start_line}-${args.end_line})`;
|
|
119
|
+
},
|
|
120
|
+
format_tool_result: (result) => {
|
|
121
|
+
if (result.operation_successful) {
|
|
122
|
+
const op = result.operation_type;
|
|
123
|
+
if (op === 'delete') {
|
|
124
|
+
return `Deleted lines`;
|
|
125
|
+
} else if (op === 'insert') {
|
|
126
|
+
return `Inserted lines`;
|
|
127
|
+
} else {
|
|
128
|
+
return `Replaced lines`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return result.error_message || 'Error editing file';
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// ============================================
|
|
136
|
+
// Search Tools
|
|
137
|
+
// ============================================
|
|
138
|
+
glob_search: {
|
|
139
|
+
show_tool_call: true,
|
|
140
|
+
show_tool_result: true,
|
|
141
|
+
display_name: 'Search',
|
|
142
|
+
format_tool_call: (args) => {
|
|
143
|
+
const pattern = args.pattern || '';
|
|
144
|
+
return `(${pattern})`;
|
|
145
|
+
},
|
|
146
|
+
format_tool_result: (result) => {
|
|
147
|
+
if (result.operation_successful) {
|
|
148
|
+
const matches = result.total_matches || 0;
|
|
149
|
+
return {
|
|
150
|
+
type: 'formatted',
|
|
151
|
+
parts: [
|
|
152
|
+
{ text: 'Found ', style: {} },
|
|
153
|
+
{ text: String(matches), style: { color: theme.brand.light, bold: true } },
|
|
154
|
+
{ text: ` match${matches !== 1 ? 'es' : ''}`, style: {} }
|
|
155
|
+
]
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return result.error_message || 'Search failed';
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
ripgrep: {
|
|
163
|
+
show_tool_call: true,
|
|
164
|
+
show_tool_result: true,
|
|
165
|
+
display_name: 'Grep',
|
|
166
|
+
format_tool_call: (args) => {
|
|
167
|
+
const pattern = args.pattern || '';
|
|
168
|
+
const shortened = pattern.length > 30 ? pattern.substring(0, 27) + '...' : pattern;
|
|
169
|
+
return `(${shortened})`;
|
|
170
|
+
},
|
|
171
|
+
format_tool_result: (result) => {
|
|
172
|
+
if (result.operation_successful) {
|
|
173
|
+
const matches = result.totalMatches || 0;
|
|
174
|
+
return {
|
|
175
|
+
type: 'formatted',
|
|
176
|
+
parts: [
|
|
177
|
+
{ text: 'Found ', style: {} },
|
|
178
|
+
{ text: String(matches), style: { color: theme.brand.light, bold: true } },
|
|
179
|
+
{ text: ` match${matches !== 1 ? 'es' : ''}`, style: {} }
|
|
180
|
+
]
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return result.error_message || 'Search failed';
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
// ============================================
|
|
188
|
+
// Web Downloader
|
|
189
|
+
// ============================================
|
|
190
|
+
fetch_web_page: {
|
|
191
|
+
show_tool_call: true,
|
|
192
|
+
show_tool_result: true,
|
|
193
|
+
display_name: 'Fetch',
|
|
194
|
+
format_tool_call: (args) => {
|
|
195
|
+
const url = args.url || '';
|
|
196
|
+
const shortened = url.length > 50 ? url.substring(0, 47) + '...' : url;
|
|
197
|
+
return `(${shortened})`;
|
|
198
|
+
},
|
|
199
|
+
format_tool_result: (result) => {
|
|
200
|
+
if (result.operation_successful) {
|
|
201
|
+
const contentLength = result.content?.length || 0;
|
|
202
|
+
return {
|
|
203
|
+
type: 'formatted',
|
|
204
|
+
parts: [
|
|
205
|
+
{ text: 'Fetched ', style: {} },
|
|
206
|
+
{ text: String(contentLength), style: { color: theme.brand.light, bold: true } },
|
|
207
|
+
{ text: ' characters', style: {} }
|
|
208
|
+
]
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return result.error_message || 'Fetch failed';
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* 도구 이름으로 UI 포맷터를 가져옵니다.
|
|
218
|
+
* @param {string} toolName - 도구 이름
|
|
219
|
+
* @returns {Object|null} UI 포맷터 또는 null
|
|
220
|
+
*/
|
|
221
|
+
export function getToolUIFormatter(toolName) {
|
|
222
|
+
return toolUIFormatters[toolName] || null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 도구 호출을 포맷팅합니다.
|
|
227
|
+
* @param {string} toolName - 도구 이름
|
|
228
|
+
* @param {Object} args - 도구 인자
|
|
229
|
+
* @returns {string} 포맷팅된 문자열
|
|
230
|
+
*/
|
|
231
|
+
export function formatToolCall(toolName, args) {
|
|
232
|
+
const formatter = getToolUIFormatter(toolName);
|
|
233
|
+
if (formatter && formatter.format_tool_call) {
|
|
234
|
+
return formatter.format_tool_call(args);
|
|
235
|
+
}
|
|
236
|
+
return `(${JSON.stringify(args)})`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 도구 결과를 포맷팅합니다.
|
|
241
|
+
* @param {string} toolName - 도구 이름
|
|
242
|
+
* @param {Object} result - 도구 실행 결과
|
|
243
|
+
* @returns {string|Object} 포맷팅된 결과
|
|
244
|
+
*/
|
|
245
|
+
export function formatToolResult(toolName, result) {
|
|
246
|
+
const formatter = getToolUIFormatter(toolName);
|
|
247
|
+
if (formatter && formatter.format_tool_result) {
|
|
248
|
+
return formatter.format_tool_result(result);
|
|
249
|
+
}
|
|
250
|
+
return result.operation_successful ? 'Success' : (result.error_message || 'Error');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* 도구의 표시 이름을 가져옵니다.
|
|
255
|
+
* @param {string} toolName - 도구 이름
|
|
256
|
+
* @returns {string} 표시 이름
|
|
257
|
+
*/
|
|
258
|
+
export function getToolDisplayName(toolName) {
|
|
259
|
+
const formatter = getToolUIFormatter(toolName);
|
|
260
|
+
return formatter?.display_name || toolName;
|
|
261
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AGENTS.md Loader
|
|
3
|
+
*
|
|
4
|
+
* AGENTS.md는 AI 코딩 에이전트를 위한 오픈 표준 포맷입니다.
|
|
5
|
+
* README.md가 인간을 위한 것이라면, AGENTS.md는 AI 에이전트를 위한 것입니다.
|
|
6
|
+
*
|
|
7
|
+
* 파일 위치:
|
|
8
|
+
* - CWD/AGENTS.md - 작업 디렉토리 루트에만 위치
|
|
9
|
+
* - 시스템 프롬프트에 포함됨
|
|
10
|
+
*
|
|
11
|
+
* 참조: https://agents.md/
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
import { safeReadFile, safeAccess, safeStat } from '../util/safe_fs.js';
|
|
16
|
+
import { createDebugLogger } from '../util/debug_log.js';
|
|
17
|
+
|
|
18
|
+
const debugLog = createDebugLogger('agents_loader.log', 'agents_loader');
|
|
19
|
+
|
|
20
|
+
// AGENTS.md 파일명 (대소문자 구분)
|
|
21
|
+
const AGENTS_MD_FILENAME = 'AGENTS.md';
|
|
22
|
+
|
|
23
|
+
// 권장 최대 줄 수 (GitHub 분석 기반)
|
|
24
|
+
const RECOMMENDED_MAX_LINES = 150;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 파일이 존재하는지 확인합니다.
|
|
28
|
+
* @param {string} filePath - 확인할 파일 경로
|
|
29
|
+
* @returns {Promise<boolean>}
|
|
30
|
+
*/
|
|
31
|
+
async function fileExists(filePath) {
|
|
32
|
+
try {
|
|
33
|
+
await safeAccess(filePath);
|
|
34
|
+
const stat = await safeStat(filePath);
|
|
35
|
+
return stat.isFile();
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* AGENTS.md 파일을 로드합니다.
|
|
43
|
+
* @param {string} filePath - AGENTS.md 파일 경로
|
|
44
|
+
* @returns {Promise<{path: string, content: string}|null>}
|
|
45
|
+
*/
|
|
46
|
+
async function loadAgentsMd(filePath) {
|
|
47
|
+
try {
|
|
48
|
+
if (!await fileExists(filePath)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const content = await safeReadFile(filePath, 'utf8');
|
|
52
|
+
const trimmedContent = content.trim();
|
|
53
|
+
const lineCount = trimmedContent.split('\n').length;
|
|
54
|
+
|
|
55
|
+
debugLog(`[loadAgentsMd] Loaded: ${filePath} (${trimmedContent.length} chars, ${lineCount} lines)`);
|
|
56
|
+
|
|
57
|
+
// 권장 크기 초과 시 경고
|
|
58
|
+
if (lineCount > RECOMMENDED_MAX_LINES) {
|
|
59
|
+
debugLog(`[loadAgentsMd] WARNING: ${filePath} has ${lineCount} lines (recommended: <=${RECOMMENDED_MAX_LINES})`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
path: filePath,
|
|
64
|
+
content: trimmedContent,
|
|
65
|
+
lineCount
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
debugLog(`[loadAgentsMd] Error loading ${filePath}: ${error.message}`);
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 작업 디렉토리 루트의 AGENTS.md 파일을 로드합니다.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} [cwd] - 현재 작업 디렉토리 (기본: process.cwd())
|
|
77
|
+
* @returns {Promise<{path: string, content: string, lineCount: number}|null>}
|
|
78
|
+
*/
|
|
79
|
+
export async function loadProjectAgentsMd(cwd = process.cwd()) {
|
|
80
|
+
debugLog(`[loadProjectAgentsMd] Loading from: ${cwd}`);
|
|
81
|
+
|
|
82
|
+
const agentsMd = await loadAgentsMd(join(cwd, AGENTS_MD_FILENAME));
|
|
83
|
+
if (agentsMd) {
|
|
84
|
+
debugLog(`[loadProjectAgentsMd] Found AGENTS.md`);
|
|
85
|
+
return agentsMd;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
debugLog(`[loadProjectAgentsMd] No AGENTS.md found`);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* AGENTS.md 내용을 시스템 프롬프트용 텍스트로 포맷팅합니다.
|
|
94
|
+
* @param {{path: string, content: string}|null} agentsMd
|
|
95
|
+
* @returns {string}
|
|
96
|
+
*/
|
|
97
|
+
export function formatAgentsMdForPrompt(agentsMd) {
|
|
98
|
+
if (!agentsMd) {
|
|
99
|
+
return '';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return `\n\n# Agent Instructions (AGENTS.md)\n\n` +
|
|
103
|
+
`The following instructions are from AGENTS.md in the project root.\n` +
|
|
104
|
+
`These provide project-specific guidance for AI coding agents.\n\n` +
|
|
105
|
+
`${agentsMd.content}\n`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 현재 프로젝트의 AGENTS.md를 로드하고 포맷팅합니다.
|
|
110
|
+
* 시스템 프롬프트에 추가할 때 사용
|
|
111
|
+
*
|
|
112
|
+
* @param {string} [cwd] - 현재 작업 디렉토리
|
|
113
|
+
* @returns {Promise<string>} 포맷팅된 AGENTS.md 내용 (없으면 빈 문자열)
|
|
114
|
+
*/
|
|
115
|
+
export async function loadAgentsMdForPrompt(cwd = process.cwd()) {
|
|
116
|
+
const agentsMd = await loadProjectAgentsMd(cwd);
|
|
117
|
+
return formatAgentsMdForPrompt(agentsMd);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* AGENTS.md 정보를 요약하여 반환합니다.
|
|
122
|
+
* /agents 명령어용
|
|
123
|
+
*
|
|
124
|
+
* @param {string} [cwd] - 현재 작업 디렉토리
|
|
125
|
+
* @returns {Promise<string>}
|
|
126
|
+
*/
|
|
127
|
+
export async function formatAgentsMdSummary(cwd = process.cwd()) {
|
|
128
|
+
const agentsMd = await loadProjectAgentsMd(cwd);
|
|
129
|
+
|
|
130
|
+
if (!agentsMd) {
|
|
131
|
+
return [
|
|
132
|
+
'No AGENTS.md file found.',
|
|
133
|
+
'',
|
|
134
|
+
'AGENTS.md is an open standard for guiding AI coding agents.',
|
|
135
|
+
'',
|
|
136
|
+
'File location:',
|
|
137
|
+
' CWD/AGENTS.md - Project root (included in system prompt)',
|
|
138
|
+
'',
|
|
139
|
+
'Create an AGENTS.md file to provide project-specific instructions.',
|
|
140
|
+
'',
|
|
141
|
+
'Recommended sections:',
|
|
142
|
+
' - Commands (build, test)',
|
|
143
|
+
' - Testing guidelines',
|
|
144
|
+
' - Project structure',
|
|
145
|
+
' - Code style',
|
|
146
|
+
' - Git workflow',
|
|
147
|
+
' - Boundaries (what not to touch)',
|
|
148
|
+
'',
|
|
149
|
+
'Learn more: https://agents.md/'
|
|
150
|
+
].join('\n');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const lineCount = agentsMd.lineCount || agentsMd.content.split('\n').length;
|
|
154
|
+
const charCount = agentsMd.content.length;
|
|
155
|
+
const sizeWarning = lineCount > RECOMMENDED_MAX_LINES
|
|
156
|
+
? ` (exceeds recommended ${RECOMMENDED_MAX_LINES} lines)`
|
|
157
|
+
: '';
|
|
158
|
+
|
|
159
|
+
const lines = [
|
|
160
|
+
'AGENTS.md:',
|
|
161
|
+
'',
|
|
162
|
+
` Path: ${agentsMd.path}`,
|
|
163
|
+
` Size: ${lineCount} lines, ${charCount} chars${sizeWarning}`,
|
|
164
|
+
'',
|
|
165
|
+
' Content:',
|
|
166
|
+
' ' + agentsMd.content.replace(/\n/g, '\n '),
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
return lines.join('\n');
|
|
170
|
+
}
|