@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,148 @@
1
+ import { Box, Text } from 'ink'
2
+ import * as React from 'react'
3
+ import { getTheme } from '../utils/theme'
4
+ import { gte } from 'semver'
5
+ import { useEffect, useState } from 'react'
6
+ import { isAutoUpdaterDisabled } from '../utils/config'
7
+ import {
8
+ AutoUpdaterResult,
9
+ getLatestVersion,
10
+ installGlobalPackage,
11
+ } from '../utils/autoUpdater.js'
12
+ import { useInterval } from '../hooks/useInterval'
13
+ import { logEvent } from '../services/statsig'
14
+ import { MACRO } from '../constants/macros'
15
+ import { PRODUCT_COMMAND } from '../constants/product'
16
+ type Props = {
17
+ debug: boolean
18
+ isUpdating: boolean
19
+ onChangeIsUpdating: (isUpdating: boolean) => void
20
+ onAutoUpdaterResult: (autoUpdaterResult: AutoUpdaterResult) => void
21
+ autoUpdaterResult: AutoUpdaterResult | null
22
+ }
23
+
24
+ export function AutoUpdater({
25
+ debug,
26
+ isUpdating,
27
+ onChangeIsUpdating,
28
+ onAutoUpdaterResult,
29
+ autoUpdaterResult,
30
+ }: Props): React.ReactNode {
31
+ const theme = getTheme()
32
+ const [versions, setVersions] = useState<{
33
+ global?: string | null
34
+ latest?: string | null
35
+ }>({})
36
+ const checkForUpdates = React.useCallback(async () => {
37
+ if (process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'dev') {
38
+ return
39
+ }
40
+
41
+ if (isUpdating) {
42
+ return
43
+ }
44
+
45
+ // Get versions
46
+ const globalVersion = MACRO.VERSION
47
+ const latestVersion = await getLatestVersion()
48
+ const isDisabled = true //await isAutoUpdaterDisabled()
49
+
50
+ setVersions({ global: globalVersion, latest: latestVersion })
51
+
52
+ // Check if update needed and perform update
53
+ if (
54
+ !isDisabled &&
55
+ globalVersion &&
56
+ latestVersion &&
57
+ !gte(globalVersion, latestVersion)
58
+ ) {
59
+ const startTime = Date.now()
60
+ onChangeIsUpdating(true)
61
+ const installStatus = await installGlobalPackage()
62
+ onChangeIsUpdating(false)
63
+
64
+ if (installStatus === 'success') {
65
+ logEvent('tengu_auto_updater_success', {
66
+ fromVersion: globalVersion,
67
+ toVersion: latestVersion,
68
+ durationMs: String(Date.now() - startTime),
69
+ })
70
+ } else {
71
+ logEvent('tengu_auto_updater_fail', {
72
+ fromVersion: globalVersion,
73
+ attemptedVersion: latestVersion,
74
+ status: installStatus,
75
+ durationMs: String(Date.now() - startTime),
76
+ })
77
+ }
78
+
79
+ onAutoUpdaterResult({
80
+ version: latestVersion!,
81
+ status: installStatus,
82
+ })
83
+ }
84
+ // Don't re-render when isUpdating changes
85
+ // TODO: Find a cleaner way to do this
86
+ // eslint-disable-next-line react-hooks/exhaustive-deps
87
+ }, [onAutoUpdaterResult])
88
+
89
+ // Initial check
90
+ useEffect(() => {
91
+ // checkForUpdates()
92
+ }, [checkForUpdates])
93
+
94
+ // Check every 30 minutes
95
+ // useInterval(checkForUpdates, 30 * 60 * 1000)
96
+
97
+ if (debug) {
98
+ return (
99
+ <Box flexDirection="row">
100
+ <Text dimColor>
101
+ globalVersion: {versions.global} &middot; latestVersion:{' '}
102
+ {versions.latest}
103
+ </Text>
104
+ </Box>
105
+ )
106
+ }
107
+
108
+ if (!autoUpdaterResult?.version && (!versions.global || !versions.latest)) {
109
+ return null
110
+ }
111
+
112
+ if (!autoUpdaterResult?.version && !isUpdating) {
113
+ return null
114
+ }
115
+
116
+ return (
117
+ <Box flexDirection="row">
118
+ {debug && (
119
+ <Text dimColor>
120
+ globalVersion: {versions.global} &middot; latestVersion:{' '}
121
+ {versions.latest}
122
+ </Text>
123
+ )}
124
+ {isUpdating && (
125
+ <>
126
+ <Box>
127
+ <Text color={theme.secondaryText} dimColor wrap="end">
128
+ Auto-updating to v{versions.latest}…
129
+ </Text>
130
+ </Box>
131
+ </>
132
+ )}
133
+ {autoUpdaterResult?.status === 'success' && autoUpdaterResult?.version ? (
134
+ <Text color={theme.success}>
135
+ ✓ Update installed &middot; Restart to apply
136
+ </Text>
137
+ ) : null}
138
+ {(autoUpdaterResult?.status === 'install_failed' ||
139
+ autoUpdaterResult?.status === 'no_permissions') && (
140
+ <Text color={theme.error}>
141
+ ✗ Auto-update failed &middot; Try{' '}
142
+ <Text bold>{PRODUCT_COMMAND} doctor</Text> or{' '}
143
+ <Text bold>npm i -g {MACRO.PACKAGE_URL}</Text>
144
+ </Text>
145
+ )}
146
+ </Box>
147
+ )
148
+ }
@@ -0,0 +1,367 @@
1
+ import { Box, Text, useInput } from 'ink'
2
+ import * as React from 'react'
3
+ import { useState, useCallback, useEffect } from 'react'
4
+ import { getTheme } from '../utils/theme'
5
+ import { getMessagesGetter } from '../messages'
6
+ import type { Message } from '../query'
7
+ import TextInput from './TextInput'
8
+ import { logError, getInMemoryErrors } from '../utils/log'
9
+ import { env } from '../utils/env'
10
+ import { getGitState, getIsGit, GitRepoState } from '../utils/git'
11
+ import { useTerminalSize } from '../hooks/useTerminalSize'
12
+ import { getAnthropicApiKey, getGlobalConfig } from '../utils/config'
13
+ import { USER_AGENT } from '../utils/http'
14
+ import { logEvent } from '../services/statsig'
15
+ import { PRODUCT_NAME } from '../constants/product'
16
+ import { API_ERROR_MESSAGE_PREFIX, queryQuick } from '../services/claude'
17
+ import { openBrowser } from '../utils/browser'
18
+ import { useExitOnCtrlCD } from '../hooks/useExitOnCtrlCD'
19
+ import { MACRO } from '../constants/macros'
20
+ import { GITHUB_ISSUES_REPO_URL } from '../constants/product'
21
+
22
+ type Props = {
23
+ onDone(result: string): void
24
+ }
25
+
26
+ type Step = 'userInput' | 'consent' | 'submitting' | 'done'
27
+
28
+ type FeedbackData = {
29
+ // Removing because of privacy concerns. Add this back in when we have a more
30
+ // robust tool for viewing feedback data that can de-identify users
31
+ // user_id: string
32
+ // session_id: string
33
+ message_count: number
34
+ datetime: string
35
+ description: string
36
+ platform: string
37
+ gitRepo: boolean
38
+ version: string | null
39
+ transcript: Message[]
40
+ }
41
+
42
+ export function Bug({ onDone }: Props): React.ReactNode {
43
+ const [step, setStep] = useState<Step>('userInput')
44
+ const [cursorOffset, setCursorOffset] = useState(0)
45
+ const [description, setDescription] = useState('')
46
+ const [feedbackId, setFeedbackId] = useState<string | null>(null)
47
+ const [error, setError] = useState<string | null>(null)
48
+ const [envInfo, setEnvInfo] = useState<{
49
+ isGit: boolean
50
+ gitState: GitRepoState | null
51
+ }>({ isGit: false, gitState: null })
52
+ const [title, setTitle] = useState<string | null>(null)
53
+ const textInputColumns = useTerminalSize().columns - 4
54
+ const messages = getMessagesGetter()()
55
+
56
+ useEffect(() => {
57
+ async function loadEnvInfo() {
58
+ const isGit = await getIsGit()
59
+ let gitState: GitRepoState | null = null
60
+ if (isGit) {
61
+ gitState = await getGitState()
62
+ }
63
+ setEnvInfo({ isGit, gitState })
64
+ }
65
+ void loadEnvInfo()
66
+ }, [])
67
+
68
+ const exitState = useExitOnCtrlCD(() => process.exit(0))
69
+
70
+ const submitReport = useCallback(async () => {
71
+ setStep('done')
72
+ // setStep('submitting')
73
+ // setError(null)
74
+ // setFeedbackId(null)
75
+
76
+ // const reportData = {
77
+ // message_count: messages.length,
78
+ // datetime: new Date().toISOString(),
79
+ // description,
80
+ // platform: env.platform,
81
+ // gitRepo: envInfo.isGit,
82
+ // terminal: env.terminal,
83
+ // version: MACRO.VERSION,
84
+ // transcript: messages,
85
+ // errors: getInMemoryErrors(),
86
+ // }
87
+
88
+ // const [result, t] = await Promise.all([
89
+ // submitFeedback(reportData),
90
+ // generateTitle(description),
91
+ // ])
92
+
93
+ // setTitle(t)
94
+
95
+ // if (result.success) {
96
+ // if (result.feedbackId) {
97
+ // setFeedbackId(result.feedbackId)
98
+ // logEvent('tengu_bug_report_submitted', {
99
+ // feedback_id: result.feedbackId,
100
+ // })
101
+ // }
102
+ // setStep('done')
103
+ // } else {
104
+ // console.log(result)
105
+ // setError('Could not submit feedback. Please try again later.')
106
+ // setStep('userInput')
107
+ // }
108
+ }, [description, envInfo.isGit, messages])
109
+
110
+ useInput((input, key) => {
111
+ // Allow any key press to close the dialog when done or when there's an error
112
+ // if (step === 'done') {
113
+ // if (key.return && feedbackId && title) {
114
+ // // Open GitHub issue URL when Enter is pressed
115
+ // const issueUrl = createGitHubIssueUrl(feedbackId, title, description)
116
+ // void openBrowser(issueUrl)
117
+ // }
118
+ // onDone('<bash-stdout>Bug report submitted</bash-stdout>')
119
+ // return
120
+ // }
121
+
122
+ if (error) {
123
+ onDone('<bash-stderr>Error submitting bug report</bash-stderr>')
124
+ return
125
+ }
126
+
127
+ if (key.escape) {
128
+ onDone('<bash-stderr>Bug report cancelled</bash-stderr>')
129
+ return
130
+ }
131
+
132
+ if (step === 'consent' && (key.return || input === ' ')) {
133
+ const issueUrl = createGitHubIssueUrl(
134
+ feedbackId,
135
+ description.slice(0, 80),
136
+ description,
137
+ )
138
+ void openBrowser(issueUrl)
139
+ onDone('<bash-stdout>Bug report submitted</bash-stdout>')
140
+ }
141
+ })
142
+
143
+ const theme = getTheme()
144
+
145
+ return (
146
+ <>
147
+ <Box
148
+ flexDirection="column"
149
+ borderStyle="round"
150
+ borderColor={theme.permission}
151
+ paddingX={1}
152
+ paddingBottom={1}
153
+ gap={1}
154
+ >
155
+ <Text bold color={theme.permission}>
156
+ Submit Bug Report
157
+ </Text>
158
+ {step === 'userInput' && (
159
+ <Box flexDirection="column" gap={1}>
160
+ <Text>
161
+ Describe the issue below and copy/paste any errors you see:
162
+ </Text>
163
+ <TextInput
164
+ value={description}
165
+ onChange={setDescription}
166
+ columns={textInputColumns}
167
+ onSubmit={() => setStep('consent')}
168
+ onExitMessage={() =>
169
+ onDone('<bash-stderr>Bug report cancelled</bash-stderr>')
170
+ }
171
+ cursorOffset={cursorOffset}
172
+ onChangeCursorOffset={setCursorOffset}
173
+ />
174
+ {error && (
175
+ <Box flexDirection="column" gap={1}>
176
+ <Text color="red">{error}</Text>
177
+ <Text dimColor>Press any key to close</Text>
178
+ </Box>
179
+ )}
180
+ </Box>
181
+ )}
182
+
183
+ {step === 'consent' && (
184
+ <Box flexDirection="column">
185
+ <Text>This report will include:</Text>
186
+ <Box marginLeft={2} flexDirection="column">
187
+ <Text>
188
+ - Your bug description: <Text dimColor>{description}</Text>
189
+ </Text>
190
+ <Text>
191
+ - Environment info:{' '}
192
+ <Text dimColor>
193
+ {env.platform}, {env.terminal}, v{MACRO.VERSION}
194
+ </Text>
195
+ </Text>
196
+ {/* {envInfo.gitState && (
197
+ <Text>
198
+ - Git repo metadata:{' '}
199
+ <Text dimColor>
200
+ {envInfo.gitState.branchName}
201
+ {envInfo.gitState.commitHash
202
+ ? `, ${envInfo.gitState.commitHash.slice(0, 7)}`
203
+ : ''}
204
+ {envInfo.gitState.remoteUrl
205
+ ? ` @ ${envInfo.gitState.remoteUrl}`
206
+ : ''}
207
+ {!envInfo.gitState.isHeadOnRemote && ', not synced'}
208
+ {!envInfo.gitState.isClean && ', has local changes'}
209
+ </Text>
210
+ </Text>
211
+ )} */}
212
+ <Text>- Model settings (no api keys)</Text>
213
+ </Box>
214
+ {/* <Box marginTop={1}>
215
+ <Text wrap="wrap" dimColor>
216
+ We will use your feedback to debug related issues or to improve{' '}
217
+ {PRODUCT_NAME}&apos;s functionality (eg. to reduce the risk of
218
+ bugs occurring in the future). Anthropic will not train
219
+ generative models using feedback from {PRODUCT_NAME}.
220
+ </Text>
221
+ </Box>
222
+ <Box marginTop={1}>
223
+ <Text>
224
+ Press <Text bold>Enter</Text> to confirm and submit.
225
+ </Text>
226
+ </Box> */}
227
+ </Box>
228
+ )}
229
+
230
+ {step === 'submitting' && (
231
+ <Box flexDirection="row" gap={1}>
232
+ <Text>Submitting report…</Text>
233
+ </Box>
234
+ )}
235
+
236
+ {step === 'done' && (
237
+ <Box flexDirection="column">
238
+ <Text color={getTheme().success}>Thank you for your report!</Text>
239
+ {feedbackId && <Text dimColor>Feedback ID: {feedbackId}</Text>}
240
+ <Box marginTop={1}>
241
+ <Text>Press </Text>
242
+ <Text bold>Enter </Text>
243
+ <Text>
244
+ to also create a GitHub issue, or any other key to close.
245
+ </Text>
246
+ </Box>
247
+ </Box>
248
+ )}
249
+ </Box>
250
+
251
+ <Box marginLeft={3}>
252
+ <Text dimColor>
253
+ {exitState.pending ? (
254
+ <>Press {exitState.keyName} again to exit</>
255
+ ) : step === 'userInput' ? (
256
+ <>Enter to continue · Esc to cancel</>
257
+ ) : step === 'consent' ? (
258
+ <>Enter to open browser to create GitHub issue · Esc to cancel</>
259
+ ) : null}
260
+ </Text>
261
+ </Box>
262
+ </>
263
+ )
264
+ }
265
+
266
+ function createGitHubIssueUrl(
267
+ feedbackId: string,
268
+ title: string,
269
+ description: string,
270
+ ): string {
271
+ const globalConfig = getGlobalConfig()
272
+
273
+ // Get ModelProfile information instead of legacy model info
274
+ const modelProfiles = globalConfig.modelProfiles || []
275
+ const activeProfiles = modelProfiles.filter(p => p.isActive)
276
+
277
+ let modelInfo = '## Models\n'
278
+ if (activeProfiles.length === 0) {
279
+ modelInfo += '- No model profiles configured\n'
280
+ } else {
281
+ activeProfiles.forEach(profile => {
282
+ modelInfo += `- ${profile.name}\n`
283
+ modelInfo += ` - provider: ${profile.provider}\n`
284
+ modelInfo += ` - model: ${profile.modelName}\n`
285
+ modelInfo += ` - baseURL: ${profile.baseURL}\n`
286
+ modelInfo += ` - maxTokens: ${profile.maxTokens}\n`
287
+ modelInfo += ` - contextLength: ${profile.contextLength}\n`
288
+ if (profile.reasoningEffort) {
289
+ modelInfo += ` - reasoning effort: ${profile.reasoningEffort}\n`
290
+ }
291
+ })
292
+ }
293
+
294
+ const body = encodeURIComponent(`
295
+ ## Bug Description
296
+ ${description}
297
+
298
+ ## Environment Info
299
+ - Platform: ${env.platform}
300
+ - Terminal: ${env.terminal}
301
+ - Version: ${MACRO.VERSION || 'unknown'}
302
+
303
+ ${modelInfo}`)
304
+ return `${GITHUB_ISSUES_REPO_URL}/new?title=${encodeURIComponent(title)}&body=${body}&labels=user-reported,bug`
305
+ }
306
+
307
+ async function generateTitle(description: string): Promise<string> {
308
+ const response = await queryQuick({
309
+ systemPrompt: [
310
+ 'Generate a concise issue title (max 80 chars) that captures the key point of this feedback. Do not include quotes or prefixes like "Feedback:" or "Issue:". If you cannot generate a title, just use "User Feedback".',
311
+ ],
312
+ userPrompt: description,
313
+ })
314
+ const title =
315
+ response.message.content[0]?.type === 'text'
316
+ ? response.message.content[0].text
317
+ : 'Bug Report'
318
+ if (title.startsWith(API_ERROR_MESSAGE_PREFIX)) {
319
+ return `Bug Report: ${description.slice(0, 60)}${description.length > 60 ? '...' : ''}`
320
+ }
321
+ return title
322
+ }
323
+
324
+ async function submitFeedback(
325
+ data: FeedbackData,
326
+ ): Promise<{ success: boolean; feedbackId?: string }> {
327
+ return { success: true, feedbackId: '123' }
328
+ // try {
329
+ // const apiKey = getAnthropicApiKey()
330
+ // if (!apiKey) {
331
+ // return { success: false }
332
+ // }
333
+
334
+ // const response = await fetch(
335
+ // 'https://api.anthropic.com/api/claude_cli_feedback',
336
+ // {
337
+ // method: 'POST',
338
+ // headers: {
339
+ // 'Content-Type': 'application/json',
340
+ // 'User-Agent': USER_AGENT,
341
+ // 'x-api-key': apiKey,
342
+ // },
343
+ // body: JSON.stringify({
344
+ // content: JSON.stringify(data),
345
+ // }),
346
+ // },
347
+ // )
348
+
349
+ // if (response.ok) {
350
+ // const result = await response.json()
351
+ // if (result?.feedback_id) {
352
+ // return { success: true, feedbackId: result.feedback_id }
353
+ // }
354
+ // logError('Failed to submit feedback: request did not return feedback_id')
355
+ // return { success: false }
356
+ // }
357
+
358
+ // logError('Failed to submit feedback:' + response.status)
359
+ // return { success: false }
360
+ // } catch (err) {
361
+ // logError(
362
+ // 'Error submitting feedback: ' +
363
+ // (err instanceof Error ? err.message : 'Unknown error'),
364
+ // )
365
+ // return { success: false }
366
+ // }
367
+ }