@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
@@ -1,760 +0,0 @@
1
- import { Box, Text, useInput } from 'ink'
2
- import { sample } from 'lodash-es'
3
- import { getExampleCommands } from '../utils/exampleCommands'
4
- import * as React from 'react'
5
- import { type Message } from '../query'
6
- import { processUserInput } from '../utils/messages'
7
- import { useArrowKeyHistory } from '../hooks/useArrowKeyHistory'
8
- import { useUnifiedCompletion } from '../hooks/useUnifiedCompletion'
9
- import { addToHistory } from '../history'
10
- import TextInput from './TextInput'
11
- import { memo, useCallback, useEffect, useMemo, useState } from 'react'
12
- import { countTokens } from '../utils/tokens'
13
- import { SentryErrorBoundary } from './SentryErrorBoundary'
14
- import { AutoUpdater } from './AutoUpdater'
15
- import type { AutoUpdaterResult } from '../utils/autoUpdater'
16
- import type { Command } from '../commands'
17
- import type { SetToolJSXFn, Tool } from '../Tool'
18
- import { TokenWarning, WARNING_THRESHOLD } from './TokenWarning'
19
- import { useTerminalSize } from '../hooks/useTerminalSize'
20
- import { getTheme } from '../utils/theme'
21
- import { getModelManager, reloadModelManager } from '../utils/model'
22
- import { saveGlobalConfig } from '../utils/config'
23
- import { setTerminalTitle } from '../utils/terminal'
24
- import terminalSetup, {
25
- isShiftEnterKeyBindingInstalled,
26
- handleHashCommand,
27
- } from '../commands/terminalSetup'
28
- import { usePermissionContext } from '../context/PermissionContext'
29
-
30
- // Async function to interpret the '#' command input using AI
31
- async function interpretHashCommand(input: string): Promise<string> {
32
- // Use the AI to interpret the input
33
- try {
34
- const { queryQuick } = await import('../services/claude')
35
-
36
- // Create a prompt for the model to interpret the hash command
37
- const systemPrompt = [
38
- "You're helping the user structure notes that will be added to their KODING.md file.",
39
- "Format the user's input into a well-structured note that will be useful for later reference.",
40
- 'Add appropriate markdown formatting, headings, bullet points, or other structural elements as needed.',
41
- 'The goal is to transform the raw note into something that will be more useful when reviewed later.',
42
- 'You should keep the original meaning but make the structure clear.',
43
- ]
44
-
45
- // Send the request to the AI
46
- const result = await queryQuick({
47
- systemPrompt,
48
- userPrompt: `Transform this note for KODING.md: ${input}`,
49
- })
50
-
51
- // Extract the content from the response
52
- if (typeof result.message.content === 'string') {
53
- return result.message.content
54
- } else if (Array.isArray(result.message.content)) {
55
- return result.message.content
56
- .filter(block => block.type === 'text')
57
- .map(block => (block.type === 'text' ? block.text : ''))
58
- .join('\n')
59
- }
60
-
61
- return `# ${input}\n\n_Added on ${new Date().toLocaleString()}_`
62
- } catch (e) {
63
- // If interpretation fails, return the input with minimal formatting
64
- return `# ${input}\n\n_Added on ${new Date().toLocaleString()}_`
65
- }
66
- }
67
-
68
- type Props = {
69
- commands: Command[]
70
- forkNumber: number
71
- messageLogName: string
72
- isDisabled: boolean
73
- isLoading: boolean
74
- onQuery: (
75
- newMessages: Message[],
76
- abortController?: AbortController,
77
- ) => Promise<void>
78
- debug: boolean
79
- verbose: boolean
80
- messages: Message[]
81
- setToolJSX: SetToolJSXFn
82
- onAutoUpdaterResult: (result: AutoUpdaterResult) => void
83
- autoUpdaterResult: AutoUpdaterResult | null
84
- tools: Tool[]
85
- input: string
86
- onInputChange: (value: string) => void
87
- mode: 'bash' | 'prompt' | 'koding'
88
- onModeChange: (mode: 'bash' | 'prompt' | 'koding') => void
89
- submitCount: number
90
- onSubmitCountChange: (updater: (prev: number) => number) => void
91
- setIsLoading: (isLoading: boolean) => void
92
- setAbortController: (abortController: AbortController | null) => void
93
- onShowMessageSelector: () => void
94
- setForkConvoWithMessagesOnTheNextRender: (
95
- forkConvoWithMessages: Message[],
96
- ) => void
97
- readFileTimestamps: { [filename: string]: number }
98
- abortController: AbortController | null
99
- onModelChange?: () => void
100
- }
101
-
102
- function getPastedTextPrompt(text: string): string {
103
- const newlineCount = (text.match(/\r\n|\r|\n/g) || []).length
104
- return `[Pasted text +${newlineCount} lines] `
105
- }
106
- function PromptInput({
107
- commands,
108
- forkNumber,
109
- messageLogName,
110
- isDisabled,
111
- isLoading,
112
- onQuery,
113
- debug,
114
- verbose,
115
- messages,
116
- setToolJSX,
117
- onAutoUpdaterResult,
118
- autoUpdaterResult,
119
- tools,
120
- input,
121
- onInputChange,
122
- mode,
123
- onModeChange,
124
- submitCount,
125
- onSubmitCountChange,
126
- setIsLoading,
127
- abortController,
128
- setAbortController,
129
- onShowMessageSelector,
130
- setForkConvoWithMessagesOnTheNextRender,
131
- readFileTimestamps,
132
- onModelChange,
133
- }: Props): React.ReactNode {
134
- const [isAutoUpdating, setIsAutoUpdating] = useState(false)
135
- const [exitMessage, setExitMessage] = useState<{
136
- show: boolean
137
- key?: string
138
- }>({ show: false })
139
- const [message, setMessage] = useState<{ show: boolean; text?: string }>({
140
- show: false,
141
- })
142
- const [modelSwitchMessage, setModelSwitchMessage] = useState<{
143
- show: boolean
144
- text?: string
145
- }>({
146
- show: false,
147
- })
148
- const [pastedImage, setPastedImage] = useState<string | null>(null)
149
- const [placeholder, setPlaceholder] = useState('')
150
- const [cursorOffset, setCursorOffset] = useState<number>(input.length)
151
- const [pastedText, setPastedText] = useState<string | null>(null)
152
-
153
- // Permission context for mode management
154
- const { cycleMode, currentMode } = usePermissionContext()
155
-
156
- // useEffect(() => {
157
- // getExampleCommands().then(commands => {
158
- // setPlaceholder(`Try "${sample(commands)}"`)
159
- // })
160
- // }, [])
161
- const { columns } = useTerminalSize()
162
-
163
- const commandWidth = useMemo(
164
- () => Math.max(...commands.map(cmd => cmd.userFacingName().length)) + 5,
165
- [commands],
166
- )
167
-
168
- // Unified completion system - one hook to rule them all (now with terminal behavior)
169
- const {
170
- suggestions,
171
- selectedIndex,
172
- isActive: completionActive,
173
- emptyDirMessage,
174
- } = useUnifiedCompletion({
175
- input,
176
- cursorOffset,
177
- onInputChange,
178
- setCursorOffset,
179
- commands,
180
- onSubmit,
181
- })
182
-
183
- // Get theme early for memoized rendering
184
- const theme = getTheme()
185
-
186
- // Memoized completion suggestions rendering - after useUnifiedCompletion
187
- const renderedSuggestions = useMemo(() => {
188
- if (suggestions.length === 0) return null
189
-
190
- return suggestions.map((suggestion, index) => {
191
- const isSelected = index === selectedIndex
192
- const isAgent = suggestion.type === 'agent'
193
-
194
- // Simple color logic without complex lookups
195
- const displayColor = isSelected
196
- ? theme.suggestion
197
- : (isAgent && suggestion.metadata?.color)
198
- ? suggestion.metadata.color
199
- : undefined
200
-
201
- return (
202
- <Box key={`${suggestion.type}-${suggestion.value}-${index}`} flexDirection="row">
203
- <Text
204
- color={displayColor}
205
- dimColor={!isSelected && !displayColor}
206
- >
207
- {isSelected ? '◆ ' : ' '}
208
- {suggestion.displayValue}
209
- </Text>
210
- </Box>
211
- )
212
- })
213
- }, [suggestions, selectedIndex, theme.suggestion])
214
-
215
- const onChange = useCallback(
216
- (value: string) => {
217
- if (value.startsWith('!')) {
218
- onModeChange('bash')
219
- return
220
- }
221
- if (value.startsWith('#')) {
222
- onModeChange('koding')
223
- return
224
- }
225
- onInputChange(value)
226
- },
227
- [onModeChange, onInputChange],
228
- )
229
-
230
- // Handle Shift+M model switching with enhanced debugging
231
- const handleQuickModelSwitch = useCallback(async () => {
232
- const modelManager = getModelManager()
233
- const currentTokens = countTokens(messages)
234
-
235
- // Get debug info for better error reporting
236
- const debugInfo = modelManager.getModelSwitchingDebugInfo()
237
-
238
- const switchResult = modelManager.switchToNextModel(currentTokens)
239
-
240
- if (switchResult.success && switchResult.modelName) {
241
- // Successful switch - use enhanced message from model manager
242
- onSubmitCountChange(prev => prev + 1)
243
- setModelSwitchMessage({
244
- show: true,
245
- text: switchResult.message || `✅ Switched to ${switchResult.modelName}`,
246
- })
247
- setTimeout(() => setModelSwitchMessage({ show: false }), 3000)
248
- } else if (switchResult.blocked && switchResult.message) {
249
- // Context overflow - show detailed message
250
- setModelSwitchMessage({
251
- show: true,
252
- text: switchResult.message,
253
- })
254
- setTimeout(() => setModelSwitchMessage({ show: false }), 5000)
255
- } else {
256
- // Enhanced error reporting with debug info
257
- let errorMessage = switchResult.message
258
-
259
- if (!errorMessage) {
260
- if (debugInfo.totalModels === 0) {
261
- errorMessage = '❌ No models configured. Use /model to add models.'
262
- } else if (debugInfo.activeModels === 0) {
263
- errorMessage = `❌ No active models (${debugInfo.totalModels} total, all inactive). Use /model to activate models.`
264
- } else if (debugInfo.activeModels === 1) {
265
- // Show ALL models including inactive ones for debugging
266
- const allModelNames = debugInfo.availableModels.map(m => `${m.name}${m.isActive ? '' : ' (inactive)'}`).join(', ')
267
- errorMessage = `⚠️ Only 1 active model out of ${debugInfo.totalModels} total models: ${allModelNames}. ALL configured models will be activated for switching.`
268
- } else {
269
- errorMessage = `❌ Model switching failed (${debugInfo.activeModels} active, ${debugInfo.totalModels} total models available)`
270
- }
271
- }
272
-
273
- setModelSwitchMessage({
274
- show: true,
275
- text: errorMessage,
276
- })
277
- setTimeout(() => setModelSwitchMessage({ show: false }), 6000)
278
- }
279
- }, [onSubmitCountChange, messages])
280
-
281
- const { resetHistory, onHistoryUp, onHistoryDown } = useArrowKeyHistory(
282
- (value: string, mode: 'bash' | 'prompt' | 'koding') => {
283
- onChange(value)
284
- onModeChange(mode)
285
- },
286
- input,
287
- )
288
-
289
- // Only use history navigation when there are no suggestions
290
- const handleHistoryUp = () => {
291
- if (!completionActive) {
292
- onHistoryUp()
293
- }
294
- }
295
-
296
- const handleHistoryDown = () => {
297
- if (!completionActive) {
298
- onHistoryDown()
299
- }
300
- }
301
-
302
- async function onSubmit(input: string, isSubmittingSlashCommand = false) {
303
- // Special handling for "put a verbose summary" and similar action prompts in koding mode
304
- if (
305
- (mode === 'koding' || input.startsWith('#')) &&
306
- input.match(/^(#\s*)?(put|create|generate|write|give|provide)/i)
307
- ) {
308
- try {
309
- // Store the original input for history
310
- const originalInput = input
311
-
312
- // Strip the # prefix if present
313
- const cleanInput = mode === 'koding' ? input : input.substring(1).trim()
314
-
315
- // Add to history and clear input field
316
- addToHistory(mode === 'koding' ? `#${input}` : input)
317
- onInputChange('')
318
-
319
- // Create additional context to inform Claude this is for KODING.md
320
- const kodingContext =
321
- 'The user is using Koding mode. Format your response as a comprehensive, well-structured document suitable for adding to AGENTS.md. Use proper markdown formatting with headings, lists, code blocks, etc. The response should be complete and ready to add to AGENTS.md documentation.'
322
-
323
- // Switch to prompt mode but tag the submission for later capture
324
- onModeChange('prompt')
325
-
326
- // 🔧 Fix Koding mode: clean up previous state
327
- if (abortController) {
328
- abortController.abort()
329
- }
330
- setIsLoading(false)
331
- await new Promise(resolve => setTimeout(resolve, 0))
332
-
333
- // Set loading state - AbortController now created in onQuery
334
- setIsLoading(true)
335
-
336
- // Process as a normal user input but with special handling
337
- const messages = await processUserInput(
338
- cleanInput,
339
- 'prompt', // Use prompt mode for processing
340
- setToolJSX,
341
- {
342
- options: {
343
- commands,
344
- forkNumber,
345
- messageLogName,
346
- tools,
347
- verbose,
348
- maxThinkingTokens: 0,
349
- // Add context flag for koding mode
350
- isKodingRequest: true,
351
- kodingContext,
352
- },
353
- messageId: undefined,
354
- abortController: abortController || new AbortController(), // Temporary controller, actual one created in onQuery
355
- readFileTimestamps,
356
- setForkConvoWithMessagesOnTheNextRender,
357
- },
358
- pastedImage ?? null,
359
- )
360
-
361
- // Send query and capture response
362
- if (messages.length) {
363
- await onQuery(messages)
364
-
365
- // After query completes, the last message should be Claude's response
366
- // We'll set up a one-time listener to capture and save Claude's response
367
- // This will be handled by the REPL component or message handler
368
- }
369
-
370
- return
371
- } catch (e) {
372
- // If something fails, log the error
373
- console.error('Error processing Koding request:', e)
374
- }
375
- }
376
-
377
- // If in koding mode or input starts with '#', interpret it using AI before appending to AGENTS.md
378
- else if (mode === 'koding' || input.startsWith('#')) {
379
- try {
380
- // Strip the # if we're in koding mode and the user didn't type it (since it's implied)
381
- const contentToInterpret =
382
- mode === 'koding' && !input.startsWith('#')
383
- ? input.trim()
384
- : input.substring(1).trim()
385
-
386
- const interpreted = await interpretHashCommand(contentToInterpret)
387
- handleHashCommand(interpreted)
388
- } catch (e) {
389
- // If interpretation fails, log the error
390
- }
391
- onInputChange('')
392
- addToHistory(mode === 'koding' ? `#${input}` : input)
393
- onModeChange('prompt')
394
- return
395
- }
396
- if (input === '') {
397
- return
398
- }
399
- if (isDisabled) {
400
- return
401
- }
402
- if (isLoading) {
403
- return
404
- }
405
-
406
- // Handle Enter key when completions are active
407
- // If there are suggestions showing, Enter should complete the selection, not send the message
408
- if (suggestions.length > 0 && completionActive) {
409
- // The completion is handled by useUnifiedCompletion hook
410
- // Just return to prevent message sending
411
- return
412
- }
413
-
414
- // Handle exit commands
415
- if (['exit', 'quit', ':q', ':q!', ':wq', ':wq!'].includes(input.trim())) {
416
- exit()
417
- }
418
-
419
- let finalInput = input
420
- if (pastedText) {
421
- // Create the prompt pattern that would have been used for this pasted text
422
- const pastedPrompt = getPastedTextPrompt(pastedText)
423
- if (finalInput.includes(pastedPrompt)) {
424
- finalInput = finalInput.replace(pastedPrompt, pastedText)
425
- } // otherwise, ignore the pastedText if the user has modified the prompt
426
- }
427
- onInputChange('')
428
- onModeChange('prompt')
429
- // Suggestions are now handled by unified completion
430
- setPastedImage(null)
431
- setPastedText(null)
432
- onSubmitCountChange(_ => _ + 1)
433
-
434
- setIsLoading(true)
435
-
436
- const newAbortController = new AbortController()
437
- setAbortController(newAbortController)
438
-
439
- const messages = await processUserInput(
440
- finalInput,
441
- mode,
442
- setToolJSX,
443
- {
444
- options: {
445
- commands,
446
- forkNumber,
447
- messageLogName,
448
- tools,
449
- verbose,
450
- maxThinkingTokens: 0,
451
- },
452
- messageId: undefined,
453
- abortController: newAbortController,
454
- readFileTimestamps,
455
- setForkConvoWithMessagesOnTheNextRender,
456
- },
457
- pastedImage ?? null,
458
- )
459
-
460
- if (messages.length) {
461
- onQuery(messages, newAbortController)
462
- } else {
463
- // Local JSX commands
464
- addToHistory(input)
465
- resetHistory()
466
- return
467
- }
468
-
469
- for (const message of messages) {
470
- if (message.type === 'user') {
471
- const inputToAdd = mode === 'bash' ? `!${input}` : input
472
- addToHistory(inputToAdd)
473
- resetHistory()
474
- }
475
- }
476
- }
477
-
478
- function onImagePaste(image: string) {
479
- onModeChange('prompt')
480
- setPastedImage(image)
481
- }
482
-
483
- function onTextPaste(rawText: string) {
484
- // Replace any \r with \n first to match useTextInput's conversion behavior
485
- const text = rawText.replace(/\r/g, '\n')
486
-
487
- // Get prompt with newline count
488
- const pastedPrompt = getPastedTextPrompt(text)
489
-
490
- // Update the input with a visual indicator that text has been pasted
491
- const newInput =
492
- input.slice(0, cursorOffset) + pastedPrompt + input.slice(cursorOffset)
493
- onInputChange(newInput)
494
-
495
- // Update cursor position to be after the inserted indicator
496
- setCursorOffset(cursorOffset + pastedPrompt.length)
497
-
498
- // Still set the pastedText state for actual submission
499
- setPastedText(text)
500
- }
501
-
502
- useInput((inputChar, key) => {
503
- // For bash mode, only exit when deleting the last character (which would be the '!' character)
504
- if (mode === 'bash' && (key.backspace || key.delete)) {
505
- // Check the current input state, not the inputChar parameter
506
- // If current input is empty, we're about to delete the '!' character, so exit bash mode
507
- if (input === '') {
508
- onModeChange('prompt')
509
- }
510
- return
511
- }
512
-
513
- // For koding mode, only exit when deleting the last character (which would be the '#' character)
514
- if (mode === 'koding' && (key.backspace || key.delete)) {
515
- // Check the current input state, not the inputChar parameter
516
- // If current input is empty, we're about to delete the '#' character, so exit koding mode
517
- if (input === '') {
518
- onModeChange('prompt')
519
- }
520
- return
521
- }
522
-
523
- // For other modes, keep the original behavior
524
- if (inputChar === '' && (key.escape || key.backspace || key.delete)) {
525
- onModeChange('prompt')
526
- }
527
- // esc is a little overloaded:
528
- // - when we're loading a response, it's used to cancel the request
529
- // - otherwise, it's used to show the message selector
530
- // - when double pressed, it's used to clear the input
531
- if (key.escape && messages.length > 0 && !input && !isLoading) {
532
- onShowMessageSelector()
533
- }
534
-
535
- // Shift+Tab for mode cycling (matching original Claude Code implementation)
536
- if (key.shift && key.tab) {
537
- cycleMode()
538
- return true // Explicitly handled
539
- }
540
-
541
- return false // Not handled, allow other hooks
542
- })
543
-
544
- // Handle special key combinations before character input
545
- const handleSpecialKey = useCallback((inputChar: string, key: any): boolean => {
546
- // Shift+M for model switching - intercept before character input
547
- if (key.shift && (inputChar === 'M' || inputChar === 'm')) {
548
- handleQuickModelSwitch()
549
- return true // Prevent character from being input
550
- }
551
-
552
- return false // Not handled, allow normal processing
553
- }, [handleQuickModelSwitch])
554
-
555
- const textInputColumns = useTerminalSize().columns - 6
556
- const tokenUsage = useMemo(() => countTokens(messages), [messages])
557
-
558
- // 🔧 Fix: Track model ID changes to detect external config updates
559
- const modelManager = getModelManager()
560
- const currentModelId = (modelManager.getModel('main') as any)?.id || null
561
-
562
- const modelInfo = useMemo(() => {
563
- // Force fresh ModelManager instance to detect config changes
564
- const freshModelManager = getModelManager()
565
- const currentModel = freshModelManager.getModel('main')
566
- if (!currentModel) {
567
- return null
568
- }
569
-
570
- return {
571
- name: currentModel.modelName, // 🔧 Fix: Use actual model name, not display name
572
- id: (currentModel as any).id, // 添加模型ID用于调试
573
- provider: currentModel.provider, // 添加提供商信息
574
- contextLength: currentModel.contextLength,
575
- currentTokens: tokenUsage,
576
- }
577
- }, [tokenUsage, modelSwitchMessage.show, submitCount, currentModelId]) // Track model ID to detect config changes
578
-
579
- return (
580
- <Box flexDirection="column">
581
- {/* Model info in top-right corner */}
582
- {modelInfo && (
583
- <Box justifyContent="flex-end" marginBottom={1}>
584
- <Text dimColor>
585
- [{modelInfo.provider}] {modelInfo.name}:{' '}
586
- {Math.round(modelInfo.currentTokens / 1000)}k /{' '}
587
- {Math.round(modelInfo.contextLength / 1000)}k
588
- </Text>
589
- </Box>
590
- )}
591
-
592
- <Box
593
- alignItems="flex-start"
594
- justifyContent="flex-start"
595
- borderColor={
596
- mode === 'bash'
597
- ? theme.bashBorder
598
- : mode === 'koding'
599
- ? theme.noting
600
- : theme.secondaryBorder
601
- }
602
- borderDimColor
603
- borderStyle="round"
604
- marginTop={1}
605
- width="100%"
606
- >
607
- <Box
608
- alignItems="flex-start"
609
- alignSelf="flex-start"
610
- flexWrap="nowrap"
611
- justifyContent="flex-start"
612
- width={3}
613
- >
614
- {mode === 'bash' ? (
615
- <Text color={theme.bashBorder}>&nbsp;!&nbsp;</Text>
616
- ) : mode === 'koding' ? (
617
- <Text color={theme.noting}>&nbsp;#&nbsp;</Text>
618
- ) : (
619
- <Text color={isLoading ? theme.secondaryText : undefined}>
620
- &nbsp;&gt;&nbsp;
621
- </Text>
622
- )}
623
- </Box>
624
- <Box paddingRight={1}>
625
- <TextInput
626
- multiline
627
- onSubmit={onSubmit}
628
- onChange={onChange}
629
- value={input}
630
- onHistoryUp={handleHistoryUp}
631
- onHistoryDown={handleHistoryDown}
632
- onHistoryReset={() => resetHistory()}
633
- placeholder={submitCount > 0 ? undefined : placeholder}
634
- onExit={() => process.exit(0)}
635
- onExitMessage={(show, key) => setExitMessage({ show, key })}
636
- onMessage={(show, text) => setMessage({ show, text })}
637
- onImagePaste={onImagePaste}
638
- columns={textInputColumns}
639
- isDimmed={isDisabled || isLoading}
640
- disableCursorMovementForUpDownKeys={completionActive}
641
- cursorOffset={cursorOffset}
642
- onChangeCursorOffset={setCursorOffset}
643
- onPaste={onTextPaste}
644
- onSpecialKey={handleSpecialKey}
645
- />
646
- </Box>
647
- </Box>
648
- {!completionActive && suggestions.length === 0 && (
649
- <Box
650
- flexDirection="row"
651
- justifyContent="space-between"
652
- paddingX={2}
653
- paddingY={0}
654
- >
655
- <Box justifyContent="flex-start" gap={1}>
656
- {exitMessage.show ? (
657
- <Text dimColor>Press {exitMessage.key} again to exit</Text>
658
- ) : message.show ? (
659
- <Text dimColor>{message.text}</Text>
660
- ) : modelSwitchMessage.show ? (
661
- <Text color={theme.success}>{modelSwitchMessage.text}</Text>
662
- ) : (
663
- <>
664
- <Text
665
- color={mode === 'bash' ? theme.bashBorder : undefined}
666
- dimColor={mode !== 'bash'}
667
- >
668
- ! for bash mode
669
- </Text>
670
- <Text
671
- color={mode === 'koding' ? theme.noting : undefined}
672
- dimColor={mode !== 'koding'}
673
- >
674
- · # for AGENTS.md
675
- </Text>
676
- <Text dimColor>
677
- · / for commands · shift+m to switch model · esc to undo
678
- </Text>
679
- </>
680
- )}
681
- </Box>
682
- <SentryErrorBoundary children={
683
- <Box justifyContent="flex-end" gap={1}>
684
- {!autoUpdaterResult &&
685
- !isAutoUpdating &&
686
- !debug &&
687
- tokenUsage < WARNING_THRESHOLD && (
688
- <Text dimColor>
689
- {terminalSetup.isEnabled &&
690
- isShiftEnterKeyBindingInstalled()
691
- ? 'shift + ⏎ for newline'
692
- : '\\⏎ for newline'}
693
- </Text>
694
- )}
695
- <TokenWarning tokenUsage={tokenUsage} />
696
- {/* <AutoUpdater
697
- debug={debug}
698
- onAutoUpdaterResult={onAutoUpdaterResult}
699
- autoUpdaterResult={autoUpdaterResult}
700
- isUpdating={isAutoUpdating}
701
- onChangeIsUpdating={setIsAutoUpdating}
702
- /> */}
703
- </Box>
704
- } />
705
- </Box>
706
- )}
707
- {/* Unified completion suggestions - optimized rendering */}
708
- {suggestions.length > 0 && (
709
- <Box
710
- flexDirection="row"
711
- justifyContent="space-between"
712
- paddingX={2}
713
- paddingY={0}
714
- >
715
- <Box flexDirection="column">
716
- {renderedSuggestions}
717
-
718
- {/* 简洁操作提示框 */}
719
- <Box marginTop={1} paddingX={3} borderStyle="round" borderColor="gray">
720
- <Text dimColor={!emptyDirMessage} color={emptyDirMessage ? "yellow" : undefined}>
721
- {emptyDirMessage || (() => {
722
- const selected = suggestions[selectedIndex]
723
- if (!selected) {
724
- return '↑↓ navigate • → accept • Tab cycle • Esc close'
725
- }
726
- if (selected?.value.endsWith('/')) {
727
- return '→ enter directory • ↑↓ navigate • Tab cycle • Esc close'
728
- } else if (selected?.type === 'agent') {
729
- return '→ select agent • ↑↓ navigate • Tab cycle • Esc close'
730
- } else {
731
- return '→ insert reference • ↑↓ navigate • Tab cycle • Esc close'
732
- }
733
- })()}
734
- </Text>
735
- </Box>
736
- </Box>
737
- <SentryErrorBoundary children={
738
- <Box justifyContent="flex-end" gap={1}>
739
- <TokenWarning tokenUsage={countTokens(messages)} />
740
- <AutoUpdater
741
- debug={debug}
742
- onAutoUpdaterResult={onAutoUpdaterResult}
743
- autoUpdaterResult={autoUpdaterResult}
744
- isUpdating={isAutoUpdating}
745
- onChangeIsUpdating={setIsAutoUpdating}
746
- />
747
- </Box>
748
- } />
749
- </Box>
750
- )}
751
- </Box>
752
- )
753
- }
754
-
755
- export default memo(PromptInput)
756
-
757
- function exit(): never {
758
- setTerminalTitle('')
759
- process.exit(0)
760
- }