@shareai-lab/kode 1.1.14 → 1.1.16-dev.2

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
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
- }