@shareai-lab/kode 1.0.69 → 1.0.71

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 (253) hide show
  1. package/README.md +205 -72
  2. package/README.zh-CN.md +246 -0
  3. package/cli.js +62 -0
  4. package/package.json +45 -25
  5. package/scripts/postinstall.js +56 -0
  6. package/src/ProjectOnboarding.tsx +180 -0
  7. package/src/Tool.ts +53 -0
  8. package/src/commands/approvedTools.ts +53 -0
  9. package/src/commands/bug.tsx +20 -0
  10. package/src/commands/clear.ts +43 -0
  11. package/src/commands/compact.ts +120 -0
  12. package/src/commands/config.tsx +19 -0
  13. package/src/commands/cost.ts +18 -0
  14. package/src/commands/ctx_viz.ts +209 -0
  15. package/src/commands/doctor.ts +24 -0
  16. package/src/commands/help.tsx +19 -0
  17. package/src/commands/init.ts +37 -0
  18. package/src/commands/listen.ts +42 -0
  19. package/src/commands/login.tsx +51 -0
  20. package/src/commands/logout.tsx +40 -0
  21. package/src/commands/mcp.ts +41 -0
  22. package/src/commands/model.tsx +40 -0
  23. package/src/commands/modelstatus.tsx +20 -0
  24. package/src/commands/onboarding.tsx +34 -0
  25. package/src/commands/pr_comments.ts +59 -0
  26. package/src/commands/refreshCommands.ts +54 -0
  27. package/src/commands/release-notes.ts +34 -0
  28. package/src/commands/resume.tsx +30 -0
  29. package/src/commands/review.ts +49 -0
  30. package/src/commands/terminalSetup.ts +221 -0
  31. package/src/commands.ts +136 -0
  32. package/src/components/ApproveApiKey.tsx +93 -0
  33. package/src/components/AsciiLogo.tsx +13 -0
  34. package/src/components/AutoUpdater.tsx +148 -0
  35. package/src/components/Bug.tsx +367 -0
  36. package/src/components/Config.tsx +289 -0
  37. package/src/components/ConsoleOAuthFlow.tsx +326 -0
  38. package/src/components/Cost.tsx +23 -0
  39. package/src/components/CostThresholdDialog.tsx +46 -0
  40. package/src/components/CustomSelect/option-map.ts +42 -0
  41. package/src/components/CustomSelect/select-option.tsx +52 -0
  42. package/src/components/CustomSelect/select.tsx +143 -0
  43. package/src/components/CustomSelect/use-select-state.ts +414 -0
  44. package/src/components/CustomSelect/use-select.ts +35 -0
  45. package/src/components/FallbackToolUseRejectedMessage.tsx +15 -0
  46. package/src/components/FileEditToolUpdatedMessage.tsx +66 -0
  47. package/src/components/Help.tsx +215 -0
  48. package/src/components/HighlightedCode.tsx +33 -0
  49. package/src/components/InvalidConfigDialog.tsx +113 -0
  50. package/src/components/Link.tsx +32 -0
  51. package/src/components/LogSelector.tsx +86 -0
  52. package/src/components/Logo.tsx +145 -0
  53. package/src/components/MCPServerApprovalDialog.tsx +100 -0
  54. package/src/components/MCPServerDialogCopy.tsx +25 -0
  55. package/src/components/MCPServerMultiselectDialog.tsx +109 -0
  56. package/src/components/Message.tsx +219 -0
  57. package/src/components/MessageResponse.tsx +15 -0
  58. package/src/components/MessageSelector.tsx +211 -0
  59. package/src/components/ModeIndicator.tsx +88 -0
  60. package/src/components/ModelConfig.tsx +301 -0
  61. package/src/components/ModelListManager.tsx +223 -0
  62. package/src/components/ModelSelector.tsx +3208 -0
  63. package/src/components/ModelStatusDisplay.tsx +228 -0
  64. package/src/components/Onboarding.tsx +274 -0
  65. package/src/components/PressEnterToContinue.tsx +11 -0
  66. package/src/components/PromptInput.tsx +710 -0
  67. package/src/components/SentryErrorBoundary.ts +33 -0
  68. package/src/components/Spinner.tsx +129 -0
  69. package/src/components/StructuredDiff.tsx +184 -0
  70. package/src/components/TextInput.tsx +246 -0
  71. package/src/components/TokenWarning.tsx +31 -0
  72. package/src/components/ToolUseLoader.tsx +40 -0
  73. package/src/components/TrustDialog.tsx +106 -0
  74. package/src/components/binary-feedback/BinaryFeedback.tsx +63 -0
  75. package/src/components/binary-feedback/BinaryFeedbackOption.tsx +111 -0
  76. package/src/components/binary-feedback/BinaryFeedbackView.tsx +172 -0
  77. package/src/components/binary-feedback/utils.ts +220 -0
  78. package/src/components/messages/AssistantBashOutputMessage.tsx +22 -0
  79. package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +45 -0
  80. package/src/components/messages/AssistantRedactedThinkingMessage.tsx +19 -0
  81. package/src/components/messages/AssistantTextMessage.tsx +144 -0
  82. package/src/components/messages/AssistantThinkingMessage.tsx +40 -0
  83. package/src/components/messages/AssistantToolUseMessage.tsx +123 -0
  84. package/src/components/messages/UserBashInputMessage.tsx +28 -0
  85. package/src/components/messages/UserCommandMessage.tsx +30 -0
  86. package/src/components/messages/UserKodingInputMessage.tsx +28 -0
  87. package/src/components/messages/UserPromptMessage.tsx +35 -0
  88. package/src/components/messages/UserTextMessage.tsx +39 -0
  89. package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +12 -0
  90. package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +36 -0
  91. package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +31 -0
  92. package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +57 -0
  93. package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +35 -0
  94. package/src/components/messages/UserToolResultMessage/utils.tsx +56 -0
  95. package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +121 -0
  96. package/src/components/permissions/FallbackPermissionRequest.tsx +155 -0
  97. package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +182 -0
  98. package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +75 -0
  99. package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +164 -0
  100. package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +81 -0
  101. package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +242 -0
  102. package/src/components/permissions/PermissionRequest.tsx +103 -0
  103. package/src/components/permissions/PermissionRequestTitle.tsx +69 -0
  104. package/src/components/permissions/hooks.ts +44 -0
  105. package/src/components/permissions/toolUseOptions.ts +59 -0
  106. package/src/components/permissions/utils.ts +23 -0
  107. package/src/constants/betas.ts +5 -0
  108. package/src/constants/claude-asterisk-ascii-art.tsx +238 -0
  109. package/src/constants/figures.ts +4 -0
  110. package/src/constants/keys.ts +3 -0
  111. package/src/constants/macros.ts +6 -0
  112. package/src/constants/models.ts +935 -0
  113. package/src/constants/oauth.ts +18 -0
  114. package/src/constants/product.ts +17 -0
  115. package/src/constants/prompts.ts +177 -0
  116. package/src/constants/releaseNotes.ts +7 -0
  117. package/src/context/PermissionContext.tsx +149 -0
  118. package/src/context.ts +278 -0
  119. package/src/cost-tracker.ts +84 -0
  120. package/src/entrypoints/cli.tsx +1498 -0
  121. package/src/entrypoints/mcp.ts +176 -0
  122. package/src/history.ts +25 -0
  123. package/src/hooks/useApiKeyVerification.ts +59 -0
  124. package/src/hooks/useArrowKeyHistory.ts +55 -0
  125. package/src/hooks/useCanUseTool.ts +138 -0
  126. package/src/hooks/useCancelRequest.ts +39 -0
  127. package/src/hooks/useDoublePress.ts +42 -0
  128. package/src/hooks/useExitOnCtrlCD.ts +31 -0
  129. package/src/hooks/useInterval.ts +25 -0
  130. package/src/hooks/useLogMessages.ts +16 -0
  131. package/src/hooks/useLogStartupTime.ts +12 -0
  132. package/src/hooks/useNotifyAfterTimeout.ts +65 -0
  133. package/src/hooks/usePermissionRequestLogging.ts +44 -0
  134. package/src/hooks/useSlashCommandTypeahead.ts +137 -0
  135. package/src/hooks/useTerminalSize.ts +49 -0
  136. package/src/hooks/useTextInput.ts +315 -0
  137. package/src/messages.ts +37 -0
  138. package/src/permissions.ts +268 -0
  139. package/src/query.ts +704 -0
  140. package/src/screens/ConfigureNpmPrefix.tsx +197 -0
  141. package/src/screens/Doctor.tsx +219 -0
  142. package/src/screens/LogList.tsx +68 -0
  143. package/src/screens/REPL.tsx +792 -0
  144. package/src/screens/ResumeConversation.tsx +68 -0
  145. package/src/services/browserMocks.ts +66 -0
  146. package/src/services/claude.ts +1947 -0
  147. package/src/services/customCommands.ts +683 -0
  148. package/src/services/fileFreshness.ts +377 -0
  149. package/src/services/mcpClient.ts +564 -0
  150. package/src/services/mcpServerApproval.tsx +50 -0
  151. package/src/services/notifier.ts +40 -0
  152. package/src/services/oauth.ts +357 -0
  153. package/src/services/openai.ts +796 -0
  154. package/src/services/sentry.ts +3 -0
  155. package/src/services/statsig.ts +171 -0
  156. package/src/services/statsigStorage.ts +86 -0
  157. package/src/services/systemReminder.ts +406 -0
  158. package/src/services/vcr.ts +161 -0
  159. package/src/tools/ArchitectTool/ArchitectTool.tsx +122 -0
  160. package/src/tools/ArchitectTool/prompt.ts +15 -0
  161. package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +505 -0
  162. package/src/tools/BashTool/BashTool.tsx +270 -0
  163. package/src/tools/BashTool/BashToolResultMessage.tsx +38 -0
  164. package/src/tools/BashTool/OutputLine.tsx +48 -0
  165. package/src/tools/BashTool/prompt.ts +174 -0
  166. package/src/tools/BashTool/utils.ts +56 -0
  167. package/src/tools/FileEditTool/FileEditTool.tsx +316 -0
  168. package/src/tools/FileEditTool/prompt.ts +51 -0
  169. package/src/tools/FileEditTool/utils.ts +58 -0
  170. package/src/tools/FileReadTool/FileReadTool.tsx +371 -0
  171. package/src/tools/FileReadTool/prompt.ts +7 -0
  172. package/src/tools/FileWriteTool/FileWriteTool.tsx +297 -0
  173. package/src/tools/FileWriteTool/prompt.ts +10 -0
  174. package/src/tools/GlobTool/GlobTool.tsx +119 -0
  175. package/src/tools/GlobTool/prompt.ts +8 -0
  176. package/src/tools/GrepTool/GrepTool.tsx +147 -0
  177. package/src/tools/GrepTool/prompt.ts +11 -0
  178. package/src/tools/MCPTool/MCPTool.tsx +106 -0
  179. package/src/tools/MCPTool/prompt.ts +3 -0
  180. package/src/tools/MemoryReadTool/MemoryReadTool.tsx +127 -0
  181. package/src/tools/MemoryReadTool/prompt.ts +3 -0
  182. package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +89 -0
  183. package/src/tools/MemoryWriteTool/prompt.ts +3 -0
  184. package/src/tools/MultiEditTool/MultiEditTool.tsx +366 -0
  185. package/src/tools/MultiEditTool/prompt.ts +45 -0
  186. package/src/tools/NotebookEditTool/NotebookEditTool.tsx +298 -0
  187. package/src/tools/NotebookEditTool/prompt.ts +3 -0
  188. package/src/tools/NotebookReadTool/NotebookReadTool.tsx +266 -0
  189. package/src/tools/NotebookReadTool/prompt.ts +3 -0
  190. package/src/tools/StickerRequestTool/StickerRequestTool.tsx +93 -0
  191. package/src/tools/StickerRequestTool/prompt.ts +19 -0
  192. package/src/tools/TaskTool/TaskTool.tsx +382 -0
  193. package/src/tools/TaskTool/constants.ts +1 -0
  194. package/src/tools/TaskTool/prompt.ts +56 -0
  195. package/src/tools/ThinkTool/ThinkTool.tsx +56 -0
  196. package/src/tools/ThinkTool/prompt.ts +12 -0
  197. package/src/tools/TodoWriteTool/TodoWriteTool.tsx +289 -0
  198. package/src/tools/TodoWriteTool/prompt.ts +63 -0
  199. package/src/tools/lsTool/lsTool.tsx +269 -0
  200. package/src/tools/lsTool/prompt.ts +2 -0
  201. package/src/tools.ts +63 -0
  202. package/src/types/PermissionMode.ts +120 -0
  203. package/src/types/RequestContext.ts +72 -0
  204. package/src/utils/Cursor.ts +436 -0
  205. package/src/utils/PersistentShell.ts +373 -0
  206. package/src/utils/agentStorage.ts +97 -0
  207. package/src/utils/array.ts +3 -0
  208. package/src/utils/ask.tsx +98 -0
  209. package/src/utils/auth.ts +13 -0
  210. package/src/utils/autoCompactCore.ts +223 -0
  211. package/src/utils/autoUpdater.ts +318 -0
  212. package/src/utils/betas.ts +20 -0
  213. package/src/utils/browser.ts +14 -0
  214. package/src/utils/cleanup.ts +72 -0
  215. package/src/utils/commands.ts +261 -0
  216. package/src/utils/config.ts +771 -0
  217. package/src/utils/conversationRecovery.ts +54 -0
  218. package/src/utils/debugLogger.ts +1123 -0
  219. package/src/utils/diff.ts +42 -0
  220. package/src/utils/env.ts +57 -0
  221. package/src/utils/errors.ts +21 -0
  222. package/src/utils/exampleCommands.ts +108 -0
  223. package/src/utils/execFileNoThrow.ts +51 -0
  224. package/src/utils/expertChatStorage.ts +136 -0
  225. package/src/utils/file.ts +402 -0
  226. package/src/utils/fileRecoveryCore.ts +71 -0
  227. package/src/utils/format.tsx +44 -0
  228. package/src/utils/generators.ts +62 -0
  229. package/src/utils/git.ts +92 -0
  230. package/src/utils/globalLogger.ts +77 -0
  231. package/src/utils/http.ts +10 -0
  232. package/src/utils/imagePaste.ts +38 -0
  233. package/src/utils/json.ts +13 -0
  234. package/src/utils/log.ts +382 -0
  235. package/src/utils/markdown.ts +213 -0
  236. package/src/utils/messageContextManager.ts +289 -0
  237. package/src/utils/messages.tsx +938 -0
  238. package/src/utils/model.ts +836 -0
  239. package/src/utils/permissions/filesystem.ts +118 -0
  240. package/src/utils/ripgrep.ts +167 -0
  241. package/src/utils/sessionState.ts +49 -0
  242. package/src/utils/state.ts +25 -0
  243. package/src/utils/style.ts +29 -0
  244. package/src/utils/terminal.ts +49 -0
  245. package/src/utils/theme.ts +122 -0
  246. package/src/utils/thinking.ts +144 -0
  247. package/src/utils/todoStorage.ts +431 -0
  248. package/src/utils/tokens.ts +43 -0
  249. package/src/utils/toolExecutionController.ts +163 -0
  250. package/src/utils/unaryLogging.ts +26 -0
  251. package/src/utils/user.ts +37 -0
  252. package/src/utils/validate.ts +165 -0
  253. package/cli.mjs +0 -1803
@@ -0,0 +1,213 @@
1
+ import { marked, Token } from 'marked'
2
+ import { stripSystemMessages } from './messages'
3
+ import chalk from 'chalk'
4
+ import { EOL } from 'os'
5
+ import { highlight, supportsLanguage } from 'cli-highlight'
6
+ import { logError } from './log'
7
+
8
+ export function applyMarkdown(content: string): string {
9
+ return marked
10
+ .lexer(stripSystemMessages(content))
11
+ .map(_ => format(_))
12
+ .join('')
13
+ .trim()
14
+ }
15
+
16
+ function format(
17
+ token: Token,
18
+ listDepth = 0,
19
+ orderedListNumber: number | null = null,
20
+ parent: Token | null = null,
21
+ ): string {
22
+ switch (token.type) {
23
+ case 'blockquote':
24
+ return chalk.dim.italic((token.tokens ?? []).map(_ => format(_)).join(''))
25
+ case 'code':
26
+ if (token.lang && supportsLanguage(token.lang)) {
27
+ return highlight(token.text, { language: token.lang }) + EOL
28
+ } else {
29
+ logError(
30
+ `Language not supported while highlighting code, falling back to markdown: ${token.lang}`,
31
+ )
32
+ return highlight(token.text, { language: 'markdown' }) + EOL
33
+ }
34
+ case 'codespan':
35
+ // inline code
36
+ return chalk.blue(token.text)
37
+ case 'em':
38
+ return chalk.italic((token.tokens ?? []).map(_ => format(_)).join(''))
39
+ case 'strong':
40
+ return chalk.bold((token.tokens ?? []).map(_ => format(_)).join(''))
41
+ case 'heading':
42
+ switch (token.depth) {
43
+ case 1: // h1
44
+ return (
45
+ chalk.bold.italic.underline(
46
+ (token.tokens ?? []).map(_ => format(_)).join(''),
47
+ ) +
48
+ EOL +
49
+ EOL
50
+ )
51
+ case 2: // h2
52
+ return (
53
+ chalk.bold((token.tokens ?? []).map(_ => format(_)).join('')) +
54
+ EOL +
55
+ EOL
56
+ )
57
+ default: // h3+
58
+ return (
59
+ chalk.bold.dim((token.tokens ?? []).map(_ => format(_)).join('')) +
60
+ EOL +
61
+ EOL
62
+ )
63
+ }
64
+ case 'hr':
65
+ return '---'
66
+ case 'image':
67
+ return `[Image: ${token.title}: ${token.href}]`
68
+ case 'link':
69
+ return chalk.blue(token.href)
70
+ case 'list': {
71
+ return token.items
72
+ .map((_: Token, index: number) =>
73
+ format(
74
+ _,
75
+ listDepth,
76
+ token.ordered ? token.start + index : null,
77
+ token,
78
+ ),
79
+ )
80
+ .join('')
81
+ }
82
+ case 'list_item':
83
+ return (token.tokens ?? [])
84
+ .map(
85
+ _ =>
86
+ `${' '.repeat(listDepth)}${format(_, listDepth + 1, orderedListNumber, token)}`,
87
+ )
88
+ .join('')
89
+ case 'paragraph':
90
+ return (token.tokens ?? []).map(_ => format(_)).join('') + EOL
91
+ case 'space':
92
+ return EOL
93
+ case 'text':
94
+ if (parent?.type === 'list_item') {
95
+ return `${orderedListNumber === null ? '-' : getListNumber(listDepth, orderedListNumber) + '.'} ${token.tokens ? token.tokens.map(_ => format(_, listDepth, orderedListNumber, token)).join('') : token.text}${EOL}`
96
+ } else {
97
+ return token.text
98
+ }
99
+ }
100
+ // TODO: tables
101
+ return ''
102
+ }
103
+
104
+ const DEPTH_1_LIST_NUMBERS = [
105
+ 'a',
106
+ 'b',
107
+ 'c',
108
+ 'd',
109
+ 'e',
110
+ 'f',
111
+ 'g',
112
+ 'h',
113
+ 'i',
114
+ 'j',
115
+ 'k',
116
+ 'l',
117
+ 'm',
118
+ 'n',
119
+ 'o',
120
+ 'p',
121
+ 'q',
122
+ 'r',
123
+ 's',
124
+ 't',
125
+ 'u',
126
+ 'v',
127
+ 'w',
128
+ 'x',
129
+ 'y',
130
+ 'z',
131
+ 'aa',
132
+ 'ab',
133
+ 'ac',
134
+ 'ad',
135
+ 'ae',
136
+ 'af',
137
+ 'ag',
138
+ 'ah',
139
+ 'ai',
140
+ 'aj',
141
+ 'ak',
142
+ 'al',
143
+ 'am',
144
+ 'an',
145
+ 'ao',
146
+ 'ap',
147
+ 'aq',
148
+ 'ar',
149
+ 'as',
150
+ 'at',
151
+ 'au',
152
+ 'av',
153
+ 'aw',
154
+ 'ax',
155
+ 'ay',
156
+ 'az',
157
+ ]
158
+ const DEPTH_2_LIST_NUMBERS = [
159
+ 'i',
160
+ 'ii',
161
+ 'iii',
162
+ 'iv',
163
+ 'v',
164
+ 'vi',
165
+ 'vii',
166
+ 'viii',
167
+ 'ix',
168
+ 'x',
169
+ 'xi',
170
+ 'xii',
171
+ 'xiii',
172
+ 'xiv',
173
+ 'xv',
174
+ 'xvi',
175
+ 'xvii',
176
+ 'xviii',
177
+ 'xix',
178
+ 'xx',
179
+ 'xxi',
180
+ 'xxii',
181
+ 'xxiii',
182
+ 'xxiv',
183
+ 'xxv',
184
+ 'xxvi',
185
+ 'xxvii',
186
+ 'xxviii',
187
+ 'xxix',
188
+ 'xxx',
189
+ 'xxxi',
190
+ 'xxxii',
191
+ 'xxxiii',
192
+ 'xxxiv',
193
+ 'xxxv',
194
+ 'xxxvi',
195
+ 'xxxvii',
196
+ 'xxxviii',
197
+ 'xxxix',
198
+ 'xl',
199
+ ]
200
+
201
+ function getListNumber(listDepth: number, orderedListNumber: number): string {
202
+ switch (listDepth) {
203
+ case 0:
204
+ case 1:
205
+ return orderedListNumber.toString()
206
+ case 2:
207
+ return DEPTH_1_LIST_NUMBERS[orderedListNumber - 1]! // TODO: don't hard code the list
208
+ case 3:
209
+ return DEPTH_2_LIST_NUMBERS[orderedListNumber - 1]! // TODO: don't hard code the list
210
+ default:
211
+ return orderedListNumber.toString()
212
+ }
213
+ }
@@ -0,0 +1,289 @@
1
+ import { Message } from '../query'
2
+ import { countTokens } from './tokens'
3
+
4
+ export interface MessageRetentionStrategy {
5
+ type:
6
+ | 'preserve_recent'
7
+ | 'preserve_important'
8
+ | 'smart_compression'
9
+ | 'auto_compact'
10
+ maxTokens: number
11
+ preserveCount?: number
12
+ importanceThreshold?: number
13
+ }
14
+
15
+ export interface MessageTruncationResult {
16
+ truncatedMessages: Message[]
17
+ removedCount: number
18
+ preservedTokens: number
19
+ strategy: string
20
+ summary?: string
21
+ }
22
+
23
+ /**
24
+ * Smart message truncation for context-limited models
25
+ * Implements multiple strategies for preserving important conversation content
26
+ */
27
+ export class MessageContextManager {
28
+ /**
29
+ * Truncate messages intelligently based on strategy and token limit
30
+ */
31
+ async truncateMessages(
32
+ messages: Message[],
33
+ strategy: MessageRetentionStrategy,
34
+ ): Promise<MessageTruncationResult> {
35
+ switch (strategy.type) {
36
+ case 'preserve_recent':
37
+ return this.preserveRecentMessages(messages, strategy)
38
+ case 'preserve_important':
39
+ return this.preserveImportantMessages(messages, strategy)
40
+ case 'smart_compression':
41
+ return this.smartCompressionStrategy(messages, strategy)
42
+ case 'auto_compact':
43
+ return this.autoCompactStrategy(messages, strategy)
44
+ default:
45
+ return this.preserveRecentMessages(messages, strategy)
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Strategy 1: Preserve most recent messages
51
+ */
52
+ private preserveRecentMessages(
53
+ messages: Message[],
54
+ strategy: MessageRetentionStrategy,
55
+ ): MessageTruncationResult {
56
+ const preserveCount =
57
+ strategy.preserveCount || this.estimateMessageCount(strategy.maxTokens)
58
+ const truncatedMessages = messages.slice(-preserveCount)
59
+ const removedCount = messages.length - truncatedMessages.length
60
+
61
+ return {
62
+ truncatedMessages,
63
+ removedCount,
64
+ preservedTokens: countTokens(truncatedMessages),
65
+ strategy: `Preserved last ${preserveCount} messages`,
66
+ summary:
67
+ removedCount > 0
68
+ ? `Removed ${removedCount} older messages to fit context window`
69
+ : 'No messages removed',
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Strategy 2: Preserve important messages (errors, user queries, recent context)
75
+ */
76
+ private preserveImportantMessages(
77
+ messages: Message[],
78
+ strategy: MessageRetentionStrategy,
79
+ ): MessageTruncationResult {
80
+ const importantMessages: Message[] = []
81
+ const recentMessages: Message[] = []
82
+
83
+ // Always preserve the last few messages for context continuity
84
+ const recentCount = Math.min(5, messages.length)
85
+ recentMessages.push(...messages.slice(-recentCount))
86
+
87
+ // Identify important messages (errors, tool failures, user decisions)
88
+ for (let i = 0; i < messages.length - recentCount; i++) {
89
+ const message = messages[i]
90
+ if (this.isImportantMessage(message)) {
91
+ importantMessages.push(message)
92
+ }
93
+ }
94
+
95
+ // Combine and deduplicate
96
+ const combinedMessages = [
97
+ ...importantMessages,
98
+ ...recentMessages.filter(
99
+ msg => !importantMessages.some(imp => this.messagesEqual(imp, msg)),
100
+ ),
101
+ ]
102
+
103
+ // Sort by original order
104
+ const truncatedMessages = combinedMessages.sort((a, b) => {
105
+ const aIndex = messages.indexOf(a)
106
+ const bIndex = messages.indexOf(b)
107
+ return aIndex - bIndex
108
+ })
109
+
110
+ const removedCount = messages.length - truncatedMessages.length
111
+
112
+ return {
113
+ truncatedMessages,
114
+ removedCount,
115
+ preservedTokens: countTokens(truncatedMessages),
116
+ strategy: `Preserved ${importantMessages.length} important + ${recentMessages.length} recent messages`,
117
+ summary: `Kept critical errors, user decisions, and recent context (${removedCount} messages archived)`,
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Strategy 3: Smart compression with summary
123
+ */
124
+ private async smartCompressionStrategy(
125
+ messages: Message[],
126
+ strategy: MessageRetentionStrategy,
127
+ ): Promise<MessageTruncationResult> {
128
+ const recentCount = Math.min(10, Math.floor(messages.length * 0.3))
129
+ const recentMessages = messages.slice(-recentCount)
130
+ const olderMessages = messages.slice(0, -recentCount)
131
+
132
+ // Create a summary of older messages
133
+ const summary = this.createMessagesSummary(olderMessages)
134
+
135
+ // Create a summary message
136
+ const summaryMessage: Message = {
137
+ type: 'assistant',
138
+ message: {
139
+ role: 'assistant',
140
+ content: [
141
+ {
142
+ type: 'text',
143
+ text: `[CONVERSATION SUMMARY - ${olderMessages.length} messages compressed]\n\n${summary}\n\n[END SUMMARY - Recent context follows...]`,
144
+ },
145
+ ],
146
+ },
147
+ }
148
+
149
+ const truncatedMessages = [summaryMessage, ...recentMessages]
150
+
151
+ return {
152
+ truncatedMessages,
153
+ removedCount: olderMessages.length,
154
+ preservedTokens: countTokens(truncatedMessages),
155
+ strategy: `Compressed ${olderMessages.length} messages + preserved ${recentCount} recent`,
156
+ summary: `Created intelligent summary of conversation history`,
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Strategy 4: Use existing auto-compact mechanism
162
+ */
163
+ private async autoCompactStrategy(
164
+ messages: Message[],
165
+ strategy: MessageRetentionStrategy,
166
+ ): Promise<MessageTruncationResult> {
167
+ // This would integrate with the existing autoCompactCore.ts
168
+ // For now, fallback to preserve_recent
169
+ return this.preserveRecentMessages(messages, strategy)
170
+ }
171
+
172
+ /**
173
+ * Helper: Estimate how many messages fit in token budget
174
+ */
175
+ private estimateMessageCount(maxTokens: number): number {
176
+ const avgTokensPerMessage = 150 // Conservative estimate
177
+ return Math.max(3, Math.floor(maxTokens / avgTokensPerMessage))
178
+ }
179
+
180
+ /**
181
+ * Helper: Determine if a message is important
182
+ */
183
+ private isImportantMessage(message: Message): boolean {
184
+ if (message.type === 'user') return true // User messages are always important
185
+
186
+ if (message.type === 'assistant') {
187
+ const content = message.message.content
188
+ if (Array.isArray(content)) {
189
+ const textContent = content
190
+ .filter(c => c.type === 'text')
191
+ .map(c => c.text)
192
+ .join(' ')
193
+ .toLowerCase()
194
+
195
+ // Mark as important if contains error keywords
196
+ return (
197
+ textContent.includes('error') ||
198
+ textContent.includes('failed') ||
199
+ textContent.includes('warning') ||
200
+ textContent.includes('critical') ||
201
+ textContent.includes('issue')
202
+ )
203
+ }
204
+ }
205
+
206
+ return false
207
+ }
208
+
209
+ /**
210
+ * Helper: Check if two messages are equal
211
+ */
212
+ private messagesEqual(a: Message, b: Message): boolean {
213
+ return JSON.stringify(a) === JSON.stringify(b)
214
+ }
215
+
216
+ /**
217
+ * Helper: Create summary of message sequence
218
+ */
219
+ private createMessagesSummary(messages: Message[]): string {
220
+ const userMessages = messages.filter(m => m.type === 'user').length
221
+ const assistantMessages = messages.filter(
222
+ m => m.type === 'assistant',
223
+ ).length
224
+ const toolUses = messages.filter(
225
+ m =>
226
+ m.type === 'assistant' &&
227
+ Array.isArray(m.message.content) &&
228
+ m.message.content.some(c => c.type === 'tool_use'),
229
+ ).length
230
+
231
+ const topics: string[] = []
232
+
233
+ // Extract key topics from user messages
234
+ messages.forEach(msg => {
235
+ if (msg.type === 'user' && Array.isArray(msg.message.content)) {
236
+ const text = msg.message.content
237
+ .filter(c => c.type === 'text')
238
+ .map(c => c.text)
239
+ .join(' ')
240
+
241
+ // Simple keyword extraction (could be enhanced with NLP)
242
+ if (text.includes('error') || text.includes('bug'))
243
+ topics.push('debugging')
244
+ if (text.includes('implement') || text.includes('create'))
245
+ topics.push('implementation')
246
+ if (text.includes('explain') || text.includes('understand'))
247
+ topics.push('explanation')
248
+ if (text.includes('fix') || text.includes('solve'))
249
+ topics.push('problem-solving')
250
+ }
251
+ })
252
+
253
+ const uniqueTopics = [...new Set(topics)]
254
+
255
+ return `Previous conversation included ${userMessages} user messages and ${assistantMessages} assistant responses, with ${toolUses} tool invocations. Key topics: ${uniqueTopics.join(', ') || 'general discussion'}.`
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Factory function to create appropriate retention strategy
261
+ */
262
+ export function createRetentionStrategy(
263
+ targetContextLength: number,
264
+ currentTokens: number,
265
+ userPreference: 'aggressive' | 'balanced' | 'conservative' = 'balanced',
266
+ ): MessageRetentionStrategy {
267
+ const maxTokens = Math.floor(targetContextLength * 0.7) // Leave room for new conversation
268
+
269
+ switch (userPreference) {
270
+ case 'aggressive':
271
+ return {
272
+ type: 'preserve_recent',
273
+ maxTokens,
274
+ preserveCount: Math.max(3, Math.floor(maxTokens / 200)),
275
+ }
276
+ case 'conservative':
277
+ return {
278
+ type: 'smart_compression',
279
+ maxTokens,
280
+ }
281
+ case 'balanced':
282
+ default:
283
+ return {
284
+ type: 'preserve_important',
285
+ maxTokens,
286
+ preserveCount: Math.max(5, Math.floor(maxTokens / 150)),
287
+ }
288
+ }
289
+ }