@shareai-lab/kode 1.1.13 → 1.1.16

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 (288) hide show
  1. package/dist/entrypoints/cli.js +2 -1
  2. package/dist/entrypoints/cli.js.map +2 -2
  3. package/dist/index.js +5 -26
  4. package/dist/package.json +4 -1
  5. package/package.json +9 -104
  6. package/dist/test/testAdapters.js +0 -88
  7. package/dist/test/testAdapters.js.map +0 -1
  8. package/src/ProjectOnboarding.tsx +0 -198
  9. package/src/Tool.ts +0 -83
  10. package/src/commands/agents.tsx +0 -3416
  11. package/src/commands/approvedTools.ts +0 -53
  12. package/src/commands/bug.tsx +0 -20
  13. package/src/commands/clear.ts +0 -43
  14. package/src/commands/compact.ts +0 -120
  15. package/src/commands/config.tsx +0 -19
  16. package/src/commands/cost.ts +0 -18
  17. package/src/commands/ctx_viz.ts +0 -209
  18. package/src/commands/doctor.ts +0 -24
  19. package/src/commands/help.tsx +0 -19
  20. package/src/commands/init.ts +0 -37
  21. package/src/commands/listen.ts +0 -42
  22. package/src/commands/login.tsx +0 -51
  23. package/src/commands/logout.tsx +0 -40
  24. package/src/commands/mcp.ts +0 -41
  25. package/src/commands/model.tsx +0 -40
  26. package/src/commands/modelstatus.tsx +0 -20
  27. package/src/commands/onboarding.tsx +0 -34
  28. package/src/commands/pr_comments.ts +0 -59
  29. package/src/commands/refreshCommands.ts +0 -54
  30. package/src/commands/release-notes.ts +0 -34
  31. package/src/commands/resume.tsx +0 -31
  32. package/src/commands/review.ts +0 -49
  33. package/src/commands/terminalSetup.ts +0 -221
  34. package/src/commands.ts +0 -139
  35. package/src/components/ApproveApiKey.tsx +0 -93
  36. package/src/components/AsciiLogo.tsx +0 -13
  37. package/src/components/AutoUpdater.tsx +0 -148
  38. package/src/components/Bug.tsx +0 -367
  39. package/src/components/Config.tsx +0 -293
  40. package/src/components/ConsoleOAuthFlow.tsx +0 -327
  41. package/src/components/Cost.tsx +0 -23
  42. package/src/components/CostThresholdDialog.tsx +0 -46
  43. package/src/components/CustomSelect/option-map.ts +0 -42
  44. package/src/components/CustomSelect/select-option.tsx +0 -78
  45. package/src/components/CustomSelect/select.tsx +0 -152
  46. package/src/components/CustomSelect/theme.ts +0 -45
  47. package/src/components/CustomSelect/use-select-state.ts +0 -414
  48. package/src/components/CustomSelect/use-select.ts +0 -35
  49. package/src/components/FallbackToolUseRejectedMessage.tsx +0 -15
  50. package/src/components/FileEditToolUpdatedMessage.tsx +0 -66
  51. package/src/components/Help.tsx +0 -215
  52. package/src/components/HighlightedCode.tsx +0 -33
  53. package/src/components/InvalidConfigDialog.tsx +0 -113
  54. package/src/components/Link.tsx +0 -32
  55. package/src/components/LogSelector.tsx +0 -86
  56. package/src/components/Logo.tsx +0 -170
  57. package/src/components/MCPServerApprovalDialog.tsx +0 -100
  58. package/src/components/MCPServerDialogCopy.tsx +0 -25
  59. package/src/components/MCPServerMultiselectDialog.tsx +0 -109
  60. package/src/components/Message.tsx +0 -221
  61. package/src/components/MessageResponse.tsx +0 -15
  62. package/src/components/MessageSelector.tsx +0 -211
  63. package/src/components/ModeIndicator.tsx +0 -88
  64. package/src/components/ModelConfig.tsx +0 -301
  65. package/src/components/ModelListManager.tsx +0 -227
  66. package/src/components/ModelSelector.tsx +0 -3387
  67. package/src/components/ModelStatusDisplay.tsx +0 -230
  68. package/src/components/Onboarding.tsx +0 -274
  69. package/src/components/PressEnterToContinue.tsx +0 -11
  70. package/src/components/PromptInput.tsx +0 -760
  71. package/src/components/SentryErrorBoundary.ts +0 -39
  72. package/src/components/Spinner.tsx +0 -129
  73. package/src/components/StickerRequestForm.tsx +0 -16
  74. package/src/components/StructuredDiff.tsx +0 -191
  75. package/src/components/TextInput.tsx +0 -259
  76. package/src/components/TodoItem.tsx +0 -47
  77. package/src/components/TokenWarning.tsx +0 -31
  78. package/src/components/ToolUseLoader.tsx +0 -40
  79. package/src/components/TrustDialog.tsx +0 -106
  80. package/src/components/binary-feedback/BinaryFeedback.tsx +0 -63
  81. package/src/components/binary-feedback/BinaryFeedbackOption.tsx +0 -111
  82. package/src/components/binary-feedback/BinaryFeedbackView.tsx +0 -172
  83. package/src/components/binary-feedback/utils.ts +0 -220
  84. package/src/components/messages/AssistantBashOutputMessage.tsx +0 -22
  85. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +0 -49
  86. package/src/components/messages/AssistantRedactedThinkingMessage.tsx +0 -19
  87. package/src/components/messages/AssistantTextMessage.tsx +0 -144
  88. package/src/components/messages/AssistantThinkingMessage.tsx +0 -40
  89. package/src/components/messages/AssistantToolUseMessage.tsx +0 -132
  90. package/src/components/messages/TaskProgressMessage.tsx +0 -32
  91. package/src/components/messages/TaskToolMessage.tsx +0 -58
  92. package/src/components/messages/UserBashInputMessage.tsx +0 -28
  93. package/src/components/messages/UserCommandMessage.tsx +0 -30
  94. package/src/components/messages/UserKodingInputMessage.tsx +0 -28
  95. package/src/components/messages/UserPromptMessage.tsx +0 -35
  96. package/src/components/messages/UserTextMessage.tsx +0 -39
  97. package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +0 -12
  98. package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +0 -36
  99. package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +0 -31
  100. package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +0 -57
  101. package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +0 -35
  102. package/src/components/messages/UserToolResultMessage/utils.tsx +0 -56
  103. package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +0 -121
  104. package/src/components/permissions/FallbackPermissionRequest.tsx +0 -153
  105. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +0 -182
  106. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +0 -77
  107. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +0 -164
  108. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +0 -83
  109. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +0 -240
  110. package/src/components/permissions/PermissionRequest.tsx +0 -101
  111. package/src/components/permissions/PermissionRequestTitle.tsx +0 -69
  112. package/src/components/permissions/hooks.ts +0 -44
  113. package/src/components/permissions/toolUseOptions.ts +0 -59
  114. package/src/components/permissions/utils.ts +0 -23
  115. package/src/constants/betas.ts +0 -5
  116. package/src/constants/claude-asterisk-ascii-art.tsx +0 -238
  117. package/src/constants/figures.ts +0 -4
  118. package/src/constants/keys.ts +0 -3
  119. package/src/constants/macros.ts +0 -11
  120. package/src/constants/modelCapabilities.ts +0 -179
  121. package/src/constants/models.ts +0 -1025
  122. package/src/constants/oauth.ts +0 -18
  123. package/src/constants/product.ts +0 -17
  124. package/src/constants/prompts.ts +0 -168
  125. package/src/constants/releaseNotes.ts +0 -7
  126. package/src/context/PermissionContext.tsx +0 -149
  127. package/src/context.ts +0 -278
  128. package/src/cost-tracker.ts +0 -84
  129. package/src/entrypoints/cli.tsx +0 -1561
  130. package/src/entrypoints/mcp.ts +0 -175
  131. package/src/history.ts +0 -25
  132. package/src/hooks/useApiKeyVerification.ts +0 -59
  133. package/src/hooks/useArrowKeyHistory.ts +0 -55
  134. package/src/hooks/useCanUseTool.ts +0 -138
  135. package/src/hooks/useCancelRequest.ts +0 -39
  136. package/src/hooks/useDoublePress.ts +0 -41
  137. package/src/hooks/useExitOnCtrlCD.ts +0 -31
  138. package/src/hooks/useInterval.ts +0 -25
  139. package/src/hooks/useLogMessages.ts +0 -16
  140. package/src/hooks/useLogStartupTime.ts +0 -12
  141. package/src/hooks/useNotifyAfterTimeout.ts +0 -65
  142. package/src/hooks/usePermissionRequestLogging.ts +0 -44
  143. package/src/hooks/useTerminalSize.ts +0 -49
  144. package/src/hooks/useTextInput.ts +0 -317
  145. package/src/hooks/useUnifiedCompletion.ts +0 -1405
  146. package/src/index.ts +0 -34
  147. package/src/messages.ts +0 -38
  148. package/src/permissions.ts +0 -268
  149. package/src/query.ts +0 -720
  150. package/src/screens/ConfigureNpmPrefix.tsx +0 -197
  151. package/src/screens/Doctor.tsx +0 -219
  152. package/src/screens/LogList.tsx +0 -68
  153. package/src/screens/REPL.tsx +0 -813
  154. package/src/screens/ResumeConversation.tsx +0 -68
  155. package/src/services/adapters/base.ts +0 -38
  156. package/src/services/adapters/chatCompletions.ts +0 -90
  157. package/src/services/adapters/responsesAPI.ts +0 -170
  158. package/src/services/browserMocks.ts +0 -66
  159. package/src/services/claude.ts +0 -2197
  160. package/src/services/customCommands.ts +0 -704
  161. package/src/services/fileFreshness.ts +0 -377
  162. package/src/services/gpt5ConnectionTest.ts +0 -340
  163. package/src/services/mcpClient.ts +0 -564
  164. package/src/services/mcpServerApproval.tsx +0 -50
  165. package/src/services/mentionProcessor.ts +0 -273
  166. package/src/services/modelAdapterFactory.ts +0 -69
  167. package/src/services/notifier.ts +0 -40
  168. package/src/services/oauth.ts +0 -357
  169. package/src/services/openai.ts +0 -1359
  170. package/src/services/responseStateManager.ts +0 -90
  171. package/src/services/sentry.ts +0 -3
  172. package/src/services/statsig.ts +0 -172
  173. package/src/services/statsigStorage.ts +0 -86
  174. package/src/services/systemReminder.ts +0 -507
  175. package/src/services/vcr.ts +0 -161
  176. package/src/test/testAdapters.ts +0 -96
  177. package/src/tools/ArchitectTool/ArchitectTool.tsx +0 -135
  178. package/src/tools/ArchitectTool/prompt.ts +0 -15
  179. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +0 -576
  180. package/src/tools/BashTool/BashTool.tsx +0 -243
  181. package/src/tools/BashTool/BashToolResultMessage.tsx +0 -38
  182. package/src/tools/BashTool/OutputLine.tsx +0 -49
  183. package/src/tools/BashTool/prompt.ts +0 -174
  184. package/src/tools/BashTool/utils.ts +0 -56
  185. package/src/tools/FileEditTool/FileEditTool.tsx +0 -319
  186. package/src/tools/FileEditTool/prompt.ts +0 -51
  187. package/src/tools/FileEditTool/utils.ts +0 -58
  188. package/src/tools/FileReadTool/FileReadTool.tsx +0 -404
  189. package/src/tools/FileReadTool/prompt.ts +0 -7
  190. package/src/tools/FileWriteTool/FileWriteTool.tsx +0 -301
  191. package/src/tools/FileWriteTool/prompt.ts +0 -10
  192. package/src/tools/GlobTool/GlobTool.tsx +0 -119
  193. package/src/tools/GlobTool/prompt.ts +0 -8
  194. package/src/tools/GrepTool/GrepTool.tsx +0 -147
  195. package/src/tools/GrepTool/prompt.ts +0 -11
  196. package/src/tools/MCPTool/MCPTool.tsx +0 -107
  197. package/src/tools/MCPTool/prompt.ts +0 -3
  198. package/src/tools/MemoryReadTool/MemoryReadTool.tsx +0 -127
  199. package/src/tools/MemoryReadTool/prompt.ts +0 -3
  200. package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +0 -89
  201. package/src/tools/MemoryWriteTool/prompt.ts +0 -3
  202. package/src/tools/MultiEditTool/MultiEditTool.tsx +0 -388
  203. package/src/tools/MultiEditTool/prompt.ts +0 -45
  204. package/src/tools/NotebookEditTool/NotebookEditTool.tsx +0 -298
  205. package/src/tools/NotebookEditTool/prompt.ts +0 -3
  206. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +0 -258
  207. package/src/tools/NotebookReadTool/prompt.ts +0 -3
  208. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +0 -107
  209. package/src/tools/StickerRequestTool/prompt.ts +0 -19
  210. package/src/tools/TaskTool/TaskTool.tsx +0 -438
  211. package/src/tools/TaskTool/constants.ts +0 -1
  212. package/src/tools/TaskTool/prompt.ts +0 -92
  213. package/src/tools/ThinkTool/ThinkTool.tsx +0 -54
  214. package/src/tools/ThinkTool/prompt.ts +0 -12
  215. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +0 -313
  216. package/src/tools/TodoWriteTool/prompt.ts +0 -63
  217. package/src/tools/URLFetcherTool/URLFetcherTool.tsx +0 -178
  218. package/src/tools/URLFetcherTool/cache.ts +0 -55
  219. package/src/tools/URLFetcherTool/htmlToMarkdown.ts +0 -55
  220. package/src/tools/URLFetcherTool/prompt.ts +0 -17
  221. package/src/tools/WebSearchTool/WebSearchTool.tsx +0 -103
  222. package/src/tools/WebSearchTool/prompt.ts +0 -13
  223. package/src/tools/WebSearchTool/searchProviders.ts +0 -66
  224. package/src/tools/lsTool/lsTool.tsx +0 -272
  225. package/src/tools/lsTool/prompt.ts +0 -2
  226. package/src/tools.ts +0 -67
  227. package/src/types/PermissionMode.ts +0 -120
  228. package/src/types/RequestContext.ts +0 -72
  229. package/src/types/common.d.ts +0 -2
  230. package/src/types/conversation.ts +0 -51
  231. package/src/types/logs.ts +0 -58
  232. package/src/types/modelCapabilities.ts +0 -64
  233. package/src/types/notebook.ts +0 -87
  234. package/src/utils/Cursor.ts +0 -436
  235. package/src/utils/PersistentShell.ts +0 -552
  236. package/src/utils/advancedFuzzyMatcher.ts +0 -290
  237. package/src/utils/agentLoader.ts +0 -278
  238. package/src/utils/agentStorage.ts +0 -97
  239. package/src/utils/array.ts +0 -3
  240. package/src/utils/ask.tsx +0 -99
  241. package/src/utils/auth.ts +0 -13
  242. package/src/utils/autoCompactCore.ts +0 -223
  243. package/src/utils/autoUpdater.ts +0 -458
  244. package/src/utils/betas.ts +0 -20
  245. package/src/utils/browser.ts +0 -14
  246. package/src/utils/cleanup.ts +0 -72
  247. package/src/utils/commands.ts +0 -261
  248. package/src/utils/commonUnixCommands.ts +0 -161
  249. package/src/utils/config.ts +0 -945
  250. package/src/utils/conversationRecovery.ts +0 -55
  251. package/src/utils/debugLogger.ts +0 -1235
  252. package/src/utils/diff.ts +0 -42
  253. package/src/utils/env.ts +0 -57
  254. package/src/utils/errors.ts +0 -21
  255. package/src/utils/exampleCommands.ts +0 -109
  256. package/src/utils/execFileNoThrow.ts +0 -51
  257. package/src/utils/expertChatStorage.ts +0 -136
  258. package/src/utils/file.ts +0 -405
  259. package/src/utils/fileRecoveryCore.ts +0 -71
  260. package/src/utils/format.tsx +0 -44
  261. package/src/utils/fuzzyMatcher.ts +0 -328
  262. package/src/utils/generators.ts +0 -62
  263. package/src/utils/git.ts +0 -92
  264. package/src/utils/globalLogger.ts +0 -77
  265. package/src/utils/http.ts +0 -10
  266. package/src/utils/imagePaste.ts +0 -38
  267. package/src/utils/json.ts +0 -13
  268. package/src/utils/log.ts +0 -382
  269. package/src/utils/markdown.ts +0 -213
  270. package/src/utils/messageContextManager.ts +0 -294
  271. package/src/utils/messages.tsx +0 -945
  272. package/src/utils/model.ts +0 -914
  273. package/src/utils/permissions/filesystem.ts +0 -127
  274. package/src/utils/responseState.ts +0 -23
  275. package/src/utils/ripgrep.ts +0 -167
  276. package/src/utils/secureFile.ts +0 -564
  277. package/src/utils/sessionState.ts +0 -49
  278. package/src/utils/state.ts +0 -25
  279. package/src/utils/style.ts +0 -29
  280. package/src/utils/terminal.ts +0 -50
  281. package/src/utils/theme.ts +0 -127
  282. package/src/utils/thinking.ts +0 -144
  283. package/src/utils/todoStorage.ts +0 -431
  284. package/src/utils/tokens.ts +0 -43
  285. package/src/utils/toolExecutionController.ts +0 -163
  286. package/src/utils/unaryLogging.ts +0 -26
  287. package/src/utils/user.ts +0 -37
  288. package/src/utils/validate.ts +0 -165
package/src/utils/file.ts DELETED
@@ -1,405 +0,0 @@
1
- import {
2
- readFileSync,
3
- writeFileSync,
4
- openSync,
5
- readSync,
6
- closeSync,
7
- existsSync,
8
- readdirSync,
9
- } from 'fs'
10
- import { logError } from './log'
11
- import {
12
- isAbsolute,
13
- normalize,
14
- resolve,
15
- resolve as resolvePath,
16
- relative,
17
- sep,
18
- basename,
19
- dirname,
20
- extname,
21
- join,
22
- } from 'path'
23
- import { glob as globLib } from 'glob'
24
- import { cwd } from 'process'
25
- import { listAllContentFiles } from './ripgrep'
26
- import { LRUCache } from 'lru-cache'
27
- import { getCwd } from './state'
28
-
29
- export type File = {
30
- filename: string
31
- content: string
32
- }
33
-
34
- export type LineEndingType = 'CRLF' | 'LF'
35
-
36
- export async function glob(
37
- filePattern: string,
38
- cwd: string,
39
- { limit, offset }: { limit: number; offset: number },
40
- abortSignal: AbortSignal,
41
- ): Promise<{ files: string[]; truncated: boolean }> {
42
- // TODO: Use worker threads
43
- const paths = await globLib([filePattern], {
44
- cwd,
45
- nocase: true,
46
- nodir: true,
47
- signal: abortSignal,
48
- stat: true,
49
- withFileTypes: true,
50
- })
51
- const sortedPaths = paths.sort((a, b) => (a.mtimeMs ?? 0) - (b.mtimeMs ?? 0))
52
- const truncated = sortedPaths.length > offset + limit
53
- return {
54
- files: sortedPaths
55
- .slice(offset, offset + limit)
56
- .map(path => path.fullpath()),
57
- truncated,
58
- }
59
- }
60
-
61
- export function readFileSafe(filepath: string): string | null {
62
- try {
63
- return readFileSync(filepath, 'utf-8')
64
- } catch (error) {
65
- logError(error)
66
- return null
67
- }
68
- }
69
-
70
- export function isInDirectory(
71
- relativePath: string,
72
- relativeCwd: string,
73
- ): boolean {
74
- if (relativePath === '.') {
75
- return true
76
- }
77
-
78
- // Reject paths starting with ~ (home directory)
79
- if (relativePath.startsWith('~')) {
80
- return false
81
- }
82
-
83
- // Reject paths containing null bytes or other sneaky characters
84
- if (relativePath.includes('\0') || relativeCwd.includes('\0')) {
85
- return false
86
- }
87
-
88
- // Normalize paths to resolve any '..' or '.' segments
89
- // and add trailing slashes
90
- let normalizedPath = normalize(relativePath)
91
- let normalizedCwd = normalize(relativeCwd)
92
-
93
- normalizedPath = normalizedPath.endsWith(sep)
94
- ? normalizedPath
95
- : normalizedPath + sep
96
- normalizedCwd = normalizedCwd.endsWith(sep)
97
- ? normalizedCwd
98
- : normalizedCwd + sep
99
-
100
- // Join with a base directory to make them absolute-like for comparison
101
- const fullPath = resolvePath(cwd(), normalizedCwd, normalizedPath)
102
- const fullCwd = resolvePath(cwd(), normalizedCwd)
103
-
104
- // Robust subpath check using path.relative (case-insensitive on Windows)
105
- const rel = relative(fullCwd, fullPath)
106
- if (!rel || rel === '') return true
107
- if (rel.startsWith('..')) return false
108
- if (isAbsolute(rel)) return false
109
- return true
110
- }
111
-
112
- export function readTextContent(
113
- filePath: string,
114
- offset = 0,
115
- maxLines?: number,
116
- ): { content: string; lineCount: number; totalLines: number } {
117
- const enc = detectFileEncoding(filePath)
118
- const content = readFileSync(filePath, enc)
119
- const lines = content.split(/\r?\n/)
120
-
121
- // Truncate number of lines if needed
122
- const toReturn =
123
- maxLines !== undefined && lines.length - offset > maxLines
124
- ? lines.slice(offset, offset + maxLines)
125
- : lines.slice(offset)
126
-
127
- return {
128
- content: toReturn.join('\n'), // TODO: This probably won't work for Windows
129
- lineCount: toReturn.length,
130
- totalLines: lines.length,
131
- }
132
- }
133
-
134
- export function writeTextContent(
135
- filePath: string,
136
- content: string,
137
- encoding: BufferEncoding,
138
- endings: LineEndingType,
139
- ): void {
140
- let toWrite = content
141
- if (endings === 'CRLF') {
142
- toWrite = content.split('\n').join('\r\n')
143
- }
144
-
145
- writeFileSync(filePath, toWrite, { encoding, flush: true })
146
- }
147
-
148
- const repoEndingCache = new LRUCache<string, LineEndingType>({
149
- fetchMethod: path => detectRepoLineEndingsDirect(path),
150
- ttl: 5 * 60 * 1000,
151
- ttlAutopurge: false,
152
- max: 1000,
153
- })
154
-
155
- export async function detectRepoLineEndings(
156
- filePath: string,
157
- ): Promise<LineEndingType | undefined> {
158
- return repoEndingCache.fetch(resolve(filePath))
159
- }
160
-
161
- export async function detectRepoLineEndingsDirect(
162
- cwd: string,
163
- ): Promise<LineEndingType> {
164
- const abortController = new AbortController()
165
- setTimeout(() => {
166
- abortController.abort()
167
- }, 1_000)
168
- const allFiles = await listAllContentFiles(cwd, abortController.signal, 15)
169
-
170
- let crlfCount = 0
171
- for (const file of allFiles) {
172
- const lineEnding = detectLineEndings(file)
173
- if (lineEnding === 'CRLF') {
174
- crlfCount++
175
- }
176
- }
177
-
178
- return crlfCount > 3 ? 'CRLF' : 'LF'
179
- }
180
-
181
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
182
- function fetch<K extends {}, V extends {}>(
183
- cache: LRUCache<K, V>,
184
- key: K,
185
- value: () => V,
186
- ): V {
187
- if (cache.has(key)) {
188
- return cache.get(key)!
189
- }
190
-
191
- const v = value()
192
- cache.set(key, v)
193
- return v
194
- }
195
-
196
- const fileEncodingCache = new LRUCache<string, BufferEncoding>({
197
- fetchMethod: path => detectFileEncodingDirect(path),
198
- ttl: 5 * 60 * 1000,
199
- ttlAutopurge: false,
200
- max: 1000,
201
- })
202
-
203
- export function detectFileEncoding(filePath: string): BufferEncoding {
204
- const k = resolve(filePath)
205
- return fetch(fileEncodingCache, k, () => detectFileEncodingDirect(k))
206
- }
207
-
208
- export function detectFileEncodingDirect(filePath: string): BufferEncoding {
209
- const BUFFER_SIZE = 4096
210
- const buffer = Buffer.alloc(BUFFER_SIZE)
211
-
212
- let fd: number | undefined = undefined
213
- try {
214
- fd = openSync(filePath, 'r')
215
- const bytesRead = readSync(fd, buffer, 0, BUFFER_SIZE, 0)
216
-
217
- if (bytesRead >= 2) {
218
- if (buffer[0] === 0xff && buffer[1] === 0xfe) return 'utf16le'
219
- }
220
-
221
- if (
222
- bytesRead >= 3 &&
223
- buffer[0] === 0xef &&
224
- buffer[1] === 0xbb &&
225
- buffer[2] === 0xbf
226
- ) {
227
- return 'utf8'
228
- }
229
-
230
- const isUtf8 = buffer.slice(0, bytesRead).toString('utf8').length > 0
231
- return isUtf8 ? 'utf8' : 'ascii'
232
- } catch (error) {
233
- logError(`Error detecting encoding for file ${filePath}: ${error}`)
234
- return 'utf8'
235
- } finally {
236
- if (fd) closeSync(fd)
237
- }
238
- }
239
-
240
- const lineEndingCache = new LRUCache<string, LineEndingType>({
241
- fetchMethod: path => detectLineEndingsDirect(path),
242
- ttl: 5 * 60 * 1000,
243
- ttlAutopurge: false,
244
- max: 1000,
245
- })
246
-
247
- export function detectLineEndings(filePath: string): LineEndingType {
248
- const k = resolve(filePath)
249
- return fetch(lineEndingCache, k, () => detectLineEndingsDirect(k))
250
- }
251
-
252
- export function detectLineEndingsDirect(
253
- filePath: string,
254
- encoding: BufferEncoding = 'utf8',
255
- ): LineEndingType {
256
- try {
257
- const buffer = Buffer.alloc(4096)
258
- const fd = openSync(filePath, 'r')
259
- const bytesRead = readSync(fd, buffer, 0, 4096, 0)
260
- closeSync(fd)
261
-
262
- const content = buffer.toString(encoding, 0, bytesRead)
263
- let crlfCount = 0
264
- let lfCount = 0
265
-
266
- for (let i = 0; i < content.length; i++) {
267
- if (content[i] === '\n') {
268
- if (i > 0 && content[i - 1] === '\r') {
269
- crlfCount++
270
- } else {
271
- lfCount++
272
- }
273
- }
274
- }
275
-
276
- return crlfCount > lfCount ? 'CRLF' : 'LF'
277
- } catch (error) {
278
- logError(`Error detecting line endings for file ${filePath}: ${error}`)
279
- return 'LF'
280
- }
281
- }
282
-
283
- export function normalizeFilePath(filePath: string): string {
284
- const absoluteFilePath = isAbsolute(filePath)
285
- ? filePath
286
- : resolve(getCwd(), filePath)
287
-
288
- // One weird trick for half-width space characters in MacOS screenshot filenames
289
- if (absoluteFilePath.endsWith(' AM.png')) {
290
- return absoluteFilePath.replace(
291
- ' AM.png',
292
- `${String.fromCharCode(8239)}AM.png`,
293
- )
294
- }
295
-
296
- // One weird trick for half-width space characters in MacOS screenshot filenames
297
- if (absoluteFilePath.endsWith(' PM.png')) {
298
- return absoluteFilePath.replace(
299
- ' PM.png',
300
- `${String.fromCharCode(8239)}PM.png`,
301
- )
302
- }
303
-
304
- return absoluteFilePath
305
- }
306
-
307
- export function getAbsolutePath(path: string | undefined): string | undefined {
308
- return path ? (isAbsolute(path) ? path : resolve(getCwd(), path)) : undefined
309
- }
310
-
311
- export function getAbsoluteAndRelativePaths(path: string | undefined): {
312
- absolutePath: string | undefined
313
- relativePath: string | undefined
314
- } {
315
- const absolutePath = getAbsolutePath(path)
316
- const relativePath = absolutePath
317
- ? relative(getCwd(), absolutePath)
318
- : undefined
319
- return { absolutePath, relativePath }
320
- }
321
-
322
- /**
323
- * Find files with the same name but different extensions in the same directory
324
- * @param filePath The path to the file that doesn't exist
325
- * @returns The found file with a different extension, or undefined if none found
326
- */
327
-
328
- export function findSimilarFile(filePath: string): string | undefined {
329
- try {
330
- const dir = dirname(filePath)
331
- const fileBaseName = basename(filePath, extname(filePath))
332
-
333
- // Check if directory exists
334
- if (!existsSync(dir)) {
335
- return undefined
336
- }
337
-
338
- // Get all files in the directory
339
- const files = readdirSync(dir)
340
-
341
- // Find files with the same base name but different extension
342
- const similarFiles = files.filter(
343
- file =>
344
- basename(file, extname(file)) === fileBaseName &&
345
- join(dir, file) !== filePath,
346
- )
347
-
348
- // Return just the filename of the first match if found
349
- const firstMatch = similarFiles[0]
350
- if (firstMatch) {
351
- return firstMatch
352
- }
353
- return undefined
354
- } catch (error) {
355
- // In case of any errors, return undefined
356
- logError(`Error finding similar file for ${filePath}: ${error}`)
357
- return undefined
358
- }
359
- }
360
-
361
- /**
362
- * Adds cat -n style line numbers to the content
363
- */
364
- export function addLineNumbers({
365
- content,
366
- // 1-indexed
367
- startLine,
368
- }: {
369
- content: string
370
- startLine: number
371
- }): string {
372
- if (!content) {
373
- return ''
374
- }
375
-
376
- return content
377
- .split(/\r?\n/)
378
- .map((line, index) => {
379
- const lineNum = index + startLine
380
- const numStr = String(lineNum)
381
- // Handle large numbers differently
382
- if (numStr.length >= 6) {
383
- return `${numStr}\t${line}`
384
- }
385
- // Regular numbers get padding to 6 characters
386
- const n = numStr.padStart(6, ' ')
387
- return `${n}\t${line}`
388
- })
389
- .join('\n') // TODO: This probably won't work for Windows
390
- }
391
-
392
- /**
393
- * Checks if a directory is empty by efficiently reading just the first entry
394
- * @param dirPath The path to the directory to check
395
- * @returns true if the directory is empty, false otherwise
396
- */
397
- export function isDirEmpty(dirPath: string): boolean {
398
- try {
399
- const entries = readdirSync(dirPath)
400
- return entries.length === 0
401
- } catch (error) {
402
- logError(`Error checking directory: ${error}`)
403
- return false
404
- }
405
- }
@@ -1,71 +0,0 @@
1
- import { readTextContent } from './file'
2
- import { fileFreshnessService } from '../services/fileFreshness'
3
-
4
- /**
5
- * File recovery configuration for auto-compact feature
6
- * These limits ensure recovered files don't overwhelm the compressed context
7
- */
8
- const MAX_FILES_TO_RECOVER = 5
9
- const MAX_TOKENS_PER_FILE = 10_000
10
- const MAX_TOTAL_FILE_TOKENS = 50_000
11
-
12
- /**
13
- * Selects and reads recently accessed files for context recovery
14
- *
15
- * During auto-compact, this function preserves development context by:
16
- * - Selecting files based on recent access patterns
17
- * - Enforcing token budgets to prevent context bloat
18
- * - Truncating large files while preserving essential content
19
- *
20
- * @returns Array of file data with content, token counts, and truncation flags
21
- */
22
- export async function selectAndReadFiles(): Promise<
23
- Array<{
24
- path: string
25
- content: string
26
- tokens: number
27
- truncated: boolean
28
- }>
29
- > {
30
- const importantFiles =
31
- fileFreshnessService.getImportantFiles(MAX_FILES_TO_RECOVER)
32
- const results = []
33
- let totalTokens = 0
34
-
35
- for (const fileInfo of importantFiles) {
36
- try {
37
- const { content } = readTextContent(fileInfo.path)
38
- const estimatedTokens = Math.ceil(content.length * 0.25)
39
-
40
- // Apply per-file token limit to prevent any single file from dominating context
41
- let finalContent = content
42
- let truncated = false
43
-
44
- if (estimatedTokens > MAX_TOKENS_PER_FILE) {
45
- const maxChars = Math.floor(MAX_TOKENS_PER_FILE / 0.25)
46
- finalContent = content.substring(0, maxChars)
47
- truncated = true
48
- }
49
-
50
- const finalTokens = Math.min(estimatedTokens, MAX_TOKENS_PER_FILE)
51
-
52
- // Enforce total token budget to maintain auto-compact effectiveness
53
- if (totalTokens + finalTokens > MAX_TOTAL_FILE_TOKENS) {
54
- break
55
- }
56
-
57
- totalTokens += finalTokens
58
- results.push({
59
- path: fileInfo.path,
60
- content: finalContent,
61
- tokens: finalTokens,
62
- truncated,
63
- })
64
- } catch (error) {
65
- // Skip files that cannot be read, don't let one failure stop the process
66
- console.error(`Failed to read file for recovery: ${fileInfo.path}`, error)
67
- }
68
- }
69
-
70
- return results
71
- }
@@ -1,44 +0,0 @@
1
- export function wrapText(text: string, width: number): string[] {
2
- const lines: string[] = []
3
- let currentLine = ''
4
-
5
- for (const char of text) {
6
- // Important: we need the spread to properly count multi-plane UTF-8 characters (eg. 𑚖)
7
- if ([...currentLine].length < width) {
8
- currentLine += char
9
- } else {
10
- lines.push(currentLine)
11
- currentLine = char
12
- }
13
- }
14
-
15
- if (currentLine) lines.push(currentLine)
16
- return lines
17
- }
18
-
19
- export function formatDuration(ms: number): string {
20
- if (ms < 60000) {
21
- return `${(ms / 1000).toFixed(1)}s`
22
- }
23
-
24
- const hours = Math.floor(ms / 3600000)
25
- const minutes = Math.floor((ms % 3600000) / 60000)
26
- const seconds = ((ms % 60000) / 1000).toFixed(1)
27
-
28
- if (hours > 0) {
29
- return `${hours}h ${minutes}m ${seconds}s`
30
- }
31
- if (minutes > 0) {
32
- return `${minutes}m ${seconds}s`
33
- }
34
- return `${seconds}s`
35
- }
36
-
37
- export function formatNumber(number: number): string {
38
- return new Intl.NumberFormat('en', {
39
- notation: 'compact',
40
- maximumFractionDigits: 1,
41
- })
42
- .format(number) // eg. "1321" => "1.3K"
43
- .toLowerCase() // eg. "1.3K" => "1.3k"
44
- }