@shareai-lab/kode 1.0.70 → 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.
- package/README.md +202 -76
- package/README.zh-CN.md +246 -0
- package/cli.js +62 -0
- package/package.json +45 -25
- package/scripts/postinstall.js +56 -0
- package/src/ProjectOnboarding.tsx +180 -0
- package/src/Tool.ts +53 -0
- package/src/commands/approvedTools.ts +53 -0
- package/src/commands/bug.tsx +20 -0
- package/src/commands/clear.ts +43 -0
- package/src/commands/compact.ts +120 -0
- package/src/commands/config.tsx +19 -0
- package/src/commands/cost.ts +18 -0
- package/src/commands/ctx_viz.ts +209 -0
- package/src/commands/doctor.ts +24 -0
- package/src/commands/help.tsx +19 -0
- package/src/commands/init.ts +37 -0
- package/src/commands/listen.ts +42 -0
- package/src/commands/login.tsx +51 -0
- package/src/commands/logout.tsx +40 -0
- package/src/commands/mcp.ts +41 -0
- package/src/commands/model.tsx +40 -0
- package/src/commands/modelstatus.tsx +20 -0
- package/src/commands/onboarding.tsx +34 -0
- package/src/commands/pr_comments.ts +59 -0
- package/src/commands/refreshCommands.ts +54 -0
- package/src/commands/release-notes.ts +34 -0
- package/src/commands/resume.tsx +30 -0
- package/src/commands/review.ts +49 -0
- package/src/commands/terminalSetup.ts +221 -0
- package/src/commands.ts +136 -0
- package/src/components/ApproveApiKey.tsx +93 -0
- package/src/components/AsciiLogo.tsx +13 -0
- package/src/components/AutoUpdater.tsx +148 -0
- package/src/components/Bug.tsx +367 -0
- package/src/components/Config.tsx +289 -0
- package/src/components/ConsoleOAuthFlow.tsx +326 -0
- package/src/components/Cost.tsx +23 -0
- package/src/components/CostThresholdDialog.tsx +46 -0
- package/src/components/CustomSelect/option-map.ts +42 -0
- package/src/components/CustomSelect/select-option.tsx +52 -0
- package/src/components/CustomSelect/select.tsx +143 -0
- package/src/components/CustomSelect/use-select-state.ts +414 -0
- package/src/components/CustomSelect/use-select.ts +35 -0
- package/src/components/FallbackToolUseRejectedMessage.tsx +15 -0
- package/src/components/FileEditToolUpdatedMessage.tsx +66 -0
- package/src/components/Help.tsx +215 -0
- package/src/components/HighlightedCode.tsx +33 -0
- package/src/components/InvalidConfigDialog.tsx +113 -0
- package/src/components/Link.tsx +32 -0
- package/src/components/LogSelector.tsx +86 -0
- package/src/components/Logo.tsx +145 -0
- package/src/components/MCPServerApprovalDialog.tsx +100 -0
- package/src/components/MCPServerDialogCopy.tsx +25 -0
- package/src/components/MCPServerMultiselectDialog.tsx +109 -0
- package/src/components/Message.tsx +219 -0
- package/src/components/MessageResponse.tsx +15 -0
- package/src/components/MessageSelector.tsx +211 -0
- package/src/components/ModeIndicator.tsx +88 -0
- package/src/components/ModelConfig.tsx +301 -0
- package/src/components/ModelListManager.tsx +223 -0
- package/src/components/ModelSelector.tsx +3208 -0
- package/src/components/ModelStatusDisplay.tsx +228 -0
- package/src/components/Onboarding.tsx +274 -0
- package/src/components/PressEnterToContinue.tsx +11 -0
- package/src/components/PromptInput.tsx +710 -0
- package/src/components/SentryErrorBoundary.ts +33 -0
- package/src/components/Spinner.tsx +129 -0
- package/src/components/StructuredDiff.tsx +184 -0
- package/src/components/TextInput.tsx +246 -0
- package/src/components/TokenWarning.tsx +31 -0
- package/src/components/ToolUseLoader.tsx +40 -0
- package/src/components/TrustDialog.tsx +106 -0
- package/src/components/binary-feedback/BinaryFeedback.tsx +63 -0
- package/src/components/binary-feedback/BinaryFeedbackOption.tsx +111 -0
- package/src/components/binary-feedback/BinaryFeedbackView.tsx +172 -0
- package/src/components/binary-feedback/utils.ts +220 -0
- package/src/components/messages/AssistantBashOutputMessage.tsx +22 -0
- package/src/components/messages/AssistantLocalCommandOutputMessage.tsx +45 -0
- package/src/components/messages/AssistantRedactedThinkingMessage.tsx +19 -0
- package/src/components/messages/AssistantTextMessage.tsx +144 -0
- package/src/components/messages/AssistantThinkingMessage.tsx +40 -0
- package/src/components/messages/AssistantToolUseMessage.tsx +123 -0
- package/src/components/messages/UserBashInputMessage.tsx +28 -0
- package/src/components/messages/UserCommandMessage.tsx +30 -0
- package/src/components/messages/UserKodingInputMessage.tsx +28 -0
- package/src/components/messages/UserPromptMessage.tsx +35 -0
- package/src/components/messages/UserTextMessage.tsx +39 -0
- package/src/components/messages/UserToolResultMessage/UserToolCanceledMessage.tsx +12 -0
- package/src/components/messages/UserToolResultMessage/UserToolErrorMessage.tsx +36 -0
- package/src/components/messages/UserToolResultMessage/UserToolRejectMessage.tsx +31 -0
- package/src/components/messages/UserToolResultMessage/UserToolResultMessage.tsx +57 -0
- package/src/components/messages/UserToolResultMessage/UserToolSuccessMessage.tsx +35 -0
- package/src/components/messages/UserToolResultMessage/utils.tsx +56 -0
- package/src/components/permissions/BashPermissionRequest/BashPermissionRequest.tsx +121 -0
- package/src/components/permissions/FallbackPermissionRequest.tsx +155 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +182 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +75 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +164 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +81 -0
- package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +242 -0
- package/src/components/permissions/PermissionRequest.tsx +103 -0
- package/src/components/permissions/PermissionRequestTitle.tsx +69 -0
- package/src/components/permissions/hooks.ts +44 -0
- package/src/components/permissions/toolUseOptions.ts +59 -0
- package/src/components/permissions/utils.ts +23 -0
- package/src/constants/betas.ts +5 -0
- package/src/constants/claude-asterisk-ascii-art.tsx +238 -0
- package/src/constants/figures.ts +4 -0
- package/src/constants/keys.ts +3 -0
- package/src/constants/macros.ts +6 -0
- package/src/constants/models.ts +935 -0
- package/src/constants/oauth.ts +18 -0
- package/src/constants/product.ts +17 -0
- package/src/constants/prompts.ts +177 -0
- package/src/constants/releaseNotes.ts +7 -0
- package/src/context/PermissionContext.tsx +149 -0
- package/src/context.ts +278 -0
- package/src/cost-tracker.ts +84 -0
- package/src/entrypoints/cli.tsx +1498 -0
- package/src/entrypoints/mcp.ts +176 -0
- package/src/history.ts +25 -0
- package/src/hooks/useApiKeyVerification.ts +59 -0
- package/src/hooks/useArrowKeyHistory.ts +55 -0
- package/src/hooks/useCanUseTool.ts +138 -0
- package/src/hooks/useCancelRequest.ts +39 -0
- package/src/hooks/useDoublePress.ts +42 -0
- package/src/hooks/useExitOnCtrlCD.ts +31 -0
- package/src/hooks/useInterval.ts +25 -0
- package/src/hooks/useLogMessages.ts +16 -0
- package/src/hooks/useLogStartupTime.ts +12 -0
- package/src/hooks/useNotifyAfterTimeout.ts +65 -0
- package/src/hooks/usePermissionRequestLogging.ts +44 -0
- package/src/hooks/useSlashCommandTypeahead.ts +137 -0
- package/src/hooks/useTerminalSize.ts +49 -0
- package/src/hooks/useTextInput.ts +315 -0
- package/src/messages.ts +37 -0
- package/src/permissions.ts +268 -0
- package/src/query.ts +704 -0
- package/src/screens/ConfigureNpmPrefix.tsx +197 -0
- package/src/screens/Doctor.tsx +219 -0
- package/src/screens/LogList.tsx +68 -0
- package/src/screens/REPL.tsx +792 -0
- package/src/screens/ResumeConversation.tsx +68 -0
- package/src/services/browserMocks.ts +66 -0
- package/src/services/claude.ts +1947 -0
- package/src/services/customCommands.ts +683 -0
- package/src/services/fileFreshness.ts +377 -0
- package/src/services/mcpClient.ts +564 -0
- package/src/services/mcpServerApproval.tsx +50 -0
- package/src/services/notifier.ts +40 -0
- package/src/services/oauth.ts +357 -0
- package/src/services/openai.ts +796 -0
- package/src/services/sentry.ts +3 -0
- package/src/services/statsig.ts +171 -0
- package/src/services/statsigStorage.ts +86 -0
- package/src/services/systemReminder.ts +406 -0
- package/src/services/vcr.ts +161 -0
- package/src/tools/ArchitectTool/ArchitectTool.tsx +122 -0
- package/src/tools/ArchitectTool/prompt.ts +15 -0
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +505 -0
- package/src/tools/BashTool/BashTool.tsx +270 -0
- package/src/tools/BashTool/BashToolResultMessage.tsx +38 -0
- package/src/tools/BashTool/OutputLine.tsx +48 -0
- package/src/tools/BashTool/prompt.ts +174 -0
- package/src/tools/BashTool/utils.ts +56 -0
- package/src/tools/FileEditTool/FileEditTool.tsx +316 -0
- package/src/tools/FileEditTool/prompt.ts +51 -0
- package/src/tools/FileEditTool/utils.ts +58 -0
- package/src/tools/FileReadTool/FileReadTool.tsx +371 -0
- package/src/tools/FileReadTool/prompt.ts +7 -0
- package/src/tools/FileWriteTool/FileWriteTool.tsx +297 -0
- package/src/tools/FileWriteTool/prompt.ts +10 -0
- package/src/tools/GlobTool/GlobTool.tsx +119 -0
- package/src/tools/GlobTool/prompt.ts +8 -0
- package/src/tools/GrepTool/GrepTool.tsx +147 -0
- package/src/tools/GrepTool/prompt.ts +11 -0
- package/src/tools/MCPTool/MCPTool.tsx +106 -0
- package/src/tools/MCPTool/prompt.ts +3 -0
- package/src/tools/MemoryReadTool/MemoryReadTool.tsx +127 -0
- package/src/tools/MemoryReadTool/prompt.ts +3 -0
- package/src/tools/MemoryWriteTool/MemoryWriteTool.tsx +89 -0
- package/src/tools/MemoryWriteTool/prompt.ts +3 -0
- package/src/tools/MultiEditTool/MultiEditTool.tsx +366 -0
- package/src/tools/MultiEditTool/prompt.ts +45 -0
- package/src/tools/NotebookEditTool/NotebookEditTool.tsx +298 -0
- package/src/tools/NotebookEditTool/prompt.ts +3 -0
- package/src/tools/NotebookReadTool/NotebookReadTool.tsx +266 -0
- package/src/tools/NotebookReadTool/prompt.ts +3 -0
- package/src/tools/StickerRequestTool/StickerRequestTool.tsx +93 -0
- package/src/tools/StickerRequestTool/prompt.ts +19 -0
- package/src/tools/TaskTool/TaskTool.tsx +382 -0
- package/src/tools/TaskTool/constants.ts +1 -0
- package/src/tools/TaskTool/prompt.ts +56 -0
- package/src/tools/ThinkTool/ThinkTool.tsx +56 -0
- package/src/tools/ThinkTool/prompt.ts +12 -0
- package/src/tools/TodoWriteTool/TodoWriteTool.tsx +289 -0
- package/src/tools/TodoWriteTool/prompt.ts +63 -0
- package/src/tools/lsTool/lsTool.tsx +269 -0
- package/src/tools/lsTool/prompt.ts +2 -0
- package/src/tools.ts +63 -0
- package/src/types/PermissionMode.ts +120 -0
- package/src/types/RequestContext.ts +72 -0
- package/src/utils/Cursor.ts +436 -0
- package/src/utils/PersistentShell.ts +373 -0
- package/src/utils/agentStorage.ts +97 -0
- package/src/utils/array.ts +3 -0
- package/src/utils/ask.tsx +98 -0
- package/src/utils/auth.ts +13 -0
- package/src/utils/autoCompactCore.ts +223 -0
- package/src/utils/autoUpdater.ts +318 -0
- package/src/utils/betas.ts +20 -0
- package/src/utils/browser.ts +14 -0
- package/src/utils/cleanup.ts +72 -0
- package/src/utils/commands.ts +261 -0
- package/src/utils/config.ts +771 -0
- package/src/utils/conversationRecovery.ts +54 -0
- package/src/utils/debugLogger.ts +1123 -0
- package/src/utils/diff.ts +42 -0
- package/src/utils/env.ts +57 -0
- package/src/utils/errors.ts +21 -0
- package/src/utils/exampleCommands.ts +108 -0
- package/src/utils/execFileNoThrow.ts +51 -0
- package/src/utils/expertChatStorage.ts +136 -0
- package/src/utils/file.ts +402 -0
- package/src/utils/fileRecoveryCore.ts +71 -0
- package/src/utils/format.tsx +44 -0
- package/src/utils/generators.ts +62 -0
- package/src/utils/git.ts +92 -0
- package/src/utils/globalLogger.ts +77 -0
- package/src/utils/http.ts +10 -0
- package/src/utils/imagePaste.ts +38 -0
- package/src/utils/json.ts +13 -0
- package/src/utils/log.ts +382 -0
- package/src/utils/markdown.ts +213 -0
- package/src/utils/messageContextManager.ts +289 -0
- package/src/utils/messages.tsx +938 -0
- package/src/utils/model.ts +836 -0
- package/src/utils/permissions/filesystem.ts +118 -0
- package/src/utils/ripgrep.ts +167 -0
- package/src/utils/sessionState.ts +49 -0
- package/src/utils/state.ts +25 -0
- package/src/utils/style.ts +29 -0
- package/src/utils/terminal.ts +49 -0
- package/src/utils/theme.ts +122 -0
- package/src/utils/thinking.ts +144 -0
- package/src/utils/todoStorage.ts +431 -0
- package/src/utils/tokens.ts +43 -0
- package/src/utils/toolExecutionController.ts +163 -0
- package/src/utils/unaryLogging.ts +26 -0
- package/src/utils/user.ts +37 -0
- package/src/utils/validate.ts +165 -0
- package/cli.mjs +0 -1803
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type { Command } from '../commands'
|
|
2
|
+
import type { Tool } from '../Tool'
|
|
3
|
+
import Table from 'cli-table3'
|
|
4
|
+
import { getSystemPrompt } from '../constants/prompts'
|
|
5
|
+
import { getContext } from '../context'
|
|
6
|
+
import { zodToJsonSchema } from 'zod-to-json-schema'
|
|
7
|
+
import { getMessagesGetter } from '../messages'
|
|
8
|
+
import { PROJECT_FILE } from '../constants/product'
|
|
9
|
+
// Quick and dirty estimate of bytes per token for rough token counts
|
|
10
|
+
const BYTES_PER_TOKEN = 4
|
|
11
|
+
|
|
12
|
+
interface Section {
|
|
13
|
+
title: string
|
|
14
|
+
content: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ToolSummary {
|
|
18
|
+
name: string
|
|
19
|
+
description: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getContextSections(text: string): Section[] {
|
|
23
|
+
const sections: Section[] = []
|
|
24
|
+
|
|
25
|
+
// Find first <context> tag
|
|
26
|
+
const firstContextIndex = text.indexOf('<context')
|
|
27
|
+
|
|
28
|
+
// Everything before first tag is Core Sysprompt
|
|
29
|
+
if (firstContextIndex > 0) {
|
|
30
|
+
const coreSysprompt = text.slice(0, firstContextIndex).trim()
|
|
31
|
+
if (coreSysprompt) {
|
|
32
|
+
sections.push({
|
|
33
|
+
title: 'Core Sysprompt',
|
|
34
|
+
content: coreSysprompt,
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let currentPos = firstContextIndex
|
|
40
|
+
let nonContextContent = ''
|
|
41
|
+
|
|
42
|
+
const regex = /<context\s+name="([^"]*)">([\s\S]*?)<\/context>/g
|
|
43
|
+
let match: RegExpExecArray | null
|
|
44
|
+
|
|
45
|
+
while ((match = regex.exec(text)) !== null) {
|
|
46
|
+
// Collect text between context tags
|
|
47
|
+
if (match.index > currentPos) {
|
|
48
|
+
nonContextContent += text.slice(currentPos, match.index)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const [, name = 'Unnamed Section', content = ''] = match
|
|
52
|
+
sections.push({
|
|
53
|
+
title: name === 'codeStyle' ? `CodeStyle + ${PROJECT_FILE}'s` : name,
|
|
54
|
+
content: content.trim(),
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
currentPos = match.index + match[0].length
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Collect remaining text after last tag
|
|
61
|
+
if (currentPos < text.length) {
|
|
62
|
+
nonContextContent += text.slice(currentPos)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Add non-contextualized content if present
|
|
66
|
+
const trimmedNonContext = nonContextContent.trim()
|
|
67
|
+
if (trimmedNonContext) {
|
|
68
|
+
sections.push({
|
|
69
|
+
title: 'Non-contextualized Content',
|
|
70
|
+
content: trimmedNonContext,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return sections
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function formatTokenCount(bytes: number): string {
|
|
78
|
+
const tokens = bytes / BYTES_PER_TOKEN
|
|
79
|
+
const k = tokens / 1000
|
|
80
|
+
return `${Math.round(k * 10) / 10}k`
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function formatByteCount(bytes: number): string {
|
|
84
|
+
const kb = bytes / 1024
|
|
85
|
+
return `${Math.round(kb * 10) / 10}kb`
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function createSummaryTable(
|
|
89
|
+
systemText: string,
|
|
90
|
+
systemSections: Section[],
|
|
91
|
+
tools: ToolSummary[],
|
|
92
|
+
messages: unknown,
|
|
93
|
+
): string {
|
|
94
|
+
const table = new Table({
|
|
95
|
+
head: ['Component', 'Tokens', 'Size', '% Used'],
|
|
96
|
+
style: { head: ['bold'] },
|
|
97
|
+
chars: {
|
|
98
|
+
mid: '─',
|
|
99
|
+
'left-mid': '├',
|
|
100
|
+
'mid-mid': '┼',
|
|
101
|
+
'right-mid': '┤',
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const messagesStr = JSON.stringify(messages)
|
|
106
|
+
const toolsStr = JSON.stringify(tools)
|
|
107
|
+
|
|
108
|
+
// Calculate total for percentages
|
|
109
|
+
const total = systemText.length + toolsStr.length + messagesStr.length
|
|
110
|
+
const getPercentage = (n: number) => `${Math.round((n / total) * 100)}%`
|
|
111
|
+
|
|
112
|
+
// System prompt and its sections
|
|
113
|
+
table.push([
|
|
114
|
+
'System prompt',
|
|
115
|
+
formatTokenCount(systemText.length),
|
|
116
|
+
formatByteCount(systemText.length),
|
|
117
|
+
getPercentage(systemText.length),
|
|
118
|
+
])
|
|
119
|
+
for (const section of systemSections) {
|
|
120
|
+
table.push([
|
|
121
|
+
` ${section.title}`,
|
|
122
|
+
formatTokenCount(section.content.length),
|
|
123
|
+
formatByteCount(section.content.length),
|
|
124
|
+
getPercentage(section.content.length),
|
|
125
|
+
])
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Tools
|
|
129
|
+
table.push([
|
|
130
|
+
'Tool definitions',
|
|
131
|
+
formatTokenCount(toolsStr.length),
|
|
132
|
+
formatByteCount(toolsStr.length),
|
|
133
|
+
getPercentage(toolsStr.length),
|
|
134
|
+
])
|
|
135
|
+
for (const tool of tools) {
|
|
136
|
+
table.push([
|
|
137
|
+
` ${tool.name}`,
|
|
138
|
+
formatTokenCount(tool.description.length),
|
|
139
|
+
formatByteCount(tool.description.length),
|
|
140
|
+
getPercentage(tool.description.length),
|
|
141
|
+
])
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Messages and total
|
|
145
|
+
table.push(
|
|
146
|
+
[
|
|
147
|
+
'Messages',
|
|
148
|
+
formatTokenCount(messagesStr.length),
|
|
149
|
+
formatByteCount(messagesStr.length),
|
|
150
|
+
getPercentage(messagesStr.length),
|
|
151
|
+
],
|
|
152
|
+
['Total', formatTokenCount(total), formatByteCount(total), '100%'],
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return table.toString()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const command: Command = {
|
|
159
|
+
name: 'ctx-viz',
|
|
160
|
+
description:
|
|
161
|
+
'Show token usage breakdown for the current conversation context',
|
|
162
|
+
isEnabled: true,
|
|
163
|
+
isHidden: false,
|
|
164
|
+
type: 'local',
|
|
165
|
+
|
|
166
|
+
userFacingName() {
|
|
167
|
+
return this.name
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
async call(_args: string, cmdContext: { options: { tools: Tool[] } }) {
|
|
171
|
+
// Get tools and system prompt with injected context
|
|
172
|
+
const [systemPromptRaw, sysContext] = await Promise.all([
|
|
173
|
+
getSystemPrompt(),
|
|
174
|
+
getContext(),
|
|
175
|
+
])
|
|
176
|
+
|
|
177
|
+
const rawTools = cmdContext.options.tools
|
|
178
|
+
|
|
179
|
+
// Full system prompt with context sections injected
|
|
180
|
+
let systemPrompt = systemPromptRaw.join('\n')
|
|
181
|
+
for (const [name, content] of Object.entries(sysContext)) {
|
|
182
|
+
systemPrompt += `\n<context name="${name}">${content}</context>`
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Get full tool definitions including prompts and schemas
|
|
186
|
+
const tools = rawTools.map(t => {
|
|
187
|
+
// Get full prompt and schema
|
|
188
|
+
const fullPrompt = t.prompt({ safeMode: false })
|
|
189
|
+
const schema = JSON.stringify(
|
|
190
|
+
'inputJSONSchema' in t && t.inputJSONSchema
|
|
191
|
+
? t.inputJSONSchema
|
|
192
|
+
: zodToJsonSchema(t.inputSchema),
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
name: t.name,
|
|
197
|
+
description: `${fullPrompt}\n\nSchema:\n${schema}`,
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// Get current messages from REPL
|
|
202
|
+
const messages = getMessagesGetter()()
|
|
203
|
+
|
|
204
|
+
const sections = getContextSections(systemPrompt)
|
|
205
|
+
return createSummaryTable(systemPrompt, sections, tools, messages)
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export default command
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import type { Command } from '../commands'
|
|
3
|
+
import { Doctor } from '../screens/Doctor'
|
|
4
|
+
import { PRODUCT_NAME } from '../constants/product'
|
|
5
|
+
|
|
6
|
+
const doctor: Command = {
|
|
7
|
+
name: 'doctor',
|
|
8
|
+
description: `Checks the health of your ${PRODUCT_NAME} installation`,
|
|
9
|
+
isEnabled: true,
|
|
10
|
+
isHidden: false,
|
|
11
|
+
userFacingName() {
|
|
12
|
+
return 'doctor'
|
|
13
|
+
},
|
|
14
|
+
type: 'local-jsx',
|
|
15
|
+
call(onDone) {
|
|
16
|
+
const element = React.createElement(Doctor, {
|
|
17
|
+
onDone,
|
|
18
|
+
doctorMode: true,
|
|
19
|
+
})
|
|
20
|
+
return Promise.resolve(element)
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default doctor
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
import { Help } from '../components/Help'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
const help = {
|
|
6
|
+
type: 'local-jsx',
|
|
7
|
+
name: 'help',
|
|
8
|
+
description: 'Show help and available commands',
|
|
9
|
+
isEnabled: true,
|
|
10
|
+
isHidden: false,
|
|
11
|
+
async call(onDone, { options: { commands } }) {
|
|
12
|
+
return <Help commands={commands} onClose={onDone} />
|
|
13
|
+
},
|
|
14
|
+
userFacingName() {
|
|
15
|
+
return 'help'
|
|
16
|
+
},
|
|
17
|
+
} satisfies Command
|
|
18
|
+
|
|
19
|
+
export default help
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Command } from '../commands'
|
|
2
|
+
import { markProjectOnboardingComplete } from '../ProjectOnboarding'
|
|
3
|
+
import { PROJECT_FILE } from '../constants/product'
|
|
4
|
+
const command = {
|
|
5
|
+
type: 'prompt',
|
|
6
|
+
name: 'init',
|
|
7
|
+
description: `Initialize a new ${PROJECT_FILE} file with codebase documentation`,
|
|
8
|
+
isEnabled: true,
|
|
9
|
+
isHidden: false,
|
|
10
|
+
progressMessage: 'analyzing your codebase',
|
|
11
|
+
userFacingName() {
|
|
12
|
+
return 'init'
|
|
13
|
+
},
|
|
14
|
+
async getPromptForCommand(_args: string) {
|
|
15
|
+
// Mark onboarding as complete when init command is run
|
|
16
|
+
markProjectOnboardingComplete()
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
role: 'user',
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: 'text',
|
|
23
|
+
text: `Please analyze this codebase and create a ${PROJECT_FILE} file containing:
|
|
24
|
+
1. Build/lint/test commands - especially for running a single test
|
|
25
|
+
2. Code style guidelines including imports, formatting, types, naming conventions, error handling, etc.
|
|
26
|
+
|
|
27
|
+
The file you create will be given to agentic coding agents (such as yourself) that operate in this repository. Make it about 20 lines long.
|
|
28
|
+
If there's already a ${PROJECT_FILE}, improve it.
|
|
29
|
+
If there are Cursor rules (in .cursor/rules/ or .cursorrules) or Copilot rules (in .github/copilot-instructions.md), make sure to include them.`,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
} satisfies Command
|
|
36
|
+
|
|
37
|
+
export default command
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
import { logError } from '../utils/log'
|
|
3
|
+
import { execFileNoThrow } from '../utils/execFileNoThrow'
|
|
4
|
+
|
|
5
|
+
const isEnabled =
|
|
6
|
+
process.platform === 'darwin' &&
|
|
7
|
+
['iTerm.app', 'Apple_Terminal'].includes(process.env.TERM_PROGRAM || '')
|
|
8
|
+
|
|
9
|
+
const listen: Command = {
|
|
10
|
+
type: 'local',
|
|
11
|
+
name: 'listen',
|
|
12
|
+
description: 'Activates speech recognition and transcribes speech to text',
|
|
13
|
+
isEnabled: isEnabled,
|
|
14
|
+
isHidden: isEnabled,
|
|
15
|
+
userFacingName() {
|
|
16
|
+
return 'listen'
|
|
17
|
+
},
|
|
18
|
+
async call(_, { abortController }) {
|
|
19
|
+
// Start dictation using AppleScript
|
|
20
|
+
const script = `tell application "System Events" to tell ¬
|
|
21
|
+
(the first process whose frontmost is true) to tell ¬
|
|
22
|
+
menu bar 1 to tell ¬
|
|
23
|
+
menu bar item "Edit" to tell ¬
|
|
24
|
+
menu "Edit" to tell ¬
|
|
25
|
+
menu item "Start Dictation" to ¬
|
|
26
|
+
if exists then click it`
|
|
27
|
+
|
|
28
|
+
const { stderr, code } = await execFileNoThrow(
|
|
29
|
+
'osascript',
|
|
30
|
+
['-e', script],
|
|
31
|
+
abortController.signal,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if (code !== 0) {
|
|
35
|
+
logError(`Failed to start dictation: ${stderr}`)
|
|
36
|
+
return 'Failed to start dictation'
|
|
37
|
+
}
|
|
38
|
+
return 'Dictation started. Press esc to stop.'
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default listen
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import type { Command } from '../commands'
|
|
3
|
+
import { ConsoleOAuthFlow } from '../components/ConsoleOAuthFlow'
|
|
4
|
+
import { clearTerminal } from '../utils/terminal'
|
|
5
|
+
import { isLoggedInToAnthropic } from '../utils/auth'
|
|
6
|
+
import { useExitOnCtrlCD } from '../hooks/useExitOnCtrlCD'
|
|
7
|
+
import { Box, Text } from 'ink'
|
|
8
|
+
import { clearConversation } from './clear'
|
|
9
|
+
|
|
10
|
+
export default () =>
|
|
11
|
+
({
|
|
12
|
+
type: 'local-jsx',
|
|
13
|
+
name: 'login',
|
|
14
|
+
description: isLoggedInToAnthropic()
|
|
15
|
+
? 'Switch Anthropic accounts'
|
|
16
|
+
: 'Sign in with your Anthropic account',
|
|
17
|
+
isEnabled: true,
|
|
18
|
+
isHidden: false,
|
|
19
|
+
async call(onDone, context) {
|
|
20
|
+
await clearTerminal()
|
|
21
|
+
return (
|
|
22
|
+
<Login
|
|
23
|
+
onDone={async () => {
|
|
24
|
+
clearConversation(context)
|
|
25
|
+
onDone()
|
|
26
|
+
}}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
},
|
|
30
|
+
userFacingName() {
|
|
31
|
+
return 'login'
|
|
32
|
+
},
|
|
33
|
+
}) satisfies Command
|
|
34
|
+
|
|
35
|
+
function Login(props: { onDone: () => void }) {
|
|
36
|
+
const exitState = useExitOnCtrlCD(props.onDone)
|
|
37
|
+
return (
|
|
38
|
+
<Box flexDirection="column">
|
|
39
|
+
<ConsoleOAuthFlow onDone={props.onDone} />
|
|
40
|
+
<Box marginLeft={3}>
|
|
41
|
+
<Text dimColor>
|
|
42
|
+
{exitState.pending ? (
|
|
43
|
+
<>Press {exitState.keyName} again to exit</>
|
|
44
|
+
) : (
|
|
45
|
+
''
|
|
46
|
+
)}
|
|
47
|
+
</Text>
|
|
48
|
+
</Box>
|
|
49
|
+
</Box>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import type { Command } from '../commands'
|
|
3
|
+
import { getGlobalConfig, saveGlobalConfig } from '../utils/config'
|
|
4
|
+
import { clearTerminal } from '../utils/terminal'
|
|
5
|
+
import { Text } from 'ink'
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
type: 'local-jsx',
|
|
9
|
+
name: 'logout',
|
|
10
|
+
description: 'Sign out from your Anthropic account',
|
|
11
|
+
isEnabled: true,
|
|
12
|
+
isHidden: false,
|
|
13
|
+
async call() {
|
|
14
|
+
await clearTerminal()
|
|
15
|
+
|
|
16
|
+
const config = getGlobalConfig()
|
|
17
|
+
|
|
18
|
+
config.oauthAccount = undefined
|
|
19
|
+
config.hasCompletedOnboarding = false
|
|
20
|
+
|
|
21
|
+
if (config.customApiKeyResponses?.approved) {
|
|
22
|
+
config.customApiKeyResponses.approved = []
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
saveGlobalConfig(config)
|
|
26
|
+
|
|
27
|
+
const message = (
|
|
28
|
+
<Text>Successfully logged out from your Anthropic account.</Text>
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
setTimeout(() => {
|
|
32
|
+
process.exit(0)
|
|
33
|
+
}, 200)
|
|
34
|
+
|
|
35
|
+
return message
|
|
36
|
+
},
|
|
37
|
+
userFacingName() {
|
|
38
|
+
return 'logout'
|
|
39
|
+
},
|
|
40
|
+
} satisfies Command
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Command } from '../commands'
|
|
2
|
+
import { listMCPServers, getClients } from '../services/mcpClient'
|
|
3
|
+
import { PRODUCT_COMMAND } from '../constants/product'
|
|
4
|
+
import chalk from 'chalk'
|
|
5
|
+
import { getTheme } from '../utils/theme'
|
|
6
|
+
|
|
7
|
+
const mcp = {
|
|
8
|
+
type: 'local',
|
|
9
|
+
name: 'mcp',
|
|
10
|
+
description: 'Show MCP server connection status',
|
|
11
|
+
isEnabled: true,
|
|
12
|
+
isHidden: false,
|
|
13
|
+
async call() {
|
|
14
|
+
const servers = listMCPServers()
|
|
15
|
+
const clients = await getClients()
|
|
16
|
+
const theme = getTheme()
|
|
17
|
+
|
|
18
|
+
if (Object.keys(servers).length === 0) {
|
|
19
|
+
return `⎿ No MCP servers configured. Run \`${PRODUCT_COMMAND} mcp\` to learn about how to configure MCP servers.`
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Sort servers by name and format status with colors
|
|
23
|
+
const serverStatusLines = clients
|
|
24
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
25
|
+
.map(client => {
|
|
26
|
+
const isConnected = client.type === 'connected'
|
|
27
|
+
const status = isConnected ? 'connected' : 'disconnected'
|
|
28
|
+
const coloredStatus = isConnected
|
|
29
|
+
? chalk.hex(theme.success)(status)
|
|
30
|
+
: chalk.hex(theme.error)(status)
|
|
31
|
+
return `⎿ • ${client.name}: ${coloredStatus}`
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
return ['⎿ MCP Server Status', ...serverStatusLines].join('\n')
|
|
35
|
+
},
|
|
36
|
+
userFacingName() {
|
|
37
|
+
return 'mcp'
|
|
38
|
+
},
|
|
39
|
+
} satisfies Command
|
|
40
|
+
|
|
41
|
+
export default mcp
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render } from 'ink'
|
|
3
|
+
import { ModelConfig } from '../components/ModelConfig'
|
|
4
|
+
import { enableConfigs } from '../utils/config'
|
|
5
|
+
import { triggerModelConfigChange } from '../messages'
|
|
6
|
+
|
|
7
|
+
export const help = 'Change your AI provider and model settings'
|
|
8
|
+
export const description = 'Change your AI provider and model settings'
|
|
9
|
+
export const isEnabled = true
|
|
10
|
+
export const isHidden = false
|
|
11
|
+
export const name = 'model'
|
|
12
|
+
export const type = 'local-jsx'
|
|
13
|
+
|
|
14
|
+
export function userFacingName(): string {
|
|
15
|
+
return name
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function call(
|
|
19
|
+
onDone: (result?: string) => void,
|
|
20
|
+
context: any,
|
|
21
|
+
): Promise<React.ReactNode> {
|
|
22
|
+
const { abortController } = context
|
|
23
|
+
enableConfigs()
|
|
24
|
+
abortController?.abort?.()
|
|
25
|
+
return (
|
|
26
|
+
<ModelConfig
|
|
27
|
+
onClose={() => {
|
|
28
|
+
// Force ModelManager reload to ensure UI sync - wait for completion before closing
|
|
29
|
+
import('../utils/model').then(({ reloadModelManager }) => {
|
|
30
|
+
reloadModelManager()
|
|
31
|
+
// 🔧 Critical fix: Trigger global UI refresh after model config changes
|
|
32
|
+
// This ensures PromptInput component detects ModelManager singleton state changes
|
|
33
|
+
triggerModelConfigChange()
|
|
34
|
+
// Only close after reload is complete to ensure UI synchronization
|
|
35
|
+
onDone()
|
|
36
|
+
})
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import type { Command } from '../commands'
|
|
3
|
+
import { ModelStatusDisplay } from '../components/ModelStatusDisplay'
|
|
4
|
+
|
|
5
|
+
const modelstatus: Command = {
|
|
6
|
+
name: 'modelstatus',
|
|
7
|
+
description: 'Display current model configuration and status',
|
|
8
|
+
aliases: ['ms', 'model-status'],
|
|
9
|
+
isEnabled: true,
|
|
10
|
+
isHidden: false,
|
|
11
|
+
userFacingName() {
|
|
12
|
+
return 'modelstatus'
|
|
13
|
+
},
|
|
14
|
+
type: 'local-jsx',
|
|
15
|
+
call(onDone) {
|
|
16
|
+
return Promise.resolve(<ModelStatusDisplay onClose={onDone} />)
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default modelstatus
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import type { Command } from '../commands'
|
|
3
|
+
import { Onboarding } from '../components/Onboarding'
|
|
4
|
+
import { clearTerminal } from '../utils/terminal'
|
|
5
|
+
import { getGlobalConfig, saveGlobalConfig } from '../utils/config'
|
|
6
|
+
import { clearConversation } from './clear'
|
|
7
|
+
|
|
8
|
+
export default {
|
|
9
|
+
type: 'local-jsx',
|
|
10
|
+
name: 'onboarding',
|
|
11
|
+
description: 'Run through the onboarding flow',
|
|
12
|
+
isEnabled: true,
|
|
13
|
+
isHidden: false,
|
|
14
|
+
async call(onDone, context) {
|
|
15
|
+
await clearTerminal()
|
|
16
|
+
const config = getGlobalConfig()
|
|
17
|
+
saveGlobalConfig({
|
|
18
|
+
...config,
|
|
19
|
+
theme: 'dark',
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Onboarding
|
|
24
|
+
onDone={async () => {
|
|
25
|
+
clearConversation(context)
|
|
26
|
+
onDone()
|
|
27
|
+
}}
|
|
28
|
+
/>
|
|
29
|
+
)
|
|
30
|
+
},
|
|
31
|
+
userFacingName() {
|
|
32
|
+
return 'onboarding'
|
|
33
|
+
},
|
|
34
|
+
} satisfies Command
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
type: 'prompt',
|
|
5
|
+
name: 'pr-comments',
|
|
6
|
+
description: 'Get comments from a GitHub pull request',
|
|
7
|
+
progressMessage: 'fetching PR comments',
|
|
8
|
+
isEnabled: true,
|
|
9
|
+
isHidden: false,
|
|
10
|
+
userFacingName() {
|
|
11
|
+
return 'pr-comments'
|
|
12
|
+
},
|
|
13
|
+
async getPromptForCommand(args: string) {
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
role: 'user',
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: 'text',
|
|
20
|
+
text: `You are an AI assistant integrated into a git-based version control system. Your task is to fetch and display comments from a GitHub pull request.
|
|
21
|
+
|
|
22
|
+
Follow these steps:
|
|
23
|
+
|
|
24
|
+
1. Use \`gh pr view --json number,headRepository\` to get the PR number and repository info
|
|
25
|
+
2. Use \`gh api /repos/{owner}/{repo}/issues/{number}/comments\` to get PR-level comments
|
|
26
|
+
3. Use \`gh api /repos/{owner}/{repo}/pulls/{number}/comments\` to get review comments. Pay particular attention to the following fields: \`body\`, \`diff_hunk\`, \`path\`, \`line\`, etc. If the comment references some code, consider fetching it using eg \`gh api /repos/{owner}/{repo}/contents/{path}?ref={branch} | jq .content -r | base64 -d\`
|
|
27
|
+
4. Parse and format all comments in a readable way
|
|
28
|
+
5. Return ONLY the formatted comments, with no additional text
|
|
29
|
+
|
|
30
|
+
Format the comments as:
|
|
31
|
+
|
|
32
|
+
## Comments
|
|
33
|
+
|
|
34
|
+
[For each comment thread:]
|
|
35
|
+
- @author file.ts#line:
|
|
36
|
+
\`\`\`diff
|
|
37
|
+
[diff_hunk from the API response]
|
|
38
|
+
\`\`\`
|
|
39
|
+
> quoted comment text
|
|
40
|
+
|
|
41
|
+
[any replies indented]
|
|
42
|
+
|
|
43
|
+
If there are no comments, return "No comments found."
|
|
44
|
+
|
|
45
|
+
Remember:
|
|
46
|
+
1. Only show the actual comments, no explanatory text
|
|
47
|
+
2. Include both PR-level and code review comments
|
|
48
|
+
3. Preserve the threading/nesting of comment replies
|
|
49
|
+
4. Show the file and line number context for code review comments
|
|
50
|
+
5. Use jq to parse the JSON responses from the GitHub API
|
|
51
|
+
|
|
52
|
+
${args ? 'Additional user input: ' + args : ''}
|
|
53
|
+
`,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
} satisfies Command
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Command } from '../commands'
|
|
2
|
+
import { reloadCustomCommands } from '../services/customCommands'
|
|
3
|
+
import { getCommands } from '../commands'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Refresh Commands - Reload custom commands from filesystem
|
|
7
|
+
*
|
|
8
|
+
* This command provides a runtime mechanism to refresh the custom commands
|
|
9
|
+
* cache without restarting the application. It's particularly useful during
|
|
10
|
+
* development or when users are actively creating/modifying custom commands.
|
|
11
|
+
*
|
|
12
|
+
* The command follows the standard local command pattern used throughout
|
|
13
|
+
* the project and provides detailed feedback about the refresh operation.
|
|
14
|
+
*/
|
|
15
|
+
const refreshCommands = {
|
|
16
|
+
type: 'local',
|
|
17
|
+
name: 'refresh-commands',
|
|
18
|
+
description: 'Reload custom commands from filesystem',
|
|
19
|
+
isEnabled: true,
|
|
20
|
+
isHidden: false,
|
|
21
|
+
async call(_, context) {
|
|
22
|
+
try {
|
|
23
|
+
// Clear custom commands cache to force filesystem rescan
|
|
24
|
+
reloadCustomCommands()
|
|
25
|
+
|
|
26
|
+
// Clear the main commands cache to ensure full reload
|
|
27
|
+
// This ensures that changes to custom commands are reflected in the main command list
|
|
28
|
+
getCommands.cache.clear?.()
|
|
29
|
+
|
|
30
|
+
// Reload commands to get updated count and validate the refresh
|
|
31
|
+
const commands = await getCommands()
|
|
32
|
+
const customCommands = commands.filter(
|
|
33
|
+
cmd => cmd.name.startsWith('project:') || cmd.name.startsWith('user:'),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
// Provide detailed feedback about the refresh operation
|
|
37
|
+
return `✅ Commands refreshed successfully!
|
|
38
|
+
|
|
39
|
+
Custom commands reloaded: ${customCommands.length}
|
|
40
|
+
- Project commands: ${customCommands.filter(cmd => cmd.name.startsWith('project:')).length}
|
|
41
|
+
- User commands: ${customCommands.filter(cmd => cmd.name.startsWith('user:')).length}
|
|
42
|
+
|
|
43
|
+
Use /help to see updated command list.`
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Failed to refresh commands:', error)
|
|
46
|
+
return '❌ Failed to refresh commands. Check console for details.'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
userFacingName() {
|
|
50
|
+
return 'refresh-commands'
|
|
51
|
+
},
|
|
52
|
+
} satisfies Command
|
|
53
|
+
|
|
54
|
+
export default refreshCommands
|