@shareai-lab/kode 1.1.14 → 1.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/cli.js +77 -82
  2. package/dist/entrypoints/cli.js +2 -1
  3. package/dist/entrypoints/cli.js.map +2 -2
  4. package/dist/index.js +5 -26
  5. package/dist/package.json +4 -1
  6. package/package.json +9 -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,313 +0,0 @@
1
- import { Box, Text } from 'ink'
2
- import * as React from 'react'
3
- import { z } from 'zod'
4
- import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage'
5
- import { TodoItem as TodoItemComponent } from '../../components/TodoItem'
6
- import { Tool, ValidationResult } from '../../Tool'
7
- import { setTodos, getTodos, TodoItem } from '../../utils/todoStorage'
8
- import { emitReminderEvent } from '../../services/systemReminder'
9
- import { startWatchingTodoFile } from '../../services/fileFreshness'
10
- import { DESCRIPTION, PROMPT } from './prompt'
11
- import { getTheme } from '../../utils/theme'
12
-
13
- const TodoItemSchema = z.object({
14
- content: z.string().min(1).describe('The task description or content'),
15
- status: z
16
- .enum(['pending', 'in_progress', 'completed'])
17
- .describe('Current status of the task'),
18
- priority: z
19
- .enum(['high', 'medium', 'low'])
20
- .describe('Priority level of the task'),
21
- id: z.string().min(1).describe('Unique identifier for the task'),
22
- })
23
-
24
- const inputSchema = z.strictObject({
25
- todos: z.array(TodoItemSchema).describe('The updated todo list'),
26
- })
27
-
28
- function validateTodos(todos: TodoItem[]): ValidationResult {
29
- // Check for duplicate IDs
30
- const ids = todos.map(todo => todo.id)
31
- const uniqueIds = new Set(ids)
32
- if (ids.length !== uniqueIds.size) {
33
- return {
34
- result: false,
35
- errorCode: 1,
36
- message: 'Duplicate todo IDs found',
37
- meta: {
38
- duplicateIds: ids.filter((id, index) => ids.indexOf(id) !== index),
39
- },
40
- }
41
- }
42
-
43
- // Check for multiple in_progress tasks
44
- const inProgressTasks = todos.filter(todo => todo.status === 'in_progress')
45
- if (inProgressTasks.length > 1) {
46
- return {
47
- result: false,
48
- errorCode: 2,
49
- message: 'Only one task can be in_progress at a time',
50
- meta: { inProgressTaskIds: inProgressTasks.map(t => t.id) },
51
- }
52
- }
53
-
54
- // Validate each todo
55
- for (const todo of todos) {
56
- if (!todo.content?.trim()) {
57
- return {
58
- result: false,
59
- errorCode: 3,
60
- message: `Todo with ID "${todo.id}" has empty content`,
61
- meta: { todoId: todo.id },
62
- }
63
- }
64
- if (!['pending', 'in_progress', 'completed'].includes(todo.status)) {
65
- return {
66
- result: false,
67
- errorCode: 4,
68
- message: `Invalid status "${todo.status}" for todo "${todo.id}"`,
69
- meta: { todoId: todo.id, invalidStatus: todo.status },
70
- }
71
- }
72
- if (!['high', 'medium', 'low'].includes(todo.priority)) {
73
- return {
74
- result: false,
75
- errorCode: 5,
76
- message: `Invalid priority "${todo.priority}" for todo "${todo.id}"`,
77
- meta: { todoId: todo.id, invalidPriority: todo.priority },
78
- }
79
- }
80
- }
81
-
82
- return { result: true }
83
- }
84
-
85
- function generateTodoSummary(todos: TodoItem[]): string {
86
- const stats = {
87
- total: todos.length,
88
- pending: todos.filter(t => t.status === 'pending').length,
89
- inProgress: todos.filter(t => t.status === 'in_progress').length,
90
- completed: todos.filter(t => t.status === 'completed').length,
91
- }
92
-
93
- // Enhanced summary with statistics
94
- let summary = `Updated ${stats.total} todo(s)`
95
- if (stats.total > 0) {
96
- summary += ` (${stats.pending} pending, ${stats.inProgress} in progress, ${stats.completed} completed)`
97
- }
98
- summary += '. Continue tracking your progress with the todo list.'
99
-
100
- return summary
101
- }
102
-
103
- export const TodoWriteTool = {
104
- name: 'TodoWrite',
105
- async description() {
106
- return DESCRIPTION
107
- },
108
- async prompt() {
109
- return PROMPT
110
- },
111
- inputSchema,
112
- userFacingName() {
113
- return 'Update Todos'
114
- },
115
- async isEnabled() {
116
- return true
117
- },
118
- isReadOnly() {
119
- return false
120
- },
121
- isConcurrencySafe() {
122
- return false // TodoWrite modifies state, not safe for concurrent execution
123
- },
124
- needsPermissions() {
125
- return false
126
- },
127
- renderResultForAssistant(result) {
128
- // Match official implementation - return static confirmation message
129
- return 'Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable'
130
- },
131
- renderToolUseMessage(input, { verbose }) {
132
- // Show a simple confirmation message when the tool is being used
133
- return '{ params.todo }'
134
- },
135
- renderToolUseRejectedMessage() {
136
- return <FallbackToolUseRejectedMessage />
137
- },
138
- renderToolResultMessage(output) {
139
- const isError = typeof output === 'string' && output.startsWith('Error')
140
-
141
- // For non-error output, get current todos from storage and render them
142
- if (!isError && typeof output === 'string') {
143
- const currentTodos = getTodos()
144
-
145
- if (currentTodos.length === 0) {
146
- return (
147
- <Box flexDirection="column" width="100%">
148
- <Box flexDirection="row">
149
- <Text color="#6B7280">&nbsp;&nbsp;⎿ &nbsp;</Text>
150
- <Text color="#9CA3AF">No todos currently</Text>
151
- </Box>
152
- </Box>
153
- )
154
- }
155
-
156
- // Sort: [completed, in_progress, pending]
157
- const sortedTodos = [...currentTodos].sort((a, b) => {
158
- const order = ['completed', 'in_progress', 'pending']
159
- return (
160
- order.indexOf(a.status) - order.indexOf(b.status) ||
161
- a.content.localeCompare(b.content)
162
- )
163
- })
164
-
165
- // Find the next pending task (first pending task after sorting)
166
- const nextPendingIndex = sortedTodos.findIndex(todo => todo.status === 'pending')
167
-
168
- return (
169
- <Box flexDirection="column" width="100%">
170
- {sortedTodos.map((todo: TodoItem, index: number) => {
171
- // Determine checkbox symbol and colors
172
- let checkbox: string
173
- let textColor: string
174
- let isBold = false
175
- let isStrikethrough = false
176
-
177
- if (todo.status === 'completed') {
178
- checkbox = '☒'
179
- textColor = '#6B7280' // Professional gray for completed
180
- isStrikethrough = true
181
- } else if (todo.status === 'in_progress') {
182
- checkbox = '☐'
183
- textColor = '#10B981' // Professional green for in progress
184
- isBold = true
185
- } else if (todo.status === 'pending') {
186
- checkbox = '☐'
187
- // Only the FIRST pending task gets purple highlight
188
- if (index === nextPendingIndex) {
189
- textColor = '#8B5CF6' // Professional purple for next pending
190
- isBold = true
191
- } else {
192
- textColor = '#9CA3AF' // Muted gray for other pending
193
- }
194
- }
195
-
196
- return (
197
- <Box key={todo.id || index} flexDirection="row" marginBottom={0}>
198
- <Text color="#6B7280">&nbsp;&nbsp;⎿ &nbsp;</Text>
199
- <Box flexDirection="row" flexGrow={1}>
200
- <Text color={textColor} bold={isBold} strikethrough={isStrikethrough}>
201
- {checkbox}
202
- </Text>
203
- <Text> </Text>
204
- <Text color={textColor} bold={isBold} strikethrough={isStrikethrough}>
205
- {todo.content}
206
- </Text>
207
- </Box>
208
- </Box>
209
- )
210
- })}
211
- </Box>
212
- )
213
- }
214
-
215
- // Fallback to simple text rendering for errors or string output
216
- return (
217
- <Box justifyContent="space-between" overflowX="hidden" width="100%">
218
- <Box flexDirection="row">
219
- <Text color={isError ? getTheme().error : getTheme().success}>
220
- &nbsp;&nbsp;⎿ &nbsp;
221
- {typeof output === 'string' ? output : JSON.stringify(output)}
222
- </Text>
223
- </Box>
224
- </Box>
225
- )
226
- },
227
- async validateInput({ todos }: z.infer<typeof inputSchema>) {
228
- // Type assertion to ensure todos match TodoItem[] interface
229
- const todoItems = todos as TodoItem[]
230
- const validation = validateTodos(todoItems)
231
- if (!validation.result) {
232
- return validation
233
- }
234
- return { result: true }
235
- },
236
- async *call({ todos }: z.infer<typeof inputSchema>, context) {
237
- try {
238
- // Get agent ID from context
239
- const agentId = context?.agentId
240
-
241
- // Start watching todo file for this agent if not already watching
242
- if (agentId) {
243
- startWatchingTodoFile(agentId)
244
- }
245
-
246
- // Store previous todos for comparison (agent-scoped)
247
- const previousTodos = getTodos(agentId)
248
-
249
- // Type assertion to ensure todos match TodoItem[] interface
250
- const todoItems = todos as TodoItem[]
251
-
252
- // Note: Validation already done in validateInput, no need for duplicate validation
253
- // This eliminates the double validation issue
254
-
255
- // Update the todos in storage (agent-scoped)
256
- setTodos(todoItems, agentId)
257
-
258
- // Emit todo change event for system reminders (optimized - only if todos actually changed)
259
- const hasChanged =
260
- JSON.stringify(previousTodos) !== JSON.stringify(todoItems)
261
- if (hasChanged) {
262
- emitReminderEvent('todo:changed', {
263
- previousTodos,
264
- newTodos: todoItems,
265
- timestamp: Date.now(),
266
- agentId: agentId || 'default',
267
- changeType:
268
- todoItems.length > previousTodos.length
269
- ? 'added'
270
- : todoItems.length < previousTodos.length
271
- ? 'removed'
272
- : 'modified',
273
- })
274
- }
275
-
276
- // Generate enhanced summary
277
- const summary = generateTodoSummary(todoItems)
278
-
279
- // Enhanced result data for rendering
280
- const resultData = {
281
- oldTodos: previousTodos,
282
- newTodos: todoItems,
283
- summary,
284
- }
285
-
286
- yield {
287
- type: 'result',
288
- data: summary, // Return string to satisfy interface
289
- resultForAssistant: summary,
290
- // Store todo data in a way accessible to the renderer
291
- // We'll modify the renderToolResultMessage to get todos from storage
292
- }
293
- } catch (error) {
294
- const errorMessage =
295
- error instanceof Error ? error.message : 'Unknown error occurred'
296
- const errorResult = `Error updating todos: ${errorMessage}`
297
-
298
- // Emit error event for system monitoring
299
- emitReminderEvent('todo:error', {
300
- error: errorMessage,
301
- timestamp: Date.now(),
302
- agentId: context?.agentId || 'default',
303
- context: 'TodoWriteTool.call',
304
- })
305
-
306
- yield {
307
- type: 'result',
308
- data: errorResult,
309
- resultForAssistant: errorResult,
310
- }
311
- }
312
- },
313
- } satisfies Tool<typeof inputSchema, string>
@@ -1,63 +0,0 @@
1
- export const DESCRIPTION =
2
- 'Creates and manages todo items for task tracking and progress management in the current session.'
3
-
4
- export const PROMPT = `Use this tool to create and manage todo items for tracking tasks and progress. This tool provides comprehensive todo management:
5
-
6
- ## When to Use This Tool
7
-
8
- Use this tool proactively in these scenarios:
9
-
10
- 1. **Complex multi-step tasks** - When a task requires 3 or more distinct steps or actions
11
- 2. **Non-trivial and complex tasks** - Tasks that require careful planning or multiple operations
12
- 3. **User explicitly requests todo list** - When the user directly asks you to use the todo list
13
- 4. **User provides multiple tasks** - When users provide a list of things to be done (numbered or comma-separated)
14
- 5. **After receiving new instructions** - Immediately capture user requirements as todos
15
- 6. **When you start working on a task** - Mark it as in_progress BEFORE beginning work. Ideally you should only have one todo as in_progress at a time
16
- 7. **After completing a task** - Mark it as completed and add any new follow-up tasks discovered during implementation
17
-
18
- ## When NOT to Use This Tool
19
-
20
- Skip using this tool when:
21
- 1. There is only a single, straightforward task
22
- 2. The task is trivial and tracking it provides no organizational benefit
23
- 3. The task can be completed in less than 3 trivial steps
24
- 4. The task is purely conversational or informational
25
-
26
- ## Task States and Management
27
-
28
- 1. **Task States**: Use these states to track progress:
29
- - pending: Task not yet started
30
- - in_progress: Currently working on (limit to ONE task at a time)
31
- - completed: Task finished successfully
32
-
33
- 2. **Task Management**:
34
- - Update task status in real-time as you work
35
- - Mark tasks complete IMMEDIATELY after finishing (don't batch completions)
36
- - Only have ONE task in_progress at any time
37
- - Complete current tasks before starting new ones
38
- - Remove tasks that are no longer relevant from the list entirely
39
-
40
- 3. **Task Completion Requirements**:
41
- - ONLY mark a task as completed when you have FULLY accomplished it
42
- - If you encounter errors, blockers, or cannot finish, keep the task as in_progress
43
- - When blocked, create a new task describing what needs to be resolved
44
- - Never mark a task as completed if:
45
- - Tests are failing
46
- - Implementation is partial
47
- - You encountered unresolved errors
48
- - You couldn't find necessary files or dependencies
49
-
50
- 4. **Task Breakdown**:
51
- - Create specific, actionable items
52
- - Break complex tasks into smaller, manageable steps
53
- - Use clear, descriptive task names
54
-
55
- ## Tool Capabilities
56
-
57
- - **Create new todos**: Add tasks with content, priority, and status
58
- - **Update existing todos**: Modify any aspect of a todo (status, priority, content)
59
- - **Delete todos**: Remove completed or irrelevant tasks
60
- - **Batch operations**: Update multiple todos in a single operation
61
- - **Clear all todos**: Reset the entire todo list
62
-
63
- When in doubt, use this tool. Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully.`
@@ -1,178 +0,0 @@
1
- import { Box, Text } from 'ink'
2
- import React from 'react'
3
- import { z } from 'zod'
4
- import fetch from 'node-fetch'
5
- import { Cost } from '../../components/Cost'
6
- import { FallbackToolUseRejectedMessage } from '../../components/FallbackToolUseRejectedMessage'
7
- import { Tool, ToolUseContext } from '../../Tool'
8
- import { DESCRIPTION, TOOL_NAME_FOR_PROMPT } from './prompt'
9
- import { convertHtmlToMarkdown } from './htmlToMarkdown'
10
- import { urlCache } from './cache'
11
- import { queryQuick } from '../../services/claude'
12
-
13
- const inputSchema = z.strictObject({
14
- url: z.string().url().describe('The URL to fetch content from'),
15
- prompt: z.string().describe('The prompt to run on the fetched content'),
16
- })
17
-
18
- type Input = z.infer<typeof inputSchema>
19
- type Output = {
20
- url: string
21
- fromCache: boolean
22
- aiAnalysis: string
23
- }
24
-
25
- function normalizeUrl(url: string): string {
26
- // Auto-upgrade HTTP to HTTPS
27
- if (url.startsWith('http://')) {
28
- return url.replace('http://', 'https://')
29
- }
30
- return url
31
- }
32
-
33
- export const URLFetcherTool = {
34
- name: TOOL_NAME_FOR_PROMPT,
35
- async description() {
36
- return DESCRIPTION
37
- },
38
- userFacingName: () => 'URL Fetcher',
39
- inputSchema,
40
- isReadOnly: () => true,
41
- isConcurrencySafe: () => true,
42
- async isEnabled() {
43
- return true
44
- },
45
- needsPermissions() {
46
- return false
47
- },
48
- async prompt() {
49
- return DESCRIPTION
50
- },
51
- renderToolUseMessage({ url, prompt }: Input) {
52
- return `Fetching content from ${url} and analyzing with prompt: "${prompt}"`
53
- },
54
- renderToolUseRejectedMessage() {
55
- return <FallbackToolUseRejectedMessage />
56
- },
57
- renderToolResultMessage(output: Output) {
58
- const statusText = output.fromCache ? 'from cache' : 'fetched'
59
-
60
- return (
61
- <Box justifyContent="space-between" width="100%">
62
- <Box flexDirection="row">
63
- <Text>&nbsp;&nbsp;⎿ &nbsp;Content </Text>
64
- <Text bold>{statusText} </Text>
65
- <Text>and analyzed</Text>
66
- </Box>
67
- <Cost costUSD={0} durationMs={0} debug={false} />
68
- </Box>
69
- )
70
- },
71
- renderResultForAssistant(output: Output) {
72
- if (!output.aiAnalysis.trim()) {
73
- return `No content could be analyzed from URL: ${output.url}`
74
- }
75
-
76
- return output.aiAnalysis
77
- },
78
- async *call({ url, prompt }: Input, {}: ToolUseContext) {
79
- const normalizedUrl = normalizeUrl(url)
80
-
81
- try {
82
- let content: string
83
- let fromCache = false
84
-
85
- // Check cache first
86
- const cachedContent = urlCache.get(normalizedUrl)
87
- if (cachedContent) {
88
- content = cachedContent
89
- fromCache = true
90
- } else {
91
- // Fetch from URL with AbortController for timeout
92
- const abortController = new AbortController()
93
- const timeout = setTimeout(() => abortController.abort(), 30000)
94
-
95
- const response = await fetch(normalizedUrl, {
96
- method: 'GET',
97
- headers: {
98
- 'User-Agent': 'Mozilla/5.0 (compatible; URLFetcher/1.0)',
99
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
100
- 'Accept-Language': 'en-US,en;q=0.5',
101
- 'Accept-Encoding': 'gzip, deflate',
102
- 'Connection': 'keep-alive',
103
- 'Upgrade-Insecure-Requests': '1',
104
- },
105
- signal: abortController.signal,
106
- redirect: 'follow',
107
- })
108
-
109
- clearTimeout(timeout)
110
-
111
- if (!response.ok) {
112
- throw new Error(`HTTP ${response.status}: ${response.statusText}`)
113
- }
114
-
115
- const contentType = response.headers.get('content-type') || ''
116
- if (!contentType.includes('text/') && !contentType.includes('application/')) {
117
- throw new Error(`Unsupported content type: ${contentType}`)
118
- }
119
-
120
- const html = await response.text()
121
- content = convertHtmlToMarkdown(html)
122
-
123
- // Cache the result
124
- urlCache.set(normalizedUrl, content)
125
- fromCache = false
126
- }
127
-
128
- // Truncate content if too large (keep within reasonable token limits)
129
- const maxContentLength = 50000 // ~15k tokens approximately
130
- const truncatedContent = content.length > maxContentLength
131
- ? content.substring(0, maxContentLength) + '\n\n[Content truncated due to length]'
132
- : content
133
-
134
- // AI Analysis - always performed fresh, even with cached content
135
- const systemPrompt = [
136
- 'You are analyzing web content based on a user\'s specific request.',
137
- 'The content has been extracted from a webpage and converted to markdown.',
138
- 'Provide a focused response that directly addresses the user\'s prompt.',
139
- ]
140
-
141
- const userPrompt = `Here is the content from ${normalizedUrl}:
142
-
143
- ${truncatedContent}
144
-
145
- User request: ${prompt}`
146
-
147
- const aiResponse = await queryQuick({
148
- systemPrompt,
149
- userPrompt,
150
- enablePromptCaching: false,
151
- })
152
-
153
- const output: Output = {
154
- url: normalizedUrl,
155
- fromCache,
156
- aiAnalysis: aiResponse.message.content[0]?.text || 'Unable to analyze content',
157
- }
158
-
159
- yield {
160
- type: 'result' as const,
161
- resultForAssistant: this.renderResultForAssistant(output),
162
- data: output,
163
- }
164
- } catch (error: any) {
165
- const output: Output = {
166
- url: normalizedUrl,
167
- fromCache: false,
168
- aiAnalysis: '',
169
- }
170
-
171
- yield {
172
- type: 'result' as const,
173
- resultForAssistant: `Error processing URL ${normalizedUrl}: ${error.message}`,
174
- data: output,
175
- }
176
- }
177
- },
178
- } satisfies Tool<typeof inputSchema, Output>
@@ -1,55 +0,0 @@
1
- interface CacheEntry {
2
- content: string
3
- timestamp: number
4
- }
5
-
6
- class URLCache {
7
- private cache = new Map<string, CacheEntry>()
8
- private readonly CACHE_DURATION = 15 * 60 * 1000 // 15 minutes in milliseconds
9
-
10
- set(url: string, content: string): void {
11
- this.cache.set(url, {
12
- content,
13
- timestamp: Date.now()
14
- })
15
- }
16
-
17
- get(url: string): string | null {
18
- const entry = this.cache.get(url)
19
- if (!entry) {
20
- return null
21
- }
22
-
23
- // Check if entry has expired
24
- if (Date.now() - entry.timestamp > this.CACHE_DURATION) {
25
- this.cache.delete(url)
26
- return null
27
- }
28
-
29
- return entry.content
30
- }
31
-
32
- clear(): void {
33
- this.cache.clear()
34
- }
35
-
36
- // Clean expired entries
37
- private cleanExpired(): void {
38
- const now = Date.now()
39
- for (const [url, entry] of this.cache.entries()) {
40
- if (now - entry.timestamp > this.CACHE_DURATION) {
41
- this.cache.delete(url)
42
- }
43
- }
44
- }
45
-
46
- // Auto-clean expired entries every 5 minutes
47
- constructor() {
48
- setInterval(() => {
49
- this.cleanExpired()
50
- }, 5 * 60 * 1000) // 5 minutes
51
- }
52
- }
53
-
54
- // Export singleton instance
55
- export const urlCache = new URLCache()
@@ -1,55 +0,0 @@
1
- import TurndownService from 'turndown'
2
-
3
- const turndownService = new TurndownService({
4
- headingStyle: 'atx',
5
- hr: '---',
6
- bulletListMarker: '-',
7
- codeBlockStyle: 'fenced',
8
- fence: '```',
9
- emDelimiter: '_',
10
- strongDelimiter: '**'
11
- })
12
-
13
- // Configure rules to handle common HTML elements
14
- turndownService.addRule('removeScripts', {
15
- filter: ['script', 'style', 'noscript'],
16
- replacement: () => ''
17
- })
18
-
19
- turndownService.addRule('removeComments', {
20
- filter: (node) => node.nodeType === 8, // Comment nodes
21
- replacement: () => ''
22
- })
23
-
24
- turndownService.addRule('cleanLinks', {
25
- filter: 'a',
26
- replacement: (content, node) => {
27
- const href = node.getAttribute('href')
28
- if (!href || href.startsWith('javascript:') || href.startsWith('#')) {
29
- return content
30
- }
31
- return `[${content}](${href})`
32
- }
33
- })
34
-
35
- export function convertHtmlToMarkdown(html: string): string {
36
- try {
37
- // Clean up the HTML before conversion
38
- const cleanHtml = html
39
- .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '') // Remove script tags
40
- .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '') // Remove style tags
41
- .replace(/<!--[\s\S]*?-->/g, '') // Remove HTML comments
42
- .replace(/\s+/g, ' ') // Normalize whitespace
43
- .trim()
44
-
45
- const markdown = turndownService.turndown(cleanHtml)
46
-
47
- // Clean up the resulting markdown
48
- return markdown
49
- .replace(/\n{3,}/g, '\n\n') // Remove excessive line breaks
50
- .replace(/^\s+|\s+$/gm, '') // Remove leading/trailing spaces on each line
51
- .trim()
52
- } catch (error) {
53
- throw new Error(`Failed to convert HTML to markdown: ${error instanceof Error ? error.message : String(error)}`)
54
- }
55
- }
@@ -1,17 +0,0 @@
1
- export const TOOL_NAME_FOR_PROMPT = 'URLFetcher'
2
- export const DESCRIPTION = `- Fetches content from a specified URL and processes it using an AI model
3
- - Takes a URL and a prompt as input
4
- - Fetches the URL content, converts HTML to markdown
5
- - Processes the content with the prompt using a small, fast model
6
- - Returns the model's response about the content
7
- - Use this tool when you need to retrieve and analyze web content
8
-
9
- Usage notes:
10
- - IMPORTANT: If an MCP-provided web fetch tool is available, prefer using that tool instead of this one, as it may have fewer restrictions. All MCP-provided tools start with "mcp__".
11
- - The URL must be a fully-formed valid URL (e.g., https://example.com)
12
- - HTTP URLs will be automatically upgraded to HTTPS
13
- - The prompt should describe what information you want to extract from the page
14
- - This tool is read-only and does not modify any files
15
- - Results may be summarized if the content is very large
16
- - Includes a self-cleaning 15-minute cache for faster responses when repeatedly accessing the same URL
17
- - When a URL redirects, the tool will inform you and provide the redirect URL in a special format. You should then make a new URLFetcher request with the redirect URL to fetch the content.`