aiexecode 1.0.66 → 1.0.69

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.

Potentially problematic release.


This version of aiexecode might be problematic. Click here for more details.

Files changed (87) hide show
  1. package/config_template/settings.json +1 -3
  2. package/index.js +46 -71
  3. package/package.json +1 -12
  4. package/payload_viewer/out/404/index.html +1 -1
  5. package/payload_viewer/out/404.html +1 -1
  6. package/payload_viewer/out/index.html +1 -1
  7. package/payload_viewer/out/index.txt +1 -1
  8. package/payload_viewer/web_server.js +0 -163
  9. package/prompts/completion_judge.txt +11 -7
  10. package/src/ai_based/completion_judge.js +97 -6
  11. package/src/ai_based/orchestrator.js +71 -3
  12. package/src/ai_based/pip_package_installer.js +14 -12
  13. package/src/ai_based/pip_package_lookup.js +13 -10
  14. package/src/commands/apikey.js +8 -34
  15. package/src/commands/help.js +3 -4
  16. package/src/commands/model.js +17 -74
  17. package/src/commands/reasoning_effort.js +1 -1
  18. package/src/config/feature_flags.js +0 -12
  19. package/src/{ui → frontend}/App.js +23 -25
  20. package/src/frontend/README.md +81 -0
  21. package/src/{ui/components/SuggestionsDisplay.js → frontend/components/AutocompleteMenu.js} +3 -3
  22. package/src/{ui/components/HistoryItemDisplay.js → frontend/components/ConversationItem.js} +37 -89
  23. package/src/{ui → frontend}/components/CurrentModelView.js +3 -5
  24. package/src/{ui → frontend}/components/Footer.js +4 -6
  25. package/src/{ui → frontend}/components/Header.js +2 -5
  26. package/src/{ui/components/InputPrompt.js → frontend/components/Input.js} +16 -54
  27. package/src/frontend/components/ModelListView.js +106 -0
  28. package/src/{ui → frontend}/components/ModelUpdatedView.js +3 -5
  29. package/src/{ui → frontend}/components/SessionSpinner.js +3 -3
  30. package/src/{ui → frontend}/components/SetupWizard.js +8 -101
  31. package/src/{ui → frontend}/components/ToolApprovalPrompt.js +16 -14
  32. package/src/frontend/design/themeColors.js +42 -0
  33. package/src/{ui → frontend}/index.js +7 -7
  34. package/src/frontend/utils/inputBuffer.js +441 -0
  35. package/src/{ui/utils/markdownRenderer.js → frontend/utils/markdownParser.js} +3 -3
  36. package/src/{ui/utils/ConsolePatcher.js → frontend/utils/outputRedirector.js} +9 -9
  37. package/src/{ui/utils/codeColorizer.js → frontend/utils/syntaxHighlighter.js} +2 -3
  38. package/src/system/ai_request.js +145 -595
  39. package/src/system/code_executer.js +111 -16
  40. package/src/system/file_integrity.js +5 -7
  41. package/src/system/log.js +3 -3
  42. package/src/system/mcp_integration.js +15 -13
  43. package/src/system/output_helper.js +0 -20
  44. package/src/system/session.js +97 -23
  45. package/src/system/session_memory.js +2 -82
  46. package/src/system/system_info.js +1 -1
  47. package/src/system/ui_events.js +0 -43
  48. package/src/tools/code_editor.js +17 -2
  49. package/src/tools/file_reader.js +17 -2
  50. package/src/tools/glob.js +9 -1
  51. package/src/tools/response_message.js +0 -2
  52. package/src/tools/ripgrep.js +9 -1
  53. package/src/tools/web_downloader.js +9 -1
  54. package/src/util/config.js +3 -8
  55. package/src/util/debug_log.js +4 -11
  56. package/src/util/mcp_config_manager.js +3 -5
  57. package/src/util/output_formatter.js +0 -47
  58. package/src/util/prompt_loader.js +3 -4
  59. package/src/util/safe_fs.js +60 -0
  60. package/src/util/setup_wizard.js +1 -3
  61. package/src/util/text_formatter.js +0 -86
  62. package/src/config/claude_models.js +0 -195
  63. package/src/ui/README.md +0 -208
  64. package/src/ui/api.js +0 -167
  65. package/src/ui/components/AgenticProgressDisplay.js +0 -126
  66. package/src/ui/components/Composer.js +0 -55
  67. package/src/ui/components/LoadingIndicator.js +0 -54
  68. package/src/ui/components/ModelListView.js +0 -214
  69. package/src/ui/components/Notifications.js +0 -55
  70. package/src/ui/components/StreamingIndicator.js +0 -36
  71. package/src/ui/contexts/AppContext.js +0 -25
  72. package/src/ui/contexts/StreamingContext.js +0 -20
  73. package/src/ui/contexts/UIStateContext.js +0 -117
  74. package/src/ui/example-usage.js +0 -180
  75. package/src/ui/hooks/useTerminalResize.js +0 -39
  76. package/src/ui/themes/semantic-tokens.js +0 -73
  77. package/src/ui/utils/text-buffer.js +0 -975
  78. /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_buildManifest.js +0 -0
  79. /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_clientMiddlewareManifest.json +0 -0
  80. /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_ssgManifest.js +0 -0
  81. /package/src/{ui → frontend}/components/BlankLine.js +0 -0
  82. /package/src/{ui → frontend}/components/FileDiffViewer.js +0 -0
  83. /package/src/{ui → frontend}/components/HelpView.js +0 -0
  84. /package/src/{ui → frontend}/hooks/useCompletion.js +0 -0
  85. /package/src/{ui → frontend}/hooks/useKeypress.js +0 -0
  86. /package/src/{ui → frontend}/utils/diffUtils.js +0 -0
  87. /package/src/{ui → frontend}/utils/renderInkComponent.js +0 -0
@@ -12,7 +12,7 @@ import { clampOutput, formatToolStdout } from "../util/output_formatter.js";
12
12
  import { buildToolHistoryEntry } from "../util/rag_helper.js";
13
13
  import { createSessionData, getLastConversationState, loadPreviousSessions, saveSessionToHistory } from "./session_memory.js";
14
14
  import { uiEvents } from "./ui_events.js";
15
- import { logSystem, logInfo, logSuccess, logWarning, logError, logAssistantMessage, logToolCall, logToolResult, logCodeExecution, logCodeResult, logIteration, logMissionComplete, logConversationRestored } from "./output_helper.js";
15
+ import { logSystem, logError, logAssistantMessage, logToolCall, logToolResult, logCodeExecution, logCodeResult, logIteration, logMissionComplete, logConversationRestored } from "./output_helper.js";
16
16
  import { requiresApproval, requestApproval } from "./tool_approval.js";
17
17
  import { setCurrentSession, saveFileSnapshot, getFileSnapshot } from "./file_integrity.js";
18
18
  import { abortCurrentRequest } from "./ai_request.js";
@@ -110,23 +110,32 @@ function processMessageOutput(output, shouldOutput = false) {
110
110
  * 일반 도구 호출을 처리하는 함수
111
111
  */
112
112
  async function processToolCall(name, argument, toolMap, sessionID) {
113
+ debugLog(`[processToolCall] START - tool: ${name}`);
114
+ debugLog(`[processToolCall] Arguments: ${JSON.stringify(argument, null, 2)}`);
115
+
113
116
  // edit_file_range, edit_file_replace인 경우 파일 스냅샷을 승인 요청 전에 저장
114
117
  // (ToolApprovalPrompt에서 DiffViewer 표시를 위해 필요)
115
118
  if ((name === 'edit_file_range' || name === 'edit_file_replace') && argument.file_path) {
116
119
  try {
120
+ debugLog(`[processToolCall] Saving file snapshot for: ${argument.file_path}`);
117
121
  const fileContent = await safeReadFile(argument.file_path, 'utf8');
118
122
  saveFileSnapshot(argument.file_path, fileContent);
123
+ debugLog(`[processToolCall] Snapshot saved successfully (${fileContent.length} bytes)`);
119
124
  } catch (error) {
125
+ debugLog(`[processToolCall] Snapshot save failed: ${error.message}`);
120
126
  // 파일을 읽을 수 없는 경우 (존재하지 않는 파일 등)
121
127
  // 스냅샷 저장 실패는 무시 (도구 실행에서 처리됨)
122
128
  }
123
129
  }
124
130
 
125
131
  // 승인이 필요한 도구인지 확인 (args 전달하여 실패 여부 판단)
132
+ debugLog(`[processToolCall] Checking approval requirement...`);
126
133
  const approvalCheck = await requiresApproval(name, argument);
134
+ debugLog(`[processToolCall] Approval check result: ${JSON.stringify(approvalCheck)}`);
127
135
 
128
136
  // 승인이 스킵되는 경우 (확실히 실패할 것으로 예상) - 바로 에러 반환
129
137
  if (approvalCheck && approvalCheck.skipApproval) {
138
+ debugLog(`[processToolCall] Approval skipped - tool will fail: ${approvalCheck.reason}`);
130
139
  const errorResult = {
131
140
  operation_successful: false,
132
141
  error_message: approvalCheck.reason
@@ -138,6 +147,7 @@ async function processToolCall(name, argument, toolMap, sessionID) {
138
147
  logToolCall(name, argument);
139
148
  logToolResult(name, exeResult.stdout, errorResult, argument);
140
149
 
150
+ debugLog(`[processToolCall] END - skipped with error`);
141
151
  return {
142
152
  exeResult,
143
153
  originalResult: errorResult,
@@ -147,7 +157,9 @@ async function processToolCall(name, argument, toolMap, sessionID) {
147
157
 
148
158
  // 승인이 필요한 경우 - 승인 요청을 먼저 처리 (History에 표시되기 전)
149
159
  if (approvalCheck === true) {
160
+ debugLog(`[processToolCall] Requesting user approval...`);
150
161
  const approved = await requestApproval(name, argument);
162
+ debugLog(`[processToolCall] User approval result: ${approved}`);
151
163
  if (!approved) {
152
164
  const errorResult = {
153
165
  operation_successful: false,
@@ -160,6 +172,7 @@ async function processToolCall(name, argument, toolMap, sessionID) {
160
172
  logToolCall(name, argument);
161
173
  logToolResult(name, exeResult.stdout, errorResult, argument);
162
174
 
175
+ debugLog(`[processToolCall] END - user denied`);
163
176
  return {
164
177
  exeResult,
165
178
  originalResult: errorResult,
@@ -169,10 +182,12 @@ async function processToolCall(name, argument, toolMap, sessionID) {
169
182
  }
170
183
 
171
184
  // 승인 완료 후 또는 승인 불필요한 경우 - 도구 호출 메시지 출력
185
+ debugLog(`[processToolCall] Approval passed, executing tool...`);
172
186
  logToolCall(name, argument);
173
187
 
174
188
  // 도구가 toolMap에 없는 경우 처리
175
189
  if (!toolMap[name] || typeof toolMap[name] !== 'function') {
190
+ debugLog(`[processToolCall] Tool not found in toolMap: ${name}`);
176
191
  const errorResult = {
177
192
  operation_successful: false,
178
193
  error_message: `Tool '${name}' is not available. This tool may be disabled due to missing system dependencies.`
@@ -182,6 +197,7 @@ async function processToolCall(name, argument, toolMap, sessionID) {
182
197
 
183
198
  logToolResult(name, exeResult.stdout, errorResult, argument);
184
199
 
200
+ debugLog(`[processToolCall] END - tool not available`);
185
201
  return {
186
202
  exeResult,
187
203
  originalResult: errorResult,
@@ -190,7 +206,10 @@ async function processToolCall(name, argument, toolMap, sessionID) {
190
206
  }
191
207
 
192
208
  const argumentWithSession = { ...argument, sessionID };
209
+ debugLog(`[processToolCall] Calling tool function...`);
193
210
  const result = await toolMap[name](argumentWithSession);
211
+ debugLog(`[processToolCall] Tool execution completed`);
212
+ debugLog(`[processToolCall] Result type: ${result?.constructor?.name}, keys: ${Object.keys(result || {}).join(', ')}`);
194
213
 
195
214
  if (result.constructor !== Object) {
196
215
  logError('Tool result is not an object');
@@ -199,12 +218,14 @@ async function processToolCall(name, argument, toolMap, sessionID) {
199
218
 
200
219
  const stdout = formatToolStdout(name, result);
201
220
  const exeResult = prepareExecutionResult(stdout, '', 0);
221
+ debugLog(`[processToolCall] Formatted stdout length: ${stdout.length} bytes`);
202
222
 
203
223
  // edit_file_range인 경우 스냅샷도 함께 전달
204
224
  let snapshotForLog = null;
205
225
  if (name === 'edit_file_range' && argument.file_path) {
206
226
  const snapshot = getFileSnapshot(argument.file_path);
207
227
  if (snapshot) {
228
+ debugLog(`[processToolCall] Retrieved snapshot for log: ${snapshot.content.length} bytes`);
208
229
  snapshotForLog = {
209
230
  content: snapshot.content,
210
231
  timestamp: snapshot.timestamp
@@ -214,6 +235,7 @@ async function processToolCall(name, argument, toolMap, sessionID) {
214
235
 
215
236
  logToolResult(name, exeResult.stdout, result, argument, snapshotForLog);
216
237
 
238
+ debugLog(`[processToolCall] END - success`);
217
239
  return {
218
240
  exeResult,
219
241
  originalResult: result, // 원본 도구 결과 반환
@@ -338,6 +360,7 @@ async function processOrchestratorResponses(params) {
338
360
  let missionSolved = false;
339
361
  let improvementPoints = '';
340
362
  let improvementPointsIsAutoGenerated = false;
363
+ let completionJudgeExecuted = false;
341
364
 
342
365
  debugLog(`Starting response processing loop...`);
343
366
  let loopIteration = 0;
@@ -589,6 +612,7 @@ async function processOrchestratorResponses(params) {
589
612
  judgement = await judgeMissionCompletion({
590
613
  what_user_requests: mission
591
614
  });
615
+ completionJudgeExecuted = true; // completion_judge 실행 완료
592
616
  } catch (err) {
593
617
  if (err.name === 'AbortError' || sessionInterrupted) {
594
618
  debugLog(`judgeMissionCompletion aborted or interrupted: ${err.name}`);
@@ -695,6 +719,7 @@ async function processOrchestratorResponses(params) {
695
719
  debugLog(` missionSolved: ${missionSolved}`);
696
720
  debugLog(` improvementPoints: ${improvementPoints}`);
697
721
  debugLog(` improvementPointsIsAutoGenerated: ${improvementPointsIsAutoGenerated}`);
722
+ debugLog(` completionJudgeExecuted: ${completionJudgeExecuted}`);
698
723
  debugLog(` Total loop iterations: ${loopIteration}`);
699
724
  debugLog(` Final toolUsageHistory: ${toolUsageHistory.length} items`);
700
725
 
@@ -703,7 +728,8 @@ async function processOrchestratorResponses(params) {
703
728
  stallDetected,
704
729
  missionSolved,
705
730
  improvementPoints,
706
- improvementPointsIsAutoGenerated
731
+ improvementPointsIsAutoGenerated,
732
+ completionJudgeExecuted
707
733
  };
708
734
  }
709
735
 
@@ -738,6 +764,13 @@ let sessionInterrupted = false;
738
764
  * @returns {Promise<AgentLoopResult>} 실행 결과
739
765
  */
740
766
  export async function runSession(options) {
767
+ debugLog('========================================');
768
+ debugLog('========== runSession START ==========');
769
+ debugLog('========================================');
770
+ debugLog(`Options: ${JSON.stringify(Object.keys(options))}`);
771
+ debugLog(`Mission: ${options.mission?.substring(0, 200)}${options.mission?.length > 200 ? '...' : ''}`);
772
+ debugLog(`MaxIterations: ${options.maxIterations || DEFAULT_MAX_ITERATIONS}`);
773
+
741
774
  // 세션 중단 플래그 초기화
742
775
  sessionInterrupted = false;
743
776
 
@@ -747,6 +780,7 @@ export async function runSession(options) {
747
780
  sessionInterrupted = true;
748
781
  abortCurrentRequest(); // API 요청 즉시 중단
749
782
  uiEvents.addErrorMessage('Session interrupted by user');
783
+ debugLog('[runSession] Session interrupted by user');
750
784
  }
751
785
  };
752
786
  uiEvents.on('session:interrupt', handleInterrupt);
@@ -764,6 +798,9 @@ export async function runSession(options) {
764
798
  previousSessions = null
765
799
  } = options;
766
800
 
801
+ debugLog(`MCP tool schemas count: ${mcpToolSchemas.length}`);
802
+ debugLog(`MCP tool functions count: ${Object.keys(mcpToolFunctions).length}`);
803
+
767
804
  // previousSessions가 제공되지 않은 경우 자동으로 로드
768
805
  const sessionsToUse = previousSessions ?? await loadPreviousSessions(process.app_custom.sessionID);
769
806
 
@@ -835,8 +872,14 @@ export async function runSession(options) {
835
872
  }
836
873
 
837
874
  // 메인 루프
875
+ debugLog(`[runSession] Starting main loop - maxIterations: ${maxIterations}`);
838
876
  while (!mission_solved && iteration_count < maxIterations && !sessionInterrupted) {
839
877
  iteration_count++;
878
+ debugLog('');
879
+ debugLog('========================================');
880
+ debugLog(`========== ITERATION ${iteration_count} START ==========`);
881
+ debugLog('========================================');
882
+ debugLog(`Current state - mission_solved: ${mission_solved}, sessionInterrupted: ${sessionInterrupted}`);
840
883
  logIteration(iteration_count);
841
884
 
842
885
  // 첫 반복에서 improvement_points 설정
@@ -874,10 +917,10 @@ export async function runSession(options) {
874
917
  currentSessionData.orchestratorConversation = getOrchestratorConversation();
875
918
  currentSessionData.orchestratorRequestOptions = null;
876
919
 
877
- debugLog(`[ITERATION ${iteration_count}] Session aborted during orchestration - saving session to history`);
878
- await saveSessionToHistory(currentSessionData).catch(saveErr => {
879
- debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${saveErr.message}`);
880
- });
920
+ debugLog(`[ITERATION ${iteration_count}] Session aborted during orchestration - NOT saving session to history (disabled)`);
921
+ // await saveSessionToHistory(currentSessionData).catch(saveErr => {
922
+ // debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${saveErr.message}`);
923
+ // });
881
924
  break;
882
925
  }
883
926
  throw err;
@@ -897,10 +940,10 @@ export async function runSession(options) {
897
940
  currentSessionData.orchestratorConversation = getOrchestratorConversation();
898
941
  currentSessionData.orchestratorRequestOptions = null;
899
942
 
900
- debugLog(`[ITERATION ${iteration_count}] Session interrupted after orchestration - saving session to history`);
901
- await saveSessionToHistory(currentSessionData).catch(err => {
902
- debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
903
- });
943
+ debugLog(`[ITERATION ${iteration_count}] Session interrupted after orchestration - NOT saving session to history (disabled)`);
944
+ // await saveSessionToHistory(currentSessionData).catch(err => {
945
+ // debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
946
+ // });
904
947
  break;
905
948
  }
906
949
 
@@ -937,6 +980,21 @@ export async function runSession(options) {
937
980
 
938
981
  debugLog(`[ITERATION ${iteration_count}] orchestratorResult.improvementPoints: "${orchestratorResult.improvementPoints || '(empty)'}", isAutoGenerated: ${orchestratorResult.improvementPointsIsAutoGenerated}`);
939
982
 
983
+ // completion_judge가 완료된 직후 세션 저장 (mission_solved 상태와 무관하게 무조건 저장)
984
+ if (orchestratorResult.completionJudgeExecuted) {
985
+ currentSessionData.completed_at = new Date().toISOString();
986
+ currentSessionData.mission_solved = mission_solved;
987
+ currentSessionData.iteration_count = iteration_count;
988
+ currentSessionData.toolUsageHistory = toolUsageHistory;
989
+ currentSessionData.orchestratorConversation = getOrchestratorConversation();
990
+ currentSessionData.orchestratorRequestOptions = null;
991
+
992
+ debugLog(`[ITERATION ${iteration_count}] Saving session to history after completion_judge (mission_solved=${mission_solved})`);
993
+ await saveSessionToHistory(currentSessionData).catch(err => {
994
+ debugLog(`[ITERATION ${iteration_count}] Failed to save session after completion_judge: ${err.message}`);
995
+ });
996
+ }
997
+
940
998
  // improvementPoints가 반환된 경우 다음 iteration에 사용
941
999
  // 반환되지 않은 경우 리셋
942
1000
  if (orchestratorResult.improvementPoints) {
@@ -959,14 +1017,14 @@ export async function runSession(options) {
959
1017
  currentSessionData.orchestratorConversation = getOrchestratorConversation();
960
1018
  currentSessionData.orchestratorRequestOptions = null;
961
1019
 
962
- debugLog(`[ITERATION ${iteration_count}] Session interrupted - saving session to history`);
963
- await saveSessionToHistory(currentSessionData).catch(err => {
964
- debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
965
- });
1020
+ debugLog(`[ITERATION ${iteration_count}] Session interrupted - NOT saving session to history (disabled)`);
1021
+ // await saveSessionToHistory(currentSessionData).catch(err => {
1022
+ // debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
1023
+ // });
966
1024
  break;
967
1025
  }
968
1026
 
969
- // 매 iteration마다 세션 히스토리 저장 (실시간 저장)
1027
+ // 매 iteration마다 세션 히스토리 저장 (실시간 저장) - DISABLED
970
1028
  currentSessionData.completed_at = new Date().toISOString();
971
1029
  currentSessionData.mission_solved = mission_solved;
972
1030
  currentSessionData.iteration_count = iteration_count;
@@ -974,13 +1032,17 @@ export async function runSession(options) {
974
1032
  currentSessionData.orchestratorConversation = getOrchestratorConversation();
975
1033
  currentSessionData.orchestratorRequestOptions = null;
976
1034
 
977
- debugLog(`[ITERATION ${iteration_count}] Saving session to history (real-time save)`);
978
- await saveSessionToHistory(currentSessionData).catch(err => {
979
- debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
980
- });
1035
+ debugLog(`[ITERATION ${iteration_count}] NOT saving session to history (disabled - will only save after completion_judge)`);
1036
+ // await saveSessionToHistory(currentSessionData).catch(err => {
1037
+ // debugLog(`[ITERATION ${iteration_count}] Failed to save session: ${err.message}`);
1038
+ // });
981
1039
 
982
1040
  // 미션 완료 처리
983
1041
  if (mission_solved) {
1042
+ debugLog(`[ITERATION ${iteration_count}] Mission solved, breaking loop`);
1043
+ debugLog('========================================');
1044
+ debugLog(`========== ITERATION ${iteration_count} END ==========`);
1045
+ debugLog('========================================');
984
1046
  break;
985
1047
  }
986
1048
 
@@ -991,11 +1053,18 @@ export async function runSession(options) {
991
1053
  ? '⚠ Session ended due to orchestrator stall'
992
1054
  : '✅ No function calls detected - mission complete';
993
1055
  uiEvents.addSystemMessage(message);
1056
+ debugLog(`[ITERATION ${iteration_count}] ${message}`);
1057
+ debugLog('========================================');
1058
+ debugLog(`========== ITERATION ${iteration_count} END ==========`);
1059
+ debugLog('========================================');
994
1060
  break;
995
1061
  }
996
1062
 
997
1063
  // improvement_points가 설정되어 있으면 다음 iteration 계속 진행
998
1064
  debugLog(`[ITERATION ${iteration_count}] Continuing with improvement_points: "${improvement_points?.substring(0, 100) || '(empty)'}"`);
1065
+ debugLog('========================================');
1066
+ debugLog(`========== ITERATION ${iteration_count} END ==========`);
1067
+ debugLog('========================================');
999
1068
  continue;
1000
1069
  }
1001
1070
 
@@ -1024,11 +1093,16 @@ export async function runSession(options) {
1024
1093
  currentSessionData.orchestratorConversation = result.orchestratorConversation;
1025
1094
  currentSessionData.orchestratorRequestOptions = null; // 필요시 orchestrator에서 가져올 수 있음
1026
1095
 
1027
- debugLog(`[runSession] Saving final session to history - sessionID: ${currentSessionData.sessionID}`);
1096
+ debugLog(`[runSession] NOT saving final session to history (disabled - will only save after completion_judge) - sessionID: ${currentSessionData.sessionID}`);
1028
1097
  debugLog(`[runSession] Session data size: ${JSON.stringify(currentSessionData).length} bytes`);
1029
- // 최종 세션 히스토리에 저장 (중복 저장이지만 최신 상태 보장)
1030
- await saveSessionToHistory(currentSessionData);
1031
-
1098
+ debugLog(`[runSession] Final state - mission_solved: ${currentSessionData.mission_solved}, iteration_count: ${currentSessionData.iteration_count}`);
1099
+ debugLog(`[runSession] Tool usage history entries: ${currentSessionData.toolUsageHistory.length}`);
1100
+ // 최종 세션 히스토리에 저장 (중복 저장이지만 최신 상태 보장) - DISABLED
1101
+ // await saveSessionToHistory(currentSessionData);
1102
+
1103
+ debugLog('========================================');
1104
+ debugLog('========== runSession END ==========');
1105
+ debugLog('========================================');
1032
1106
  return currentSessionData;
1033
1107
  } catch (error) {
1034
1108
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -26,8 +26,6 @@ async function ensureHistoryDir(sessionID) {
26
26
  await safeMkdir(sessionDir, { recursive: true });
27
27
  }
28
28
 
29
- function consolelog() { }
30
-
31
29
  /**
32
30
  * 세션 히스토리 파일을 삭제
33
31
  * @param {string} sessionID - 세션 ID
@@ -54,11 +52,11 @@ export async function loadPreviousSessions(sessionID) {
54
52
  if (await safeExists(historyFile)) {
55
53
  const content = await safeReadFile(historyFile, 'utf8');
56
54
  const sessions = JSON.parse(content);
57
- // consolelog(chalk.blue(`📚 Loaded ${sessions.length} previous sessions from history`));
55
+ debugLog(`Loaded ${sessions.length} previous sessions from history`);
58
56
  return sessions;
59
57
  }
60
58
  } catch (err) {
61
- // consolelog(chalk.yellow(`⚠ Could not load previous sessions: ${err.message}`));
59
+ debugLog(`Could not load previous sessions: ${err.message}`);
62
60
  }
63
61
  return [];
64
62
  }
@@ -114,84 +112,6 @@ export async function saveSessionToHistory(sessionData) {
114
112
  return null;
115
113
  }
116
114
 
117
- /**
118
- * 최근 N개의 세션만 추출
119
- * @param {Array} sessions - 전체 세션 배열
120
- * @param {number} count - 가져올 개수
121
- * @returns {Array} 최근 N개 세션
122
- */
123
- export function getRecentSessions(sessions, count = 5) {
124
- return sessions.slice(-count);
125
- }
126
-
127
- /**
128
- * 현재 미션과 관련된 세션들을 필터링
129
- * @param {Array} sessions - 전체 세션 배열
130
- * @param {string} currentMission - 현재 미션
131
- * @returns {Array} 관련 세션들
132
- */
133
- export function getRelatedSessions(sessions, currentMission) {
134
- const keywords = currentMission.toLowerCase().split(/\s+/);
135
-
136
- return sessions.filter(session => {
137
- const sessionMission = (session.mission || '').toLowerCase();
138
- // 키워드 중 하나라도 매칭되면 관련 세션으로 판단
139
- return keywords.some(keyword =>
140
- keyword.length > 2 && sessionMission.includes(keyword)
141
- );
142
- });
143
- }
144
-
145
- /**
146
- * 이전 세션들을 AI가 이해할 수 있는 컨텍스트로 변환
147
- * @param {Array} sessions - 세션 배열
148
- * @param {string} currentMission - 현재 미션
149
- * @returns {string} AI용 컨텍스트 문자열
150
- */
151
- export function buildHistoricalContext(sessions, currentMission) {
152
- if (!sessions || sessions.length === 0) {
153
- return '';
154
- }
155
-
156
- // 현재 미션과 관련된 세션 + 최근 세션 조합
157
- const relatedSessions = getRelatedSessions(sessions, currentMission);
158
- const recentSessions = getRecentSessions(sessions, 3);
159
-
160
- // 중복 제거하면서 합치기
161
- const sessionSet = new Set([...relatedSessions, ...recentSessions]);
162
- const relevantSessions = Array.from(sessionSet).slice(-5); // 최대 5개만
163
-
164
- if (relevantSessions.length === 0) {
165
- return '';
166
- }
167
-
168
- const contextParts = [
169
- '# Previous Execution History',
170
- `You have access to ${relevantSessions.length} previous session(s) that may be relevant:`,
171
- ''
172
- ];
173
-
174
- relevantSessions.forEach((session, idx) => {
175
- contextParts.push(`## Session ${idx + 1} (${session.started_at || 'unknown time'})`);
176
- contextParts.push(`**Mission**: ${session.mission}`);
177
- contextParts.push(`**Status**: ${session.mission_solved ? '✅ Completed' : '❌ Not completed'}`);
178
- contextParts.push(`**Iterations**: ${session.iteration_count || 0}`);
179
-
180
- // 도구 사용 통계
181
- if (session.toolUsageHistory && session.toolUsageHistory.length > 0) {
182
- const toolCounts = {};
183
- session.toolUsageHistory.forEach(tool => {
184
- toolCounts[tool.toolName] = (toolCounts[tool.toolName] || 0) + 1;
185
- });
186
- contextParts.push(`**Tools Used**: ${Object.entries(toolCounts).map(([name, count]) => `${name}(${count})`).join(', ')}`);
187
- }
188
-
189
- contextParts.push('');
190
- });
191
-
192
- return contextParts.join('\n');
193
- }
194
-
195
115
  /**
196
116
  * 현재 세션 데이터 구조 생성
197
117
  * @param {string} sessionID - 세션 ID
@@ -8,7 +8,7 @@ const execAsync = promisify(exec);
8
8
  * 현재 운영체제 타입을 반환합니다.
9
9
  * @returns {string} 'macos' | 'linux' | 'windows' | 'unknown'
10
10
  */
11
- export function getOSType() {
11
+ function getOSType() {
12
12
  const platformType = platform();
13
13
 
14
14
  switch (platformType) {
@@ -106,27 +106,6 @@ class UIEventEmitter extends EventEmitter {
106
106
  });
107
107
  }
108
108
 
109
- /**
110
- * 검증 시작 알림
111
- */
112
- startVerification() {
113
- this.emit('history:add', {
114
- type: 'verification_start',
115
- timestamp: Date.now()
116
- });
117
- }
118
-
119
- /**
120
- * 검증 결과
121
- */
122
- addVerificationResult(result) {
123
- this.emit('history:add', {
124
- type: 'verification_result',
125
- result,
126
- timestamp: Date.now()
127
- });
128
- }
129
-
130
109
  /**
131
110
  * 미션 완료
132
111
  */
@@ -138,28 +117,6 @@ class UIEventEmitter extends EventEmitter {
138
117
  });
139
118
  }
140
119
 
141
- /**
142
- * 미션 실패
143
- */
144
- missionFailed(reason) {
145
- this.emit('history:add', {
146
- type: 'mission_failed',
147
- reason,
148
- timestamp: Date.now()
149
- });
150
- }
151
-
152
- /**
153
- * RAG 검색 결과
154
- */
155
- addRagSearch(contextLength) {
156
- this.emit('history:add', {
157
- type: 'rag_search',
158
- contextLength,
159
- timestamp: Date.now()
160
- });
161
- }
162
-
163
120
  /**
164
121
  * 대화 복원 알림
165
122
  */
@@ -5,6 +5,7 @@ import { assertFileIntegrity, trackFileRead, saveFileSnapshot } from '../system/
5
5
  import { createDebugLogger } from '../util/debug_log.js';
6
6
  import { DEBUG_LOG_DIR } from '../util/config.js';
7
7
  import { toDisplayPath } from '../util/path_helper.js';
8
+ import { theme } from '../frontend/design/themeColors.js';
8
9
 
9
10
  const debugLog = createDebugLogger('code_editor.log', 'code_editor');
10
11
 
@@ -231,7 +232,14 @@ export const writeFileSchema = {
231
232
  if (result.operation_successful) {
232
233
  const lines = result.total_line_count || 0;
233
234
  const action = result.file_existed ? 'Overwrote' : 'Created';
234
- return `${action} ${lines} line${lines !== 1 ? 's' : ''}`;
235
+ return {
236
+ type: 'formatted',
237
+ parts: [
238
+ { text: `${action} `, style: {} },
239
+ { text: String(lines), style: { color: theme.brand.light, bold: true } },
240
+ { text: ` line${lines !== 1 ? 's' : ''}`, style: {} }
241
+ ]
242
+ };
235
243
  }
236
244
  return result.error_message || 'Error writing file';
237
245
  }
@@ -704,7 +712,14 @@ export const editFileReplaceSchema = {
704
712
  "format_tool_result": (result) => {
705
713
  if (result.operation_successful) {
706
714
  const count = result.replacement_count || 0;
707
- return `Replaced ${count} occurrence${count !== 1 ? 's' : ''}`;
715
+ return {
716
+ type: 'formatted',
717
+ parts: [
718
+ { text: 'Replaced ', style: {} },
719
+ { text: String(count), style: { color: theme.brand.light, bold: true } },
720
+ { text: ` occurrence${count !== 1 ? 's' : ''}`, style: {} }
721
+ ]
722
+ };
708
723
  }
709
724
  return result.error_message || 'Error replacing string';
710
725
  }
@@ -3,6 +3,7 @@ import { resolve } from 'path';
3
3
  import { trackFileRead, saveFileSnapshot } from '../system/file_integrity.js';
4
4
  import { createDebugLogger } from '../util/debug_log.js';
5
5
  import { toDisplayPath } from '../util/path_helper.js';
6
+ import { theme } from '../frontend/design/themeColors.js';
6
7
 
7
8
  const debugLog = createDebugLogger('file_reader.log', 'file_reader');
8
9
 
@@ -128,7 +129,14 @@ export const readFileSchema = {
128
129
  "format_tool_result": (result) => {
129
130
  if (result.operation_successful) {
130
131
  const lines = result.total_line_count || 0;
131
- return `Read ${lines} line${lines !== 1 ? 's' : ''}`;
132
+ return {
133
+ type: 'formatted',
134
+ parts: [
135
+ { text: 'Read ', style: {} },
136
+ { text: String(lines), style: { color: theme.brand.light, bold: true } },
137
+ { text: ` line${lines !== 1 ? 's' : ''}`, style: {} }
138
+ ]
139
+ };
132
140
  }
133
141
  return result.error_message || 'Error reading file';
134
142
  }
@@ -288,7 +296,14 @@ export const readFileRangeSchema = {
288
296
  "format_tool_result": (result) => {
289
297
  if (result.operation_successful) {
290
298
  const lineCount = result.file_lines?.length || 0;
291
- return `Read ${lineCount} line${lineCount !== 1 ? 's' : ''}`;
299
+ return {
300
+ type: 'formatted',
301
+ parts: [
302
+ { text: 'Read ', style: {} },
303
+ { text: String(lineCount), style: { color: theme.brand.light, bold: true } },
304
+ { text: ` line${lineCount !== 1 ? 's' : ''}`, style: {} }
305
+ ]
306
+ };
292
307
  }
293
308
  return result.error_message || 'Error reading file';
294
309
  }
package/src/tools/glob.js CHANGED
@@ -2,6 +2,7 @@ import { glob } from 'glob';
2
2
  import { resolve, relative } from 'path';
3
3
  import { safeStat } from '../util/safe_fs.js';
4
4
  import { createDebugLogger } from '../util/debug_log.js';
5
+ import { theme } from '../frontend/design/themeColors.js';
5
6
 
6
7
  const debugLog = createDebugLogger('glob.log', 'glob');
7
8
 
@@ -241,7 +242,14 @@ export const globSearchSchema = {
241
242
  format_tool_result: (result) => {
242
243
  if (result.operation_successful) {
243
244
  const matches = result.total_matches || 0;
244
- return `Found ${matches} match${matches !== 1 ? 'es' : ''}`;
245
+ return {
246
+ type: 'formatted',
247
+ parts: [
248
+ { text: 'Found ', style: {} },
249
+ { text: String(matches), style: { color: theme.brand.light, bold: true } },
250
+ { text: ` match${matches !== 1 ? 'es' : ''}`, style: {} }
251
+ ]
252
+ };
245
253
  }
246
254
  return result.error_message || 'Search failed';
247
255
  }
@@ -1,6 +1,4 @@
1
- function consolelog() { }
2
1
  export async function response_message({ message = "" }) {
3
- consolelog(`Assistant say: ${message}`);
4
2
  return { message };
5
3
  }
6
4
 
@@ -1,4 +1,5 @@
1
1
  import { spawn } from 'child_process';
2
+ import { theme } from '../frontend/design/themeColors.js';
2
3
 
3
4
  // 파일 내용 검색, 파일 경로 필터링, 다양한 출력 모드 등을 지원합니다.
4
5
 
@@ -441,7 +442,14 @@ export const ripgrepSchema = {
441
442
  format_tool_result: (result) => {
442
443
  if (result.operation_successful) {
443
444
  const matches = result.totalMatches || 0;
444
- return `Found ${matches} match${matches !== 1 ? 'es' : ''}`;
445
+ return {
446
+ type: 'formatted',
447
+ parts: [
448
+ { text: 'Found ', style: {} },
449
+ { text: String(matches), style: { color: theme.brand.light, bold: true } },
450
+ { text: ` match${matches !== 1 ? 'es' : ''}`, style: {} }
451
+ ]
452
+ };
445
453
  }
446
454
  return result.error_message || 'Search failed';
447
455
  }
@@ -1,6 +1,7 @@
1
1
  import { execPythonCode } from "../system/code_executer.js";
2
2
  import { safeReadFile } from '../util/safe_fs.js';
3
3
  import { join } from 'path';
4
+ import { theme } from '../frontend/design/themeColors.js';
4
5
 
5
6
  // 이 파일은 웹 페이지를 가져와서 텍스트 형식으로 변환하는 도구를 제공합니다.
6
7
  // 외부 참고 자료가 필요한 미션일 때 Orchestrator가 지식을 확보하고 Verifier가 근거를 남길 수 있게 보조합니다.
@@ -60,7 +61,14 @@ export const fetchWebPageSchema = {
60
61
  "format_tool_result": (result) => {
61
62
  if (result.operation_successful) {
62
63
  const contentLength = result.content?.length || 0;
63
- return `Fetched ${contentLength} characters`;
64
+ return {
65
+ type: 'formatted',
66
+ parts: [
67
+ { text: 'Fetched ', style: {} },
68
+ { text: String(contentLength), style: { color: theme.brand.light, bold: true } },
69
+ { text: ' characters', style: {} }
70
+ ]
71
+ };
64
72
  }
65
73
  return result.error_message || 'Fetch failed';
66
74
  }