@shareai-lab/kode 1.1.14 → 1.1.16-dev.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.
Files changed (289) hide show
  1. package/cli.js +77 -82
  2. package/dist/entrypoints/cli.js +59 -38
  3. package/dist/entrypoints/cli.js.map +3 -3
  4. package/dist/index.js +5 -26
  5. package/dist/package.json +4 -1
  6. package/package.json +11 -104
  7. package/dist/test/testAdapters.js +0 -88
  8. package/dist/test/testAdapters.js.map +0 -1
  9. package/src/ProjectOnboarding.tsx +0 -198
  10. package/src/Tool.ts +0 -83
  11. package/src/commands/agents.tsx +0 -3416
  12. package/src/commands/approvedTools.ts +0 -53
  13. package/src/commands/bug.tsx +0 -20
  14. package/src/commands/clear.ts +0 -43
  15. package/src/commands/compact.ts +0 -120
  16. package/src/commands/config.tsx +0 -19
  17. package/src/commands/cost.ts +0 -18
  18. package/src/commands/ctx_viz.ts +0 -209
  19. package/src/commands/doctor.ts +0 -24
  20. package/src/commands/help.tsx +0 -19
  21. package/src/commands/init.ts +0 -37
  22. package/src/commands/listen.ts +0 -42
  23. package/src/commands/login.tsx +0 -51
  24. package/src/commands/logout.tsx +0 -40
  25. package/src/commands/mcp.ts +0 -41
  26. package/src/commands/model.tsx +0 -40
  27. package/src/commands/modelstatus.tsx +0 -20
  28. package/src/commands/onboarding.tsx +0 -34
  29. package/src/commands/pr_comments.ts +0 -59
  30. package/src/commands/refreshCommands.ts +0 -54
  31. package/src/commands/release-notes.ts +0 -34
  32. package/src/commands/resume.tsx +0 -31
  33. package/src/commands/review.ts +0 -49
  34. package/src/commands/terminalSetup.ts +0 -221
  35. package/src/commands.ts +0 -139
  36. package/src/components/ApproveApiKey.tsx +0 -93
  37. package/src/components/AsciiLogo.tsx +0 -13
  38. package/src/components/AutoUpdater.tsx +0 -148
  39. package/src/components/Bug.tsx +0 -367
  40. package/src/components/Config.tsx +0 -293
  41. package/src/components/ConsoleOAuthFlow.tsx +0 -327
  42. package/src/components/Cost.tsx +0 -23
  43. package/src/components/CostThresholdDialog.tsx +0 -46
  44. package/src/components/CustomSelect/option-map.ts +0 -42
  45. package/src/components/CustomSelect/select-option.tsx +0 -78
  46. package/src/components/CustomSelect/select.tsx +0 -152
  47. package/src/components/CustomSelect/theme.ts +0 -45
  48. package/src/components/CustomSelect/use-select-state.ts +0 -414
  49. package/src/components/CustomSelect/use-select.ts +0 -35
  50. package/src/components/FallbackToolUseRejectedMessage.tsx +0 -15
  51. package/src/components/FileEditToolUpdatedMessage.tsx +0 -66
  52. package/src/components/Help.tsx +0 -215
  53. package/src/components/HighlightedCode.tsx +0 -33
  54. package/src/components/InvalidConfigDialog.tsx +0 -113
  55. package/src/components/Link.tsx +0 -32
  56. package/src/components/LogSelector.tsx +0 -86
  57. package/src/components/Logo.tsx +0 -170
  58. package/src/components/MCPServerApprovalDialog.tsx +0 -100
  59. package/src/components/MCPServerDialogCopy.tsx +0 -25
  60. package/src/components/MCPServerMultiselectDialog.tsx +0 -109
  61. package/src/components/Message.tsx +0 -221
  62. package/src/components/MessageResponse.tsx +0 -15
  63. package/src/components/MessageSelector.tsx +0 -211
  64. package/src/components/ModeIndicator.tsx +0 -88
  65. package/src/components/ModelConfig.tsx +0 -301
  66. package/src/components/ModelListManager.tsx +0 -227
  67. package/src/components/ModelSelector.tsx +0 -3387
  68. package/src/components/ModelStatusDisplay.tsx +0 -230
  69. package/src/components/Onboarding.tsx +0 -274
  70. package/src/components/PressEnterToContinue.tsx +0 -11
  71. package/src/components/PromptInput.tsx +0 -760
  72. package/src/components/SentryErrorBoundary.ts +0 -39
  73. package/src/components/Spinner.tsx +0 -129
  74. package/src/components/StickerRequestForm.tsx +0 -16
  75. package/src/components/StructuredDiff.tsx +0 -191
  76. package/src/components/TextInput.tsx +0 -259
  77. package/src/components/TodoItem.tsx +0 -47
  78. package/src/components/TokenWarning.tsx +0 -31
  79. package/src/components/ToolUseLoader.tsx +0 -40
  80. package/src/components/TrustDialog.tsx +0 -106
  81. package/src/components/binary-feedback/BinaryFeedback.tsx +0 -63
  82. package/src/components/binary-feedback/BinaryFeedbackOption.tsx +0 -111
  83. package/src/components/binary-feedback/BinaryFeedbackView.tsx +0 -172
  84. package/src/components/binary-feedback/utils.ts +0 -220
  85. package/src/components/messages/AssistantBashOutputMessage.tsx +0 -22
  86. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +0 -49
  87. package/src/components/messages/AssistantRedactedThinkingMessage.tsx +0 -19
  88. package/src/components/messages/AssistantTextMessage.tsx +0 -144
  89. package/src/components/messages/AssistantThinkingMessage.tsx +0 -40
  90. package/src/components/messages/AssistantToolUseMessage.tsx +0 -132
  91. package/src/components/messages/TaskProgressMessage.tsx +0 -32
  92. package/src/components/messages/TaskToolMessage.tsx +0 -58
  93. package/src/components/messages/UserBashInputMessage.tsx +0 -28
  94. package/src/components/messages/UserCommandMessage.tsx +0 -30
  95. package/src/components/messages/UserKodingInputMessage.tsx +0 -28
  96. package/src/components/messages/UserPromptMessage.tsx +0 -35
  97. package/src/components/messages/UserTextMessage.tsx +0 -39
  98. package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +0 -12
  99. package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +0 -36
  100. package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +0 -31
  101. package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +0 -57
  102. package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +0 -35
  103. package/src/components/messages/UserToolResultMessage/utils.tsx +0 -56
  104. package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +0 -121
  105. package/src/components/permissions/FallbackPermissionRequest.tsx +0 -153
  106. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +0 -182
  107. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +0 -77
  108. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +0 -164
  109. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +0 -83
  110. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +0 -240
  111. package/src/components/permissions/PermissionRequest.tsx +0 -101
  112. package/src/components/permissions/PermissionRequestTitle.tsx +0 -69
  113. package/src/components/permissions/hooks.ts +0 -44
  114. package/src/components/permissions/toolUseOptions.ts +0 -59
  115. package/src/components/permissions/utils.ts +0 -23
  116. package/src/constants/betas.ts +0 -5
  117. package/src/constants/claude-asterisk-ascii-art.tsx +0 -238
  118. package/src/constants/figures.ts +0 -4
  119. package/src/constants/keys.ts +0 -3
  120. package/src/constants/macros.ts +0 -11
  121. package/src/constants/modelCapabilities.ts +0 -179
  122. package/src/constants/models.ts +0 -1025
  123. package/src/constants/oauth.ts +0 -18
  124. package/src/constants/product.ts +0 -17
  125. package/src/constants/prompts.ts +0 -168
  126. package/src/constants/releaseNotes.ts +0 -7
  127. package/src/context/PermissionContext.tsx +0 -149
  128. package/src/context.ts +0 -278
  129. package/src/cost-tracker.ts +0 -84
  130. package/src/entrypoints/cli.tsx +0 -1561
  131. package/src/entrypoints/mcp.ts +0 -175
  132. package/src/history.ts +0 -25
  133. package/src/hooks/useApiKeyVerification.ts +0 -59
  134. package/src/hooks/useArrowKeyHistory.ts +0 -55
  135. package/src/hooks/useCanUseTool.ts +0 -138
  136. package/src/hooks/useCancelRequest.ts +0 -39
  137. package/src/hooks/useDoublePress.ts +0 -41
  138. package/src/hooks/useExitOnCtrlCD.ts +0 -31
  139. package/src/hooks/useInterval.ts +0 -25
  140. package/src/hooks/useLogMessages.ts +0 -16
  141. package/src/hooks/useLogStartupTime.ts +0 -12
  142. package/src/hooks/useNotifyAfterTimeout.ts +0 -65
  143. package/src/hooks/usePermissionRequestLogging.ts +0 -44
  144. package/src/hooks/useTerminalSize.ts +0 -49
  145. package/src/hooks/useTextInput.ts +0 -317
  146. package/src/hooks/useUnifiedCompletion.ts +0 -1405
  147. package/src/index.ts +0 -34
  148. package/src/messages.ts +0 -38
  149. package/src/permissions.ts +0 -268
  150. package/src/query.ts +0 -720
  151. package/src/screens/ConfigureNpmPrefix.tsx +0 -197
  152. package/src/screens/Doctor.tsx +0 -219
  153. package/src/screens/LogList.tsx +0 -68
  154. package/src/screens/REPL.tsx +0 -813
  155. package/src/screens/ResumeConversation.tsx +0 -68
  156. package/src/services/adapters/base.ts +0 -38
  157. package/src/services/adapters/chatCompletions.ts +0 -90
  158. package/src/services/adapters/responsesAPI.ts +0 -170
  159. package/src/services/browserMocks.ts +0 -66
  160. package/src/services/claude.ts +0 -2197
  161. package/src/services/customCommands.ts +0 -704
  162. package/src/services/fileFreshness.ts +0 -377
  163. package/src/services/gpt5ConnectionTest.ts +0 -340
  164. package/src/services/mcpClient.ts +0 -564
  165. package/src/services/mcpServerApproval.tsx +0 -50
  166. package/src/services/mentionProcessor.ts +0 -273
  167. package/src/services/modelAdapterFactory.ts +0 -69
  168. package/src/services/notifier.ts +0 -40
  169. package/src/services/oauth.ts +0 -357
  170. package/src/services/openai.ts +0 -1359
  171. package/src/services/responseStateManager.ts +0 -90
  172. package/src/services/sentry.ts +0 -3
  173. package/src/services/statsig.ts +0 -172
  174. package/src/services/statsigStorage.ts +0 -86
  175. package/src/services/systemReminder.ts +0 -507
  176. package/src/services/vcr.ts +0 -161
  177. package/src/test/testAdapters.ts +0 -96
  178. package/src/tools/ArchitectTool/ArchitectTool.tsx +0 -135
  179. package/src/tools/ArchitectTool/prompt.ts +0 -15
  180. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +0 -576
  181. package/src/tools/BashTool/BashTool.tsx +0 -243
  182. package/src/tools/BashTool/BashToolResultMessage.tsx +0 -38
  183. package/src/tools/BashTool/OutputLine.tsx +0 -49
  184. package/src/tools/BashTool/prompt.ts +0 -174
  185. package/src/tools/BashTool/utils.ts +0 -56
  186. package/src/tools/FileEditTool/FileEditTool.tsx +0 -319
  187. package/src/tools/FileEditTool/prompt.ts +0 -51
  188. package/src/tools/FileEditTool/utils.ts +0 -58
  189. package/src/tools/FileReadTool/FileReadTool.tsx +0 -404
  190. package/src/tools/FileReadTool/prompt.ts +0 -7
  191. package/src/tools/FileWriteTool/FileWriteTool.tsx +0 -301
  192. package/src/tools/FileWriteTool/prompt.ts +0 -10
  193. package/src/tools/GlobTool/GlobTool.tsx +0 -119
  194. package/src/tools/GlobTool/prompt.ts +0 -8
  195. package/src/tools/GrepTool/GrepTool.tsx +0 -147
  196. package/src/tools/GrepTool/prompt.ts +0 -11
  197. package/src/tools/MCPTool/MCPTool.tsx +0 -107
  198. package/src/tools/MCPTool/prompt.ts +0 -3
  199. package/src/tools/MemoryReadTool/MemoryReadTool.tsx +0 -127
  200. package/src/tools/MemoryReadTool/prompt.ts +0 -3
  201. package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +0 -89
  202. package/src/tools/MemoryWriteTool/prompt.ts +0 -3
  203. package/src/tools/MultiEditTool/MultiEditTool.tsx +0 -388
  204. package/src/tools/MultiEditTool/prompt.ts +0 -45
  205. package/src/tools/NotebookEditTool/NotebookEditTool.tsx +0 -298
  206. package/src/tools/NotebookEditTool/prompt.ts +0 -3
  207. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +0 -258
  208. package/src/tools/NotebookReadTool/prompt.ts +0 -3
  209. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +0 -107
  210. package/src/tools/StickerRequestTool/prompt.ts +0 -19
  211. package/src/tools/TaskTool/TaskTool.tsx +0 -438
  212. package/src/tools/TaskTool/constants.ts +0 -1
  213. package/src/tools/TaskTool/prompt.ts +0 -92
  214. package/src/tools/ThinkTool/ThinkTool.tsx +0 -54
  215. package/src/tools/ThinkTool/prompt.ts +0 -12
  216. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +0 -313
  217. package/src/tools/TodoWriteTool/prompt.ts +0 -63
  218. package/src/tools/URLFetcherTool/URLFetcherTool.tsx +0 -178
  219. package/src/tools/URLFetcherTool/cache.ts +0 -55
  220. package/src/tools/URLFetcherTool/htmlToMarkdown.ts +0 -55
  221. package/src/tools/URLFetcherTool/prompt.ts +0 -17
  222. package/src/tools/WebSearchTool/WebSearchTool.tsx +0 -103
  223. package/src/tools/WebSearchTool/prompt.ts +0 -13
  224. package/src/tools/WebSearchTool/searchProviders.ts +0 -66
  225. package/src/tools/lsTool/lsTool.tsx +0 -272
  226. package/src/tools/lsTool/prompt.ts +0 -2
  227. package/src/tools.ts +0 -67
  228. package/src/types/PermissionMode.ts +0 -120
  229. package/src/types/RequestContext.ts +0 -72
  230. package/src/types/common.d.ts +0 -2
  231. package/src/types/conversation.ts +0 -51
  232. package/src/types/logs.ts +0 -58
  233. package/src/types/modelCapabilities.ts +0 -64
  234. package/src/types/notebook.ts +0 -87
  235. package/src/utils/Cursor.ts +0 -436
  236. package/src/utils/PersistentShell.ts +0 -552
  237. package/src/utils/advancedFuzzyMatcher.ts +0 -290
  238. package/src/utils/agentLoader.ts +0 -278
  239. package/src/utils/agentStorage.ts +0 -97
  240. package/src/utils/array.ts +0 -3
  241. package/src/utils/ask.tsx +0 -99
  242. package/src/utils/auth.ts +0 -13
  243. package/src/utils/autoCompactCore.ts +0 -223
  244. package/src/utils/autoUpdater.ts +0 -458
  245. package/src/utils/betas.ts +0 -20
  246. package/src/utils/browser.ts +0 -14
  247. package/src/utils/cleanup.ts +0 -72
  248. package/src/utils/commands.ts +0 -261
  249. package/src/utils/commonUnixCommands.ts +0 -161
  250. package/src/utils/config.ts +0 -945
  251. package/src/utils/conversationRecovery.ts +0 -55
  252. package/src/utils/debugLogger.ts +0 -1235
  253. package/src/utils/diff.ts +0 -42
  254. package/src/utils/env.ts +0 -57
  255. package/src/utils/errors.ts +0 -21
  256. package/src/utils/exampleCommands.ts +0 -109
  257. package/src/utils/execFileNoThrow.ts +0 -51
  258. package/src/utils/expertChatStorage.ts +0 -136
  259. package/src/utils/file.ts +0 -405
  260. package/src/utils/fileRecoveryCore.ts +0 -71
  261. package/src/utils/format.tsx +0 -44
  262. package/src/utils/fuzzyMatcher.ts +0 -328
  263. package/src/utils/generators.ts +0 -62
  264. package/src/utils/git.ts +0 -92
  265. package/src/utils/globalLogger.ts +0 -77
  266. package/src/utils/http.ts +0 -10
  267. package/src/utils/imagePaste.ts +0 -38
  268. package/src/utils/json.ts +0 -13
  269. package/src/utils/log.ts +0 -382
  270. package/src/utils/markdown.ts +0 -213
  271. package/src/utils/messageContextManager.ts +0 -294
  272. package/src/utils/messages.tsx +0 -945
  273. package/src/utils/model.ts +0 -914
  274. package/src/utils/permissions/filesystem.ts +0 -127
  275. package/src/utils/responseState.ts +0 -23
  276. package/src/utils/ripgrep.ts +0 -167
  277. package/src/utils/secureFile.ts +0 -564
  278. package/src/utils/sessionState.ts +0 -49
  279. package/src/utils/state.ts +0 -25
  280. package/src/utils/style.ts +0 -29
  281. package/src/utils/terminal.ts +0 -50
  282. package/src/utils/theme.ts +0 -127
  283. package/src/utils/thinking.ts +0 -144
  284. package/src/utils/todoStorage.ts +0 -431
  285. package/src/utils/tokens.ts +0 -43
  286. package/src/utils/toolExecutionController.ts +0 -163
  287. package/src/utils/unaryLogging.ts +0 -26
  288. package/src/utils/user.ts +0 -37
  289. package/src/utils/validate.ts +0 -165
@@ -1,1235 +0,0 @@
1
- import { existsSync, mkdirSync, appendFileSync } from 'fs'
2
- import { join } from 'path'
3
- import { homedir } from 'os'
4
- import { randomUUID } from 'crypto'
5
- import chalk from 'chalk'
6
- import envPaths from 'env-paths'
7
- import { PRODUCT_COMMAND } from '../constants/product'
8
- import { SESSION_ID } from './log'
9
- import type { Message } from '../types/conversation'
10
-
11
- // 调试日志级别
12
- export enum LogLevel {
13
- TRACE = 'TRACE',
14
- DEBUG = 'DEBUG',
15
- INFO = 'INFO',
16
- WARN = 'WARN',
17
- ERROR = 'ERROR',
18
- FLOW = 'FLOW',
19
- API = 'API',
20
- STATE = 'STATE',
21
- REMINDER = 'REMINDER', // 新增:系统提醒事件
22
- }
23
-
24
- // 调试模式检测
25
- const isDebugMode = () =>
26
- process.argv.includes('--debug') || process.argv.includes('--debug-verbose')
27
- const isVerboseMode = () => process.argv.includes('--verbose')
28
- const isDebugVerboseMode = () => process.argv.includes('--debug-verbose')
29
-
30
- // 终端日志级别配置 - 显示关键信息
31
- const TERMINAL_LOG_LEVELS = new Set([
32
- LogLevel.ERROR,
33
- LogLevel.WARN,
34
- LogLevel.INFO, // 添加 INFO 级别,显示关键系统状态
35
- LogLevel.REMINDER, // 系统提醒事件,用户应该看到
36
- ])
37
-
38
- // 在调试详细模式下显示更多日志级别
39
- const DEBUG_VERBOSE_TERMINAL_LOG_LEVELS = new Set([
40
- LogLevel.ERROR,
41
- LogLevel.WARN,
42
- LogLevel.FLOW,
43
- LogLevel.API,
44
- LogLevel.STATE,
45
- LogLevel.INFO,
46
- LogLevel.REMINDER, // 系统提醒在详细模式下也显示
47
- ])
48
-
49
- // 用户友好的日志级别 - 简化的高级日志
50
- const USER_FRIENDLY_LEVELS = new Set([
51
- 'SESSION_START',
52
- 'QUERY_START',
53
- 'QUERY_PROGRESS',
54
- 'QUERY_COMPLETE',
55
- 'TOOL_EXECUTION',
56
- 'ERROR_OCCURRED',
57
- 'PERFORMANCE_SUMMARY',
58
- ])
59
-
60
- // 启动时间戳用于文件命名
61
- const STARTUP_TIMESTAMP = new Date().toISOString().replace(/[:.]/g, '-')
62
- const REQUEST_START_TIME = Date.now()
63
-
64
- // 路径配置 - 统一使用 ~/.kode 目录
65
- const KODE_DIR = join(homedir(), '.kode')
66
- function getProjectDir(cwd: string): string {
67
- return cwd.replace(/[^a-zA-Z0-9]/g, '-')
68
- }
69
-
70
- const DEBUG_PATHS = {
71
- base: () => join(KODE_DIR, getProjectDir(process.cwd()), 'debug'),
72
- detailed: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-detailed.log`),
73
- flow: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-flow.log`),
74
- api: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-api.log`),
75
- state: () => join(DEBUG_PATHS.base(), `${STARTUP_TIMESTAMP}-state.log`),
76
- }
77
-
78
- // 确保调试目录存在
79
- function ensureDebugDir() {
80
- const debugDir = DEBUG_PATHS.base()
81
- if (!existsSync(debugDir)) {
82
- mkdirSync(debugDir, { recursive: true })
83
- }
84
- }
85
-
86
- // 日志条目接口
87
- interface LogEntry {
88
- timestamp: string
89
- level: LogLevel
90
- phase: string
91
- requestId?: string
92
- data: any
93
- elapsed?: number
94
- }
95
-
96
- // 当前请求上下文
97
- class RequestContext {
98
- public readonly id: string
99
- public readonly startTime: number
100
- private phases: Map<string, number> = new Map()
101
-
102
- constructor() {
103
- this.id = randomUUID().slice(0, 8)
104
- this.startTime = Date.now()
105
- }
106
-
107
- markPhase(phase: string) {
108
- this.phases.set(phase, Date.now() - this.startTime)
109
- }
110
-
111
- getPhaseTime(phase: string): number {
112
- return this.phases.get(phase) || 0
113
- }
114
-
115
- getAllPhases(): Record<string, number> {
116
- return Object.fromEntries(this.phases)
117
- }
118
- }
119
-
120
- // 全局请求上下文管理
121
- const activeRequests = new Map<string, RequestContext>()
122
- let currentRequest: RequestContext | null = null
123
-
124
- // 核心日志记录函数
125
- function writeToFile(filePath: string, entry: LogEntry) {
126
- if (!isDebugMode()) return
127
-
128
- try {
129
- ensureDebugDir()
130
- const logLine =
131
- JSON.stringify(
132
- {
133
- ...entry,
134
- sessionId: SESSION_ID,
135
- pid: process.pid,
136
- uptime: Date.now() - REQUEST_START_TIME,
137
- },
138
- null,
139
- 2,
140
- ) + ',\n'
141
-
142
- appendFileSync(filePath, logLine)
143
- } catch (error) {
144
- // 静默失败,避免调试日志影响主功能
145
- }
146
- }
147
-
148
- // 日志去重机制
149
- const recentLogs = new Map<string, number>()
150
- const LOG_DEDUPE_WINDOW_MS = 5000 // 5秒内相同日志视为重复
151
-
152
- // 生成日志去重键
153
- function getDedupeKey(level: LogLevel, phase: string, data: any): string {
154
- // 对于配置相关的日志,使用文件路径和操作类型作为键
155
- if (phase.startsWith('CONFIG_')) {
156
- const file = data?.file || ''
157
- return `${level}:${phase}:${file}`
158
- }
159
-
160
- // 对于其他日志,使用阶段作为键
161
- return `${level}:${phase}`
162
- }
163
-
164
- // 检查是否应该记录日志(去重)
165
- function shouldLogWithDedupe(
166
- level: LogLevel,
167
- phase: string,
168
- data: any,
169
- ): boolean {
170
- const key = getDedupeKey(level, phase, data)
171
- const now = Date.now()
172
- const lastLogTime = recentLogs.get(key)
173
-
174
- // 如果是第一次记录,或者超过去重时间窗口,则允许记录
175
- if (!lastLogTime || now - lastLogTime > LOG_DEDUPE_WINDOW_MS) {
176
- recentLogs.set(key, now)
177
-
178
- // 清理过期的日志记录
179
- for (const [oldKey, oldTime] of recentLogs.entries()) {
180
- if (now - oldTime > LOG_DEDUPE_WINDOW_MS) {
181
- recentLogs.delete(oldKey)
182
- }
183
- }
184
-
185
- return true
186
- }
187
-
188
- return false
189
- }
190
- function formatMessages(messages: any): string {
191
- if (Array.isArray(messages)) {
192
- // 只显示最近 5 条消息
193
- const recentMessages = messages.slice(-5)
194
- return recentMessages
195
- .map((msg, index) => {
196
- const role = msg.role || 'unknown'
197
- let content = ''
198
-
199
- if (typeof msg.content === 'string') {
200
- // 每条消息最长 300 字符,超出省略
201
- content =
202
- msg.content.length > 300
203
- ? msg.content.substring(0, 300) + '...'
204
- : msg.content
205
- } else if (typeof msg.content === 'object') {
206
- content = '[complex_content]'
207
- } else {
208
- content = String(msg.content || '')
209
- }
210
-
211
- const totalIndex = messages.length - recentMessages.length + index
212
- return `[${totalIndex}] ${chalk.dim(role)}: ${content}`
213
- })
214
- .join('\n ')
215
- }
216
-
217
- if (typeof messages === 'string') {
218
- try {
219
- const parsed = JSON.parse(messages)
220
- if (Array.isArray(parsed)) {
221
- return formatMessages(parsed) // 递归处理解析后的数组
222
- }
223
- } catch {
224
- // 如果解析失败,返回截断的字符串
225
- }
226
- }
227
-
228
- // 对于非消息数组的长字符串,也进行截断
229
- if (typeof messages === 'string' && messages.length > 200) {
230
- return messages.substring(0, 200) + '...'
231
- }
232
-
233
- return typeof messages === 'string' ? messages : JSON.stringify(messages)
234
- }
235
-
236
- // 判断是否应该在终端显示日志
237
- function shouldShowInTerminal(level: LogLevel): boolean {
238
- if (!isDebugMode()) return false
239
-
240
- // 在调试详细模式下显示更多日志级别
241
- if (isDebugVerboseMode()) {
242
- return DEBUG_VERBOSE_TERMINAL_LOG_LEVELS.has(level)
243
- }
244
-
245
- // 默认只显示错误和警告
246
- return TERMINAL_LOG_LEVELS.has(level)
247
- }
248
-
249
- // 终端彩色输出
250
- function logToTerminal(entry: LogEntry) {
251
- // 使用新的过滤逻辑
252
- if (!shouldShowInTerminal(entry.level)) return
253
-
254
- const { level, phase, data, requestId, elapsed } = entry
255
- const timestamp = new Date().toISOString().slice(11, 23) // HH:mm:ss.SSS
256
-
257
- let prefix = ''
258
- let color = chalk.gray
259
-
260
- switch (level) {
261
- case LogLevel.FLOW:
262
- prefix = '🔄'
263
- color = chalk.cyan
264
- break
265
- case LogLevel.API:
266
- prefix = '🌐'
267
- color = chalk.yellow
268
- break
269
- case LogLevel.STATE:
270
- prefix = '📊'
271
- color = chalk.blue
272
- break
273
- case LogLevel.ERROR:
274
- prefix = '❌'
275
- color = chalk.red
276
- break
277
- case LogLevel.WARN:
278
- prefix = '⚠️'
279
- color = chalk.yellow
280
- break
281
- case LogLevel.INFO:
282
- prefix = 'ℹ️'
283
- color = chalk.green
284
- break
285
- case LogLevel.TRACE:
286
- prefix = '📈'
287
- color = chalk.magenta
288
- break
289
- default:
290
- prefix = '🔍'
291
- color = chalk.gray
292
- }
293
-
294
- const reqId = requestId ? chalk.dim(`[${requestId}]`) : ''
295
- const elapsedStr = elapsed !== undefined ? chalk.dim(`+${elapsed}ms`) : ''
296
-
297
- // 特殊处理一些数据格式
298
- let dataStr = ''
299
- if (typeof data === 'object' && data !== null) {
300
- if (data.messages) {
301
- // 格式化消息数组
302
- const formattedMessages = formatMessages(data.messages)
303
- dataStr = JSON.stringify(
304
- {
305
- ...data,
306
- messages: `\n ${formattedMessages}`,
307
- },
308
- null,
309
- 2,
310
- )
311
- } else {
312
- dataStr = JSON.stringify(data, null, 2)
313
- }
314
- } else {
315
- dataStr = typeof data === 'string' ? data : JSON.stringify(data)
316
- }
317
-
318
- console.log(
319
- `${color(`[${timestamp}]`)} ${prefix} ${color(phase)} ${reqId} ${dataStr} ${elapsedStr}`,
320
- )
321
- }
322
-
323
- // 主要调试日志函数
324
- export function debugLog(
325
- level: LogLevel,
326
- phase: string,
327
- data: any,
328
- requestId?: string,
329
- ) {
330
- if (!isDebugMode()) return
331
-
332
- // 检查是否应该记录(去重检查)
333
- if (!shouldLogWithDedupe(level, phase, data)) {
334
- return // 跳过重复的日志
335
- }
336
-
337
- const entry: LogEntry = {
338
- timestamp: new Date().toISOString(),
339
- level,
340
- phase,
341
- data,
342
- requestId: requestId || currentRequest?.id,
343
- elapsed: currentRequest ? Date.now() - currentRequest.startTime : undefined,
344
- }
345
-
346
- // 写入对应的日志文件
347
- writeToFile(DEBUG_PATHS.detailed(), entry)
348
-
349
- switch (level) {
350
- case LogLevel.FLOW:
351
- writeToFile(DEBUG_PATHS.flow(), entry)
352
- break
353
- case LogLevel.API:
354
- writeToFile(DEBUG_PATHS.api(), entry)
355
- break
356
- case LogLevel.STATE:
357
- writeToFile(DEBUG_PATHS.state(), entry)
358
- break
359
- }
360
-
361
- // 终端输出(也会被过滤)
362
- logToTerminal(entry)
363
- }
364
-
365
- // 便捷的日志函数
366
- export const debug = {
367
- flow: (phase: string, data: any, requestId?: string) =>
368
- debugLog(LogLevel.FLOW, phase, data, requestId),
369
-
370
- api: (phase: string, data: any, requestId?: string) =>
371
- debugLog(LogLevel.API, phase, data, requestId),
372
-
373
- state: (phase: string, data: any, requestId?: string) =>
374
- debugLog(LogLevel.STATE, phase, data, requestId),
375
-
376
- info: (phase: string, data: any, requestId?: string) =>
377
- debugLog(LogLevel.INFO, phase, data, requestId),
378
-
379
- warn: (phase: string, data: any, requestId?: string) =>
380
- debugLog(LogLevel.WARN, phase, data, requestId),
381
-
382
- error: (phase: string, data: any, requestId?: string) =>
383
- debugLog(LogLevel.ERROR, phase, data, requestId),
384
-
385
- trace: (phase: string, data: any, requestId?: string) =>
386
- debugLog(LogLevel.TRACE, phase, data, requestId),
387
-
388
- // 新增UI相关的调试函数 (只记录到文件,不显示在终端)
389
- ui: (phase: string, data: any, requestId?: string) =>
390
- debugLog(LogLevel.STATE, `UI_${phase}`, data, requestId),
391
-
392
- // 新增Statsig事件追踪
393
- statsig: (phase: string, data: any) => debugLog(LogLevel.TRACE, phase, data),
394
- }
395
-
396
- // 请求生命周期管理
397
- export function startRequest(): RequestContext {
398
- const ctx = new RequestContext()
399
- currentRequest = ctx
400
- activeRequests.set(ctx.id, ctx)
401
-
402
- debug.flow('REQUEST_START', {
403
- requestId: ctx.id,
404
- activeRequests: activeRequests.size,
405
- })
406
-
407
- return ctx
408
- }
409
-
410
- export function endRequest(ctx?: RequestContext) {
411
- const request = ctx || currentRequest
412
- if (!request) return
413
-
414
- debug.flow('REQUEST_END', {
415
- requestId: request.id,
416
- totalTime: Date.now() - request.startTime,
417
- phases: request.getAllPhases(),
418
- })
419
-
420
- activeRequests.delete(request.id)
421
- if (currentRequest === request) {
422
- currentRequest = null
423
- }
424
- }
425
-
426
- export function getCurrentRequest(): RequestContext | null {
427
- return currentRequest
428
- }
429
-
430
- // 阶段标记函数
431
- export function markPhase(phase: string, data?: any) {
432
- if (!currentRequest) return
433
-
434
- currentRequest.markPhase(phase)
435
- debug.flow(`PHASE_${phase.toUpperCase()}`, {
436
- requestId: currentRequest.id,
437
- elapsed: currentRequest.getPhaseTime(phase),
438
- data,
439
- })
440
- }
441
-
442
- // 新增:Reminder 事件日志记录
443
- export function logReminderEvent(
444
- eventType: string,
445
- reminderData: any,
446
- agentId?: string,
447
- ) {
448
- if (!isDebugMode()) return
449
-
450
- debug.info('REMINDER_EVENT_TRIGGERED', {
451
- eventType,
452
- agentId: agentId || 'default',
453
- reminderType: reminderData.type || 'unknown',
454
- reminderCategory: reminderData.category || 'general',
455
- reminderPriority: reminderData.priority || 'medium',
456
- contentLength: reminderData.content ? reminderData.content.length : 0,
457
- timestamp: Date.now(),
458
- })
459
- }
460
-
461
- // API错误日志功能
462
- export function logAPIError(context: {
463
- model: string
464
- endpoint: string
465
- status: number
466
- error: any
467
- request?: any
468
- response?: any
469
- provider?: string
470
- }) {
471
- const errorDir = join(KODE_DIR, 'logs', 'error', 'api')
472
-
473
- // 确保目录存在
474
- if (!existsSync(errorDir)) {
475
- try {
476
- mkdirSync(errorDir, { recursive: true })
477
- } catch (err) {
478
- console.error('Failed to create error log directory:', err)
479
- return // Exit early if we can't create the directory
480
- }
481
- }
482
-
483
- // 生成文件名
484
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
485
- const sanitizedModel = context.model.replace(/[^a-zA-Z0-9-_]/g, '_')
486
- const filename = `${sanitizedModel}_${timestamp}.log`
487
- const filepath = join(errorDir, filename)
488
-
489
- // 准备完整的日志内容(文件中保存所有信息)
490
- const fullLogContent = {
491
- timestamp: new Date().toISOString(),
492
- sessionId: SESSION_ID,
493
- requestId: getCurrentRequest()?.id,
494
- model: context.model,
495
- provider: context.provider,
496
- endpoint: context.endpoint,
497
- status: context.status,
498
- error: context.error,
499
- request: context.request, // 保存完整请求
500
- response: context.response, // 保存完整响应
501
- environment: {
502
- nodeVersion: process.version,
503
- platform: process.platform,
504
- cwd: process.cwd(),
505
- }
506
- }
507
-
508
- // 写入文件(保存完整信息)
509
- try {
510
- appendFileSync(filepath, JSON.stringify(fullLogContent, null, 2) + '\n')
511
- appendFileSync(filepath, '='.repeat(80) + '\n\n')
512
- } catch (err) {
513
- console.error('Failed to write API error log:', err)
514
- }
515
-
516
- // 在调试模式下记录到系统日志
517
- if (isDebugMode()) {
518
- debug.error('API_ERROR', {
519
- model: context.model,
520
- status: context.status,
521
- error: typeof context.error === 'string' ? context.error : context.error?.message || 'Unknown error',
522
- endpoint: context.endpoint,
523
- logFile: filename,
524
- })
525
- }
526
-
527
- // 优雅的终端显示(仅在verbose模式下)
528
- if (isVerboseMode() || isDebugVerboseMode()) {
529
- console.log()
530
- console.log(chalk.red('━'.repeat(60)))
531
- console.log(chalk.red.bold('⚠️ API Error'))
532
- console.log(chalk.red('━'.repeat(60)))
533
-
534
- // 显示关键信息
535
- console.log(chalk.white(' Model: ') + chalk.yellow(context.model))
536
- console.log(chalk.white(' Status: ') + chalk.red(context.status))
537
-
538
- // 格式化错误消息
539
- let errorMessage = 'Unknown error'
540
- if (typeof context.error === 'string') {
541
- errorMessage = context.error
542
- } else if (context.error?.message) {
543
- errorMessage = context.error.message
544
- } else if (context.error?.error?.message) {
545
- errorMessage = context.error.error.message
546
- }
547
-
548
- // 错误消息换行显示
549
- console.log(chalk.white(' Error: ') + chalk.red(errorMessage))
550
-
551
- // 如果有响应体,显示格式化的响应
552
- if (context.response) {
553
- console.log()
554
- console.log(chalk.gray(' Response:'))
555
- const responseStr = typeof context.response === 'string'
556
- ? context.response
557
- : JSON.stringify(context.response, null, 2)
558
-
559
- // 缩进显示响应内容
560
- responseStr.split('\n').forEach(line => {
561
- console.log(chalk.gray(' ' + line))
562
- })
563
- }
564
-
565
- console.log()
566
- console.log(chalk.dim(` 📁 Full log: ${filepath}`))
567
- console.log(chalk.red('━'.repeat(60)))
568
- console.log()
569
- }
570
- }
571
-
572
- // 新增:LLM 交互核心调试信息
573
- export function logLLMInteraction(context: {
574
- systemPrompt: string
575
- messages: any[]
576
- response: any
577
- usage?: { inputTokens: number; outputTokens: number }
578
- timing: { start: number; end: number }
579
- apiFormat?: 'anthropic' | 'openai'
580
- }) {
581
- if (!isDebugMode()) return
582
-
583
- const duration = context.timing.end - context.timing.start
584
-
585
- console.log('\n' + chalk.blue('🧠 LLM CALL DEBUG'))
586
- console.log(chalk.gray('━'.repeat(60)))
587
-
588
- // 显示上下文基本信息
589
- console.log(chalk.yellow('📊 Context Overview:'))
590
- console.log(` Messages Count: ${context.messages.length}`)
591
- console.log(` System Prompt Length: ${context.systemPrompt.length} chars`)
592
- console.log(` Duration: ${duration.toFixed(0)}ms`)
593
-
594
- if (context.usage) {
595
- console.log(
596
- ` Token Usage: ${context.usage.inputTokens} → ${context.usage.outputTokens}`,
597
- )
598
- }
599
-
600
- // 显示真实发送给 LLM API 的 messages(完整还原API调用)
601
- const apiLabel = context.apiFormat
602
- ? ` (${context.apiFormat.toUpperCase()})`
603
- : ''
604
- console.log(chalk.cyan(`\n💬 Real API Messages${apiLabel} (last 10):`))
605
-
606
- // 这里展示的是真正发送给LLM API的messages,不是内部处理的版本
607
- const recentMessages = context.messages.slice(-10)
608
- recentMessages.forEach((msg, index) => {
609
- const globalIndex = context.messages.length - recentMessages.length + index
610
- const roleColor =
611
- msg.role === 'user'
612
- ? 'green'
613
- : msg.role === 'assistant'
614
- ? 'blue'
615
- : msg.role === 'system'
616
- ? 'yellow'
617
- : 'gray'
618
-
619
- let content = ''
620
- let isReminder = false
621
-
622
- if (typeof msg.content === 'string') {
623
- // 检查是否是 system-reminder
624
- if (msg.content.includes('<system-reminder>')) {
625
- isReminder = true
626
- // 提取 reminder 的核心内容,显示更多字符,记得加省略号
627
- const reminderContent = msg.content
628
- .replace(/<\/?system-reminder>/g, '')
629
- .trim()
630
- content = `🔔 ${reminderContent.length > 800 ? reminderContent.substring(0, 800) + '...' : reminderContent}`
631
- } else {
632
- // 增加普通消息的显示字符数 - 用户消息和系统消息显示更多
633
- const maxLength =
634
- msg.role === 'user' ? 1000 : msg.role === 'system' ? 1200 : 800
635
- content =
636
- msg.content.length > maxLength
637
- ? msg.content.substring(0, maxLength) + '...'
638
- : msg.content
639
- }
640
- } else if (Array.isArray(msg.content)) {
641
- // Anthropic格式:content是对象数组
642
- const textBlocks = msg.content.filter(
643
- (block: any) => block.type === 'text',
644
- )
645
- const toolBlocks = msg.content.filter(
646
- (block: any) => block.type === 'tool_use',
647
- )
648
- if (textBlocks.length > 0) {
649
- const text = textBlocks[0].text || ''
650
- // Assistant消息显示更多内容
651
- const maxLength = msg.role === 'assistant' ? 1000 : 800
652
- content =
653
- text.length > maxLength ? text.substring(0, maxLength) + '...' : text
654
- }
655
- if (toolBlocks.length > 0) {
656
- content += ` [+ ${toolBlocks.length} tool calls]`
657
- }
658
- if (textBlocks.length === 0 && toolBlocks.length === 0) {
659
- content = `[${msg.content.length} blocks: ${msg.content.map(b => b.type || 'unknown').join(', ')}]`
660
- }
661
- } else {
662
- content = '[complex_content]'
663
- }
664
-
665
- // 根据消息类型使用不同的显示样式 - 更友好的视觉格式
666
- if (isReminder) {
667
- console.log(
668
- ` [${globalIndex}] ${chalk.magenta('🔔 REMINDER')}: ${chalk.dim(content)}`,
669
- )
670
- } else {
671
- // 为不同角色添加图标
672
- const roleIcon =
673
- msg.role === 'user'
674
- ? '👤'
675
- : msg.role === 'assistant'
676
- ? '🤖'
677
- : msg.role === 'system'
678
- ? '⚙️'
679
- : '📄'
680
- console.log(
681
- ` [${globalIndex}] ${(chalk as any)[roleColor](roleIcon + ' ' + msg.role.toUpperCase())}: ${content}`,
682
- )
683
- }
684
-
685
- // 显示工具调用信息(Anthropic格式)- 更清晰的格式
686
- if (msg.role === 'assistant' && Array.isArray(msg.content)) {
687
- const toolCalls = msg.content.filter(
688
- (block: any) => block.type === 'tool_use',
689
- )
690
- if (toolCalls.length > 0) {
691
- console.log(
692
- chalk.cyan(
693
- ` 🔧 → Tool calls (${toolCalls.length}): ${toolCalls.map((t: any) => t.name).join(', ')}`,
694
- ),
695
- )
696
- // 显示每个工具的详细参数
697
- toolCalls.forEach((tool: any, idx: number) => {
698
- const inputStr = JSON.stringify(tool.input || {})
699
- const maxLength = 200
700
- const displayInput =
701
- inputStr.length > maxLength
702
- ? inputStr.substring(0, maxLength) + '...'
703
- : inputStr
704
- console.log(
705
- chalk.dim(` [${idx}] ${tool.name}: ${displayInput}`),
706
- )
707
- })
708
- }
709
- }
710
- // OpenAI格式的工具调用
711
- if (msg.tool_calls && msg.tool_calls.length > 0) {
712
- console.log(
713
- chalk.cyan(
714
- ` 🔧 → Tool calls (${msg.tool_calls.length}): ${msg.tool_calls.map((t: any) => t.function.name).join(', ')}`,
715
- ),
716
- )
717
- msg.tool_calls.forEach((tool: any, idx: number) => {
718
- const inputStr = tool.function.arguments || '{}'
719
- const maxLength = 200
720
- const displayInput =
721
- inputStr.length > maxLength
722
- ? inputStr.substring(0, maxLength) + '...'
723
- : inputStr
724
- console.log(
725
- chalk.dim(` [${idx}] ${tool.function.name}: ${displayInput}`),
726
- )
727
- })
728
- }
729
- })
730
-
731
- // 显示 LLM 响应核心信息 - 更详细友好的格式
732
- console.log(chalk.magenta('\n🤖 LLM Response:'))
733
-
734
- // Handle different response formats (Anthropic vs OpenAI)
735
- let responseContent = ''
736
- let toolCalls: any[] = []
737
-
738
- if (Array.isArray(context.response.content)) {
739
- // Anthropic format: content is array of blocks
740
- const textBlocks = context.response.content.filter(
741
- (block: any) => block.type === 'text',
742
- )
743
- responseContent = textBlocks.length > 0 ? textBlocks[0].text || '' : ''
744
- toolCalls = context.response.content.filter(
745
- (block: any) => block.type === 'tool_use',
746
- )
747
- } else if (typeof context.response.content === 'string') {
748
- // OpenAI format: content might be string
749
- responseContent = context.response.content
750
- // Tool calls are separate in OpenAI format
751
- toolCalls = context.response.tool_calls || []
752
- } else {
753
- responseContent = JSON.stringify(context.response.content || '')
754
- }
755
-
756
- // 显示更多响应内容
757
- const maxResponseLength = 1000
758
- const displayContent =
759
- responseContent.length > maxResponseLength
760
- ? responseContent.substring(0, maxResponseLength) + '...'
761
- : responseContent
762
- console.log(` Content: ${displayContent}`)
763
-
764
- if (toolCalls.length > 0) {
765
- const toolNames = toolCalls.map(
766
- (t: any) => t.name || t.function?.name || 'unknown',
767
- )
768
- console.log(
769
- chalk.cyan(
770
- ` 🔧 Tool Calls (${toolCalls.length}): ${toolNames.join(', ')}`,
771
- ),
772
- )
773
- toolCalls.forEach((tool: any, index: number) => {
774
- const toolName = tool.name || tool.function?.name || 'unknown'
775
- const toolInput = tool.input || tool.function?.arguments || '{}'
776
- const inputStr =
777
- typeof toolInput === 'string' ? toolInput : JSON.stringify(toolInput)
778
- // 显示更多工具参数内容
779
- const maxToolInputLength = 300
780
- const displayInput =
781
- inputStr.length > maxToolInputLength
782
- ? inputStr.substring(0, maxToolInputLength) + '...'
783
- : inputStr
784
- console.log(chalk.dim(` [${index}] ${toolName}: ${displayInput}`))
785
- })
786
- }
787
-
788
- console.log(
789
- ` Stop Reason: ${context.response.stop_reason || context.response.finish_reason || 'unknown'}`,
790
- )
791
- console.log(chalk.gray('━'.repeat(60)))
792
- }
793
-
794
- // 新增:系统提示构建过程调试
795
- export function logSystemPromptConstruction(construction: {
796
- basePrompt: string
797
- kodeContext?: string
798
- reminders: string[]
799
- finalPrompt: string
800
- }) {
801
- if (!isDebugMode()) return
802
-
803
- console.log('\n' + chalk.yellow('📝 SYSTEM PROMPT CONSTRUCTION'))
804
- console.log(` Base Prompt: ${construction.basePrompt.length} chars`)
805
-
806
- if (construction.kodeContext) {
807
- console.log(` + Kode Context: ${construction.kodeContext.length} chars`)
808
- }
809
-
810
- if (construction.reminders.length > 0) {
811
- console.log(
812
- ` + Dynamic Reminders: ${construction.reminders.length} items`,
813
- )
814
- construction.reminders.forEach((reminder, index) => {
815
- console.log(chalk.dim(` [${index}] ${reminder.substring(0, 80)}...`))
816
- })
817
- }
818
-
819
- console.log(` = Final Length: ${construction.finalPrompt.length} chars`)
820
- }
821
-
822
- // 新增:上下文压缩过程调试
823
- export function logContextCompression(compression: {
824
- beforeMessages: number
825
- afterMessages: number
826
- trigger: string
827
- preservedFiles: string[]
828
- compressionRatio: number
829
- }) {
830
- if (!isDebugMode()) return
831
-
832
- console.log('\n' + chalk.red('🗜️ CONTEXT COMPRESSION'))
833
- console.log(` Trigger: ${compression.trigger}`)
834
- console.log(
835
- ` Messages: ${compression.beforeMessages} → ${compression.afterMessages}`,
836
- )
837
- console.log(
838
- ` Compression Ratio: ${(compression.compressionRatio * 100).toFixed(1)}%`,
839
- )
840
-
841
- if (compression.preservedFiles.length > 0) {
842
- console.log(` Preserved Files: ${compression.preservedFiles.join(', ')}`)
843
- }
844
- }
845
-
846
- // 新增:用户友好的日志显示
847
- export function logUserFriendly(type: string, data: any, requestId?: string) {
848
- if (!isDebugMode()) return
849
-
850
- const timestamp = new Date().toLocaleTimeString()
851
- let message = ''
852
- let color = chalk.gray
853
- let icon = '•'
854
-
855
- switch (type) {
856
- case 'SESSION_START':
857
- icon = '🚀'
858
- color = chalk.green
859
- message = `Session started with ${data.model || 'default model'}`
860
- break
861
- case 'QUERY_START':
862
- icon = '💭'
863
- color = chalk.blue
864
- message = `Processing query: "${data.query?.substring(0, 50)}${data.query?.length > 50 ? '...' : ''}"`
865
- break
866
- case 'QUERY_PROGRESS':
867
- icon = '⏳'
868
- color = chalk.yellow
869
- message = `${data.phase} (${data.elapsed}ms)`
870
- break
871
- case 'QUERY_COMPLETE':
872
- icon = '✅'
873
- color = chalk.green
874
- message = `Query completed in ${data.duration}ms - Cost: $${data.cost} - ${data.tokens} tokens`
875
- break
876
- case 'TOOL_EXECUTION':
877
- icon = '🔧'
878
- color = chalk.cyan
879
- message = `${data.toolName}: ${data.action} ${data.target ? '→ ' + data.target : ''}`
880
- break
881
- case 'ERROR_OCCURRED':
882
- icon = '❌'
883
- color = chalk.red
884
- message = `${data.error} ${data.context ? '(' + data.context + ')' : ''}`
885
- break
886
- case 'PERFORMANCE_SUMMARY':
887
- icon = '📊'
888
- color = chalk.magenta
889
- message = `Session: ${data.queries} queries, $${data.totalCost}, ${data.avgResponseTime}ms avg`
890
- break
891
- default:
892
- message = JSON.stringify(data)
893
- }
894
-
895
- const reqId = requestId ? chalk.dim(`[${requestId.slice(0, 8)}]`) : ''
896
- console.log(`${color(`[${timestamp}]`)} ${icon} ${color(message)} ${reqId}`)
897
- }
898
-
899
- // 初始化日志系统
900
- export function initDebugLogger() {
901
- if (!isDebugMode()) return
902
-
903
- debug.info('DEBUG_LOGGER_INIT', {
904
- startupTimestamp: STARTUP_TIMESTAMP,
905
- sessionId: SESSION_ID,
906
- debugPaths: {
907
- detailed: DEBUG_PATHS.detailed(),
908
- flow: DEBUG_PATHS.flow(),
909
- api: DEBUG_PATHS.api(),
910
- state: DEBUG_PATHS.state(),
911
- },
912
- })
913
-
914
- // 显示终端输出过滤信息
915
- const terminalLevels = isDebugVerboseMode()
916
- ? Array.from(DEBUG_VERBOSE_TERMINAL_LOG_LEVELS).join(', ')
917
- : Array.from(TERMINAL_LOG_LEVELS).join(', ')
918
-
919
- console.log(
920
- chalk.dim(`[DEBUG] Terminal output filtered to: ${terminalLevels}`),
921
- )
922
- console.log(
923
- chalk.dim(`[DEBUG] Complete logs saved to: ${DEBUG_PATHS.base()}`),
924
- )
925
- if (!isDebugVerboseMode()) {
926
- console.log(
927
- chalk.dim(
928
- `[DEBUG] Use --debug-verbose for detailed system logs (FLOW, API, STATE)`,
929
- ),
930
- )
931
- }
932
- }
933
-
934
- // 新增:错误诊断和恢复建议系统
935
- interface ErrorDiagnosis {
936
- errorType: string
937
- category:
938
- | 'NETWORK'
939
- | 'API'
940
- | 'PERMISSION'
941
- | 'CONFIG'
942
- | 'SYSTEM'
943
- | 'USER_INPUT'
944
- severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
945
- description: string
946
- suggestions: string[]
947
- debugSteps: string[]
948
- relatedLogs?: string[]
949
- }
950
-
951
- export function diagnoseError(error: any, context?: any): ErrorDiagnosis {
952
- const errorMessage = error instanceof Error ? error.message : String(error)
953
- const errorStack = error instanceof Error ? error.stack : undefined
954
-
955
- // AbortController 相关错误
956
- if (
957
- errorMessage.includes('aborted') ||
958
- errorMessage.includes('AbortController')
959
- ) {
960
- return {
961
- errorType: 'REQUEST_ABORTED',
962
- category: 'SYSTEM',
963
- severity: 'MEDIUM',
964
- description:
965
- 'Request was aborted, often due to user cancellation or timeout',
966
- suggestions: [
967
- '检查是否按下了 ESC 键取消请求',
968
- '检查网络连接是否稳定',
969
- '验证 AbortController 状态: isActive 和 signal.aborted 应该一致',
970
- '查看是否有重复的请求导致冲突',
971
- ],
972
- debugSteps: [
973
- '使用 --debug-verbose 模式查看详细的请求流程',
974
- '检查 debug 日志中的 BINARY_FEEDBACK_* 事件',
975
- '验证 REQUEST_START 和 REQUEST_END 日志配对',
976
- '查看 QUERY_ABORTED 事件的触发原因',
977
- ],
978
- }
979
- }
980
-
981
- // API 密钥相关错误
982
- if (
983
- errorMessage.includes('api-key') ||
984
- errorMessage.includes('authentication') ||
985
- errorMessage.includes('401')
986
- ) {
987
- return {
988
- errorType: 'API_AUTHENTICATION',
989
- category: 'API',
990
- severity: 'HIGH',
991
- description: 'API authentication failed - invalid or missing API key',
992
- suggestions: [
993
- '运行 /login 重新设置 API 密钥',
994
- '检查 ~/.kode/ 配置文件中的 API 密钥',
995
- '验证 API 密钥是否已过期或被撤销',
996
- '确认使用的 provider 设置正确 (anthropic/opendev/bigdream)',
997
- ],
998
- debugSteps: [
999
- '检查 CONFIG_LOAD 日志中的 provider 和 API 密钥状态',
1000
- '运行 kode doctor 检查系统健康状态',
1001
- '查看 API_ERROR 日志了解详细错误信息',
1002
- '使用 kode config 命令查看当前配置',
1003
- ],
1004
- }
1005
- }
1006
-
1007
- // 网络连接错误
1008
- if (
1009
- errorMessage.includes('ECONNREFUSED') ||
1010
- errorMessage.includes('ENOTFOUND') ||
1011
- errorMessage.includes('timeout')
1012
- ) {
1013
- return {
1014
- errorType: 'NETWORK_CONNECTION',
1015
- category: 'NETWORK',
1016
- severity: 'HIGH',
1017
- description: 'Network connection failed - unable to reach API endpoint',
1018
- suggestions: [
1019
- '检查网络连接是否正常',
1020
- '确认防火墙没有阻止相关端口',
1021
- '检查 proxy 设置是否正确',
1022
- '尝试切换到不同的网络环境',
1023
- '验证 baseURL 配置是否正确',
1024
- ],
1025
- debugSteps: [
1026
- '检查 API_REQUEST_START 和相关网络日志',
1027
- '查看 LLM_REQUEST_ERROR 中的详细错误信息',
1028
- '使用 ping 或 curl 测试 API 端点连通性',
1029
- '检查企业网络是否需要代理设置',
1030
- ],
1031
- }
1032
- }
1033
-
1034
- // 权限相关错误
1035
- if (
1036
- errorMessage.includes('permission') ||
1037
- errorMessage.includes('EACCES') ||
1038
- errorMessage.includes('denied')
1039
- ) {
1040
- return {
1041
- errorType: 'PERMISSION_DENIED',
1042
- category: 'PERMISSION',
1043
- severity: 'MEDIUM',
1044
- description: 'Permission denied - insufficient access rights',
1045
- suggestions: [
1046
- '检查文件和目录的读写权限',
1047
- '确认当前用户有足够的系统权限',
1048
- '查看是否需要管理员权限运行',
1049
- '检查工具权限设置是否正确配置',
1050
- ],
1051
- debugSteps: [
1052
- '查看 PERMISSION_* 日志了解权限检查过程',
1053
- '检查文件系统权限: ls -la',
1054
- '验证工具审批状态',
1055
- '查看 TOOL_* 相关的调试日志',
1056
- ],
1057
- }
1058
- }
1059
-
1060
- // LLM 响应格式错误
1061
- if (
1062
- errorMessage.includes('substring is not a function') ||
1063
- errorMessage.includes('content')
1064
- ) {
1065
- return {
1066
- errorType: 'RESPONSE_FORMAT',
1067
- category: 'API',
1068
- severity: 'MEDIUM',
1069
- description: 'LLM response format mismatch between different providers',
1070
- suggestions: [
1071
- '检查当前使用的 provider 是否与期望一致',
1072
- '验证响应格式处理逻辑',
1073
- '确认不同 provider 的响应格式差异',
1074
- '检查是否需要更新响应解析代码',
1075
- ],
1076
- debugSteps: [
1077
- '查看 LLM_CALL_DEBUG 中的响应格式',
1078
- '检查 provider 配置和实际使用的 API',
1079
- '对比 Anthropic 和 OpenAI 响应格式差异',
1080
- '验证 logLLMInteraction 函数的格式处理',
1081
- ],
1082
- }
1083
- }
1084
-
1085
- // 上下文窗口溢出
1086
- if (
1087
- errorMessage.includes('too long') ||
1088
- errorMessage.includes('context') ||
1089
- errorMessage.includes('token')
1090
- ) {
1091
- return {
1092
- errorType: 'CONTEXT_OVERFLOW',
1093
- category: 'SYSTEM',
1094
- severity: 'MEDIUM',
1095
- description: 'Context window exceeded - conversation too long',
1096
- suggestions: [
1097
- '运行 /compact 手动压缩对话历史',
1098
- '检查自动压缩设置是否正确配置',
1099
- '减少单次输入的内容长度',
1100
- '清理不必要的上下文信息',
1101
- ],
1102
- debugSteps: [
1103
- '查看 AUTO_COMPACT_* 日志检查压缩触发',
1104
- '检查 token 使用量和阈值',
1105
- '查看 CONTEXT_COMPRESSION 相关日志',
1106
- '验证模型的最大 token 限制',
1107
- ],
1108
- }
1109
- }
1110
-
1111
- // 配置相关错误
1112
- if (
1113
- errorMessage.includes('config') ||
1114
- (errorMessage.includes('undefined') && context?.configRelated)
1115
- ) {
1116
- return {
1117
- errorType: 'CONFIGURATION',
1118
- category: 'CONFIG',
1119
- severity: 'MEDIUM',
1120
- description: 'Configuration error - missing or invalid settings',
1121
- suggestions: [
1122
- '运行 kode config 检查配置设置',
1123
- '删除损坏的配置文件重新初始化',
1124
- '检查 JSON 配置文件语法是否正确',
1125
- '验证环境变量设置',
1126
- ],
1127
- debugSteps: [
1128
- '查看 CONFIG_LOAD 和 CONFIG_SAVE 日志',
1129
- '检查配置文件路径和权限',
1130
- '验证 JSON 格式: cat ~/.kode/config.json | jq',
1131
- '查看配置缓存相关的调试信息',
1132
- ],
1133
- }
1134
- }
1135
-
1136
- // 通用错误兜底
1137
- return {
1138
- errorType: 'UNKNOWN',
1139
- category: 'SYSTEM',
1140
- severity: 'MEDIUM',
1141
- description: `Unexpected error: ${errorMessage}`,
1142
- suggestions: [
1143
- '重新启动应用程序',
1144
- '检查系统资源是否充足',
1145
- '查看完整的错误日志获取更多信息',
1146
- '如果问题持续,请报告此错误',
1147
- ],
1148
- debugSteps: [
1149
- '使用 --debug-verbose 获取详细日志',
1150
- '检查 error.log 中的完整错误信息',
1151
- '查看系统资源使用情况',
1152
- '收集重现步骤和环境信息',
1153
- ],
1154
- relatedLogs: errorStack ? [errorStack] : undefined,
1155
- }
1156
- }
1157
-
1158
- export function logErrorWithDiagnosis(
1159
- error: any,
1160
- context?: any,
1161
- requestId?: string,
1162
- ) {
1163
- if (!isDebugMode()) return
1164
-
1165
- const diagnosis = diagnoseError(error, context)
1166
- const errorMessage = error instanceof Error ? error.message : String(error)
1167
-
1168
- // 记录标准错误日志
1169
- debug.error(
1170
- 'ERROR_OCCURRED',
1171
- {
1172
- error: errorMessage,
1173
- errorType: diagnosis.errorType,
1174
- category: diagnosis.category,
1175
- severity: diagnosis.severity,
1176
- context,
1177
- },
1178
- requestId,
1179
- )
1180
-
1181
- // 在终端显示诊断信息
1182
- console.log('\n' + chalk.red('🚨 ERROR DIAGNOSIS'))
1183
- console.log(chalk.gray('━'.repeat(60)))
1184
-
1185
- console.log(chalk.red(`❌ ${diagnosis.errorType}`))
1186
- console.log(
1187
- chalk.dim(
1188
- `Category: ${diagnosis.category} | Severity: ${diagnosis.severity}`,
1189
- ),
1190
- )
1191
- console.log(`\n${diagnosis.description}`)
1192
-
1193
- console.log(chalk.yellow('\n💡 Recovery Suggestions:'))
1194
- diagnosis.suggestions.forEach((suggestion, index) => {
1195
- console.log(` ${index + 1}. ${suggestion}`)
1196
- })
1197
-
1198
- console.log(chalk.cyan('\n🔍 Debug Steps:'))
1199
- diagnosis.debugSteps.forEach((step, index) => {
1200
- console.log(` ${index + 1}. ${step}`)
1201
- })
1202
-
1203
- if (diagnosis.relatedLogs && diagnosis.relatedLogs.length > 0) {
1204
- console.log(chalk.magenta('\n📋 Related Information:'))
1205
- diagnosis.relatedLogs.forEach((log, index) => {
1206
- const truncatedLog =
1207
- log.length > 200 ? log.substring(0, 200) + '...' : log
1208
- console.log(chalk.dim(` ${truncatedLog}`))
1209
- })
1210
- }
1211
-
1212
- const debugPath = DEBUG_PATHS.base()
1213
- console.log(chalk.gray(`\n📁 Complete logs: ${debugPath}`))
1214
- console.log(chalk.gray('━'.repeat(60)))
1215
- }
1216
- export function getDebugInfo() {
1217
- return {
1218
- isDebugMode: isDebugMode(),
1219
- isVerboseMode: isVerboseMode(),
1220
- isDebugVerboseMode: isDebugVerboseMode(),
1221
- startupTimestamp: STARTUP_TIMESTAMP,
1222
- sessionId: SESSION_ID,
1223
- currentRequest: currentRequest?.id,
1224
- activeRequests: Array.from(activeRequests.keys()),
1225
- terminalLogLevels: isDebugVerboseMode()
1226
- ? Array.from(DEBUG_VERBOSE_TERMINAL_LOG_LEVELS)
1227
- : Array.from(TERMINAL_LOG_LEVELS),
1228
- debugPaths: {
1229
- detailed: DEBUG_PATHS.detailed(),
1230
- flow: DEBUG_PATHS.flow(),
1231
- api: DEBUG_PATHS.api(),
1232
- state: DEBUG_PATHS.state(),
1233
- },
1234
- }
1235
- }