@shareai-lab/kode 1.0.70 → 1.0.73
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 +342 -75
- package/README.zh-CN.md +292 -0
- package/cli.js +62 -0
- package/package.json +49 -25
- package/scripts/postinstall.js +56 -0
- package/src/ProjectOnboarding.tsx +198 -0
- package/src/Tool.ts +82 -0
- package/src/commands/agents.tsx +3401 -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 +31 -0
- package/src/commands/review.ts +49 -0
- package/src/commands/terminalSetup.ts +221 -0
- package/src/commands.ts +139 -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 +293 -0
- package/src/components/ConsoleOAuthFlow.tsx +327 -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 +78 -0
- package/src/components/CustomSelect/select.tsx +152 -0
- package/src/components/CustomSelect/theme.ts +45 -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 +221 -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 +227 -0
- package/src/components/ModelSelector.tsx +3386 -0
- package/src/components/ModelStatusDisplay.tsx +230 -0
- package/src/components/Onboarding.tsx +274 -0
- package/src/components/PressEnterToContinue.tsx +11 -0
- package/src/components/PromptInput.tsx +740 -0
- package/src/components/SentryErrorBoundary.ts +33 -0
- package/src/components/Spinner.tsx +129 -0
- package/src/components/StickerRequestForm.tsx +16 -0
- package/src/components/StructuredDiff.tsx +191 -0
- package/src/components/TextInput.tsx +259 -0
- package/src/components/TodoItem.tsx +11 -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 +49 -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 +133 -0
- package/src/components/messages/TaskProgressMessage.tsx +32 -0
- package/src/components/messages/TaskToolMessage.tsx +58 -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 +153 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditPermissionRequest.tsx +182 -0
- package/src/components/permissions/FileEditPermissionRequest/FileEditToolDiff.tsx +77 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWritePermissionRequest.tsx +164 -0
- package/src/components/permissions/FileWritePermissionRequest/FileWriteToolDiff.tsx +83 -0
- package/src/components/permissions/FilesystemPermissionRequest/FilesystemPermissionRequest.tsx +240 -0
- package/src/components/permissions/PermissionRequest.tsx +101 -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 +8 -0
- package/src/constants/modelCapabilities.ts +179 -0
- package/src/constants/models.ts +1025 -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 +1518 -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/useTerminalSize.ts +49 -0
- package/src/hooks/useTextInput.ts +318 -0
- package/src/hooks/useUnifiedCompletion.ts +1404 -0
- package/src/messages.ts +38 -0
- package/src/permissions.ts +268 -0
- package/src/query.ts +707 -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 +798 -0
- package/src/screens/ResumeConversation.tsx +68 -0
- package/src/services/adapters/base.ts +38 -0
- package/src/services/adapters/chatCompletions.ts +90 -0
- package/src/services/adapters/responsesAPI.ts +170 -0
- package/src/services/browserMocks.ts +66 -0
- package/src/services/claude.ts +2083 -0
- package/src/services/customCommands.ts +704 -0
- package/src/services/fileFreshness.ts +377 -0
- package/src/services/gpt5ConnectionTest.ts +340 -0
- package/src/services/mcpClient.ts +564 -0
- package/src/services/mcpServerApproval.tsx +50 -0
- package/src/services/mentionProcessor.ts +273 -0
- package/src/services/modelAdapterFactory.ts +69 -0
- package/src/services/notifier.ts +40 -0
- package/src/services/oauth.ts +357 -0
- package/src/services/openai.ts +1305 -0
- package/src/services/responseStateManager.ts +90 -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 +507 -0
- package/src/services/vcr.ts +161 -0
- package/src/test/testAdapters.ts +96 -0
- package/src/tools/ArchitectTool/ArchitectTool.tsx +122 -0
- package/src/tools/ArchitectTool/prompt.ts +15 -0
- package/src/tools/AskExpertModelTool/AskExpertModelTool.tsx +569 -0
- package/src/tools/BashTool/BashTool.tsx +243 -0
- package/src/tools/BashTool/BashToolResultMessage.tsx +38 -0
- package/src/tools/BashTool/OutputLine.tsx +49 -0
- package/src/tools/BashTool/prompt.ts +174 -0
- package/src/tools/BashTool/utils.ts +56 -0
- package/src/tools/FileEditTool/FileEditTool.tsx +315 -0
- package/src/tools/FileEditTool/prompt.ts +51 -0
- package/src/tools/FileEditTool/utils.ts +58 -0
- package/src/tools/FileReadTool/FileReadTool.tsx +404 -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 +107 -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 +258 -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 +466 -0
- package/src/tools/TaskTool/constants.ts +1 -0
- package/src/tools/TaskTool/prompt.ts +92 -0
- package/src/tools/ThinkTool/ThinkTool.tsx +54 -0
- package/src/tools/ThinkTool/prompt.ts +12 -0
- package/src/tools/TodoWriteTool/TodoWriteTool.tsx +290 -0
- package/src/tools/TodoWriteTool/prompt.ts +63 -0
- package/src/tools/lsTool/lsTool.tsx +272 -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/types/conversation.ts +51 -0
- package/src/types/logs.ts +58 -0
- package/src/types/modelCapabilities.ts +64 -0
- package/src/types/notebook.ts +87 -0
- package/src/utils/Cursor.ts +436 -0
- package/src/utils/PersistentShell.ts +373 -0
- package/src/utils/advancedFuzzyMatcher.ts +290 -0
- package/src/utils/agentLoader.ts +284 -0
- package/src/utils/agentStorage.ts +97 -0
- package/src/utils/array.ts +3 -0
- package/src/utils/ask.tsx +99 -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/commonUnixCommands.ts +161 -0
- package/src/utils/config.ts +942 -0
- package/src/utils/conversationRecovery.ts +55 -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 +109 -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/fuzzyMatcher.ts +328 -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 +939 -0
- package/src/utils/model.ts +836 -0
- package/src/utils/permissions/filesystem.ts +118 -0
- package/src/utils/responseState.ts +23 -0
- package/src/utils/ripgrep.ts +167 -0
- package/src/utils/secureFile.ts +559 -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 +50 -0
- package/src/utils/theme.ts +133 -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,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent configuration loader
|
|
3
|
+
* Loads agent configurations from markdown files with YAML frontmatter
|
|
4
|
+
* Following Claude Code's agent system architecture
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { existsSync, readFileSync, readdirSync, statSync, watch, FSWatcher } from 'fs'
|
|
8
|
+
import { join, resolve } from 'path'
|
|
9
|
+
import { homedir } from 'os'
|
|
10
|
+
import matter from 'gray-matter'
|
|
11
|
+
import { getCwd } from './state'
|
|
12
|
+
import { memoize } from 'lodash-es'
|
|
13
|
+
|
|
14
|
+
// Track warned agents to avoid spam
|
|
15
|
+
const warnedAgents = new Set<string>()
|
|
16
|
+
|
|
17
|
+
export interface AgentConfig {
|
|
18
|
+
agentType: string // Agent identifier (matches subagent_type)
|
|
19
|
+
whenToUse: string // Description of when to use this agent
|
|
20
|
+
tools: string[] | '*' // Tool permissions
|
|
21
|
+
systemPrompt: string // System prompt content
|
|
22
|
+
location: 'built-in' | 'user' | 'project'
|
|
23
|
+
color?: string // Optional UI color
|
|
24
|
+
model_name?: string // Optional model override
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Built-in general-purpose agent as fallback
|
|
28
|
+
const BUILTIN_GENERAL_PURPOSE: AgentConfig = {
|
|
29
|
+
agentType: 'general-purpose',
|
|
30
|
+
whenToUse: 'General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks',
|
|
31
|
+
tools: '*',
|
|
32
|
+
systemPrompt: `You are a general-purpose agent. Given the user's task, use the tools available to complete it efficiently and thoroughly.
|
|
33
|
+
|
|
34
|
+
When to use your capabilities:
|
|
35
|
+
- Searching for code, configurations, and patterns across large codebases
|
|
36
|
+
- Analyzing multiple files to understand system architecture
|
|
37
|
+
- Investigating complex questions that require exploring many files
|
|
38
|
+
- Performing multi-step research tasks
|
|
39
|
+
|
|
40
|
+
Guidelines:
|
|
41
|
+
- For file searches: Use Grep or Glob when you need to search broadly. Use FileRead when you know the specific file path.
|
|
42
|
+
- For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.
|
|
43
|
+
- Be thorough: Check multiple locations, consider different naming conventions, look for related files.
|
|
44
|
+
- Complete tasks directly using your capabilities.`,
|
|
45
|
+
location: 'built-in'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse tools field from frontmatter
|
|
50
|
+
*/
|
|
51
|
+
function parseTools(tools: any): string[] | '*' {
|
|
52
|
+
if (!tools) return '*'
|
|
53
|
+
if (tools === '*') return '*'
|
|
54
|
+
if (Array.isArray(tools)) {
|
|
55
|
+
// Ensure all items are strings and filter out non-strings
|
|
56
|
+
const filteredTools = tools.filter((t): t is string => typeof t === 'string')
|
|
57
|
+
return filteredTools.length > 0 ? filteredTools : '*'
|
|
58
|
+
}
|
|
59
|
+
if (typeof tools === 'string') {
|
|
60
|
+
return [tools]
|
|
61
|
+
}
|
|
62
|
+
return '*'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Scan a directory for agent configuration files
|
|
67
|
+
*/
|
|
68
|
+
async function scanAgentDirectory(dirPath: string, location: 'user' | 'project'): Promise<AgentConfig[]> {
|
|
69
|
+
if (!existsSync(dirPath)) {
|
|
70
|
+
return []
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const agents: AgentConfig[] = []
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const files = readdirSync(dirPath)
|
|
77
|
+
|
|
78
|
+
for (const file of files) {
|
|
79
|
+
if (!file.endsWith('.md')) continue
|
|
80
|
+
|
|
81
|
+
const filePath = join(dirPath, file)
|
|
82
|
+
const stat = statSync(filePath)
|
|
83
|
+
|
|
84
|
+
if (!stat.isFile()) continue
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const content = readFileSync(filePath, 'utf-8')
|
|
88
|
+
const { data: frontmatter, content: body } = matter(content)
|
|
89
|
+
|
|
90
|
+
// Validate required fields
|
|
91
|
+
if (!frontmatter.name || !frontmatter.description) {
|
|
92
|
+
console.warn(`Skipping ${filePath}: missing required fields (name, description)`)
|
|
93
|
+
continue
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Silently ignore deprecated 'model' field - no warnings by default
|
|
97
|
+
// Only warn if KODE_DEBUG_AGENTS environment variable is set
|
|
98
|
+
if (frontmatter.model && !frontmatter.model_name && !warnedAgents.has(frontmatter.name) && process.env.KODE_DEBUG_AGENTS) {
|
|
99
|
+
console.warn(`⚠️ Agent ${frontmatter.name}: 'model' field is deprecated and ignored. Use 'model_name' instead, or omit to use default 'task' model.`)
|
|
100
|
+
warnedAgents.add(frontmatter.name)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Build agent config
|
|
104
|
+
const agent: AgentConfig = {
|
|
105
|
+
agentType: frontmatter.name,
|
|
106
|
+
whenToUse: frontmatter.description.replace(/\\n/g, '\n'),
|
|
107
|
+
tools: parseTools(frontmatter.tools),
|
|
108
|
+
systemPrompt: body.trim(),
|
|
109
|
+
location,
|
|
110
|
+
...(frontmatter.color && { color: frontmatter.color }),
|
|
111
|
+
// Only use model_name field, ignore deprecated 'model' field
|
|
112
|
+
...(frontmatter.model_name && { model_name: frontmatter.model_name })
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
agents.push(agent)
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.warn(`Failed to parse agent file ${filePath}:`, error)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.warn(`Failed to scan directory ${dirPath}:`, error)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return agents
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Load all agent configurations
|
|
129
|
+
*/
|
|
130
|
+
async function loadAllAgents(): Promise<{
|
|
131
|
+
activeAgents: AgentConfig[]
|
|
132
|
+
allAgents: AgentConfig[]
|
|
133
|
+
}> {
|
|
134
|
+
try {
|
|
135
|
+
// Scan both .claude and .kode directories in parallel
|
|
136
|
+
// Claude Code compatibility: support both ~/.claude/agents and ~/.kode/agents
|
|
137
|
+
const userClaudeDir = join(homedir(), '.claude', 'agents')
|
|
138
|
+
const userKodeDir = join(homedir(), '.kode', 'agents')
|
|
139
|
+
const projectClaudeDir = join(getCwd(), '.claude', 'agents')
|
|
140
|
+
const projectKodeDir = join(getCwd(), '.kode', 'agents')
|
|
141
|
+
|
|
142
|
+
const [userClaudeAgents, userKodeAgents, projectClaudeAgents, projectKodeAgents] = await Promise.all([
|
|
143
|
+
scanAgentDirectory(userClaudeDir, 'user'),
|
|
144
|
+
scanAgentDirectory(userKodeDir, 'user'),
|
|
145
|
+
scanAgentDirectory(projectClaudeDir, 'project'),
|
|
146
|
+
scanAgentDirectory(projectKodeDir, 'project')
|
|
147
|
+
])
|
|
148
|
+
|
|
149
|
+
// Built-in agents (currently just general-purpose)
|
|
150
|
+
const builtinAgents = [BUILTIN_GENERAL_PURPOSE]
|
|
151
|
+
|
|
152
|
+
// Apply priority override: built-in < .claude (user) < .kode (user) < .claude (project) < .kode (project)
|
|
153
|
+
const agentMap = new Map<string, AgentConfig>()
|
|
154
|
+
|
|
155
|
+
// Add in priority order (later entries override earlier ones)
|
|
156
|
+
for (const agent of builtinAgents) {
|
|
157
|
+
agentMap.set(agent.agentType, agent)
|
|
158
|
+
}
|
|
159
|
+
for (const agent of userClaudeAgents) {
|
|
160
|
+
agentMap.set(agent.agentType, agent)
|
|
161
|
+
}
|
|
162
|
+
for (const agent of userKodeAgents) {
|
|
163
|
+
agentMap.set(agent.agentType, agent)
|
|
164
|
+
}
|
|
165
|
+
for (const agent of projectClaudeAgents) {
|
|
166
|
+
agentMap.set(agent.agentType, agent)
|
|
167
|
+
}
|
|
168
|
+
for (const agent of projectKodeAgents) {
|
|
169
|
+
agentMap.set(agent.agentType, agent)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const activeAgents = Array.from(agentMap.values())
|
|
173
|
+
const allAgents = [...builtinAgents, ...userClaudeAgents, ...userKodeAgents, ...projectClaudeAgents, ...projectKodeAgents]
|
|
174
|
+
|
|
175
|
+
return { activeAgents, allAgents }
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('Failed to load agents, falling back to built-in:', error)
|
|
178
|
+
return {
|
|
179
|
+
activeAgents: [BUILTIN_GENERAL_PURPOSE],
|
|
180
|
+
allAgents: [BUILTIN_GENERAL_PURPOSE]
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Memoized version for performance
|
|
186
|
+
export const getActiveAgents = memoize(
|
|
187
|
+
async (): Promise<AgentConfig[]> => {
|
|
188
|
+
const { activeAgents } = await loadAllAgents()
|
|
189
|
+
return activeAgents
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
// Get all agents (both active and overridden)
|
|
194
|
+
export const getAllAgents = memoize(
|
|
195
|
+
async (): Promise<AgentConfig[]> => {
|
|
196
|
+
const { allAgents } = await loadAllAgents()
|
|
197
|
+
return allAgents
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
// Clear cache when needed
|
|
202
|
+
export function clearAgentCache() {
|
|
203
|
+
getActiveAgents.cache?.clear?.()
|
|
204
|
+
getAllAgents.cache?.clear?.()
|
|
205
|
+
getAgentByType.cache?.clear?.()
|
|
206
|
+
getAvailableAgentTypes.cache?.clear?.()
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Get a specific agent by type
|
|
210
|
+
export const getAgentByType = memoize(
|
|
211
|
+
async (agentType: string): Promise<AgentConfig | undefined> => {
|
|
212
|
+
const agents = await getActiveAgents()
|
|
213
|
+
return agents.find(agent => agent.agentType === agentType)
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
// Get all available agent types for validation
|
|
218
|
+
export const getAvailableAgentTypes = memoize(
|
|
219
|
+
async (): Promise<string[]> => {
|
|
220
|
+
const agents = await getActiveAgents()
|
|
221
|
+
return agents.map(agent => agent.agentType)
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
// File watcher for hot reload
|
|
226
|
+
let watchers: FSWatcher[] = []
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Start watching agent configuration directories for changes
|
|
230
|
+
*/
|
|
231
|
+
export async function startAgentWatcher(onChange?: () => void): Promise<void> {
|
|
232
|
+
await stopAgentWatcher() // Clean up any existing watchers
|
|
233
|
+
|
|
234
|
+
// Watch both .claude and .kode directories
|
|
235
|
+
const userClaudeDir = join(homedir(), '.claude', 'agents')
|
|
236
|
+
const userKodeDir = join(homedir(), '.kode', 'agents')
|
|
237
|
+
const projectClaudeDir = join(getCwd(), '.claude', 'agents')
|
|
238
|
+
const projectKodeDir = join(getCwd(), '.kode', 'agents')
|
|
239
|
+
|
|
240
|
+
const watchDirectory = (dirPath: string, label: string) => {
|
|
241
|
+
if (existsSync(dirPath)) {
|
|
242
|
+
const watcher = watch(dirPath, { recursive: false }, async (eventType, filename) => {
|
|
243
|
+
if (filename && filename.endsWith('.md')) {
|
|
244
|
+
console.log(`🔄 Agent configuration changed in ${label}: ${filename}`)
|
|
245
|
+
clearAgentCache()
|
|
246
|
+
// Also clear any other related caches
|
|
247
|
+
getAllAgents.cache?.clear?.()
|
|
248
|
+
onChange?.()
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
watchers.push(watcher)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Watch all directories
|
|
256
|
+
watchDirectory(userClaudeDir, 'user/.claude')
|
|
257
|
+
watchDirectory(userKodeDir, 'user/.kode')
|
|
258
|
+
watchDirectory(projectClaudeDir, 'project/.claude')
|
|
259
|
+
watchDirectory(projectKodeDir, 'project/.kode')
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Stop watching agent configuration directories
|
|
264
|
+
*/
|
|
265
|
+
export async function stopAgentWatcher(): Promise<void> {
|
|
266
|
+
const closePromises = watchers.map(watcher =>
|
|
267
|
+
new Promise<void>((resolve) => {
|
|
268
|
+
try {
|
|
269
|
+
watcher.close((err) => {
|
|
270
|
+
if (err) {
|
|
271
|
+
console.error('Failed to close file watcher:', err)
|
|
272
|
+
}
|
|
273
|
+
resolve()
|
|
274
|
+
})
|
|
275
|
+
} catch (error) {
|
|
276
|
+
console.error('Error closing watcher:', error)
|
|
277
|
+
resolve()
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
await Promise.allSettled(closePromises)
|
|
283
|
+
watchers = []
|
|
284
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import { homedir } from 'os'
|
|
4
|
+
import { randomUUID } from 'crypto'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Agent Storage Utilities
|
|
8
|
+
* Provides file-based state isolation for different agents
|
|
9
|
+
* Based on Kode's Agent ID architecture
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get the kode config directory
|
|
14
|
+
*/
|
|
15
|
+
function getConfigDirectory(): string {
|
|
16
|
+
return process.env.KODE_CONFIG_DIR ?? process.env.ANYKODE_CONFIG_DIR ?? join(homedir(), '.kode')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Get the current session ID
|
|
21
|
+
*/
|
|
22
|
+
function getSessionId(): string {
|
|
23
|
+
// This should be set when the session starts
|
|
24
|
+
return process.env.ANYKODE_SESSION_ID ?? 'default-session'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Generate agent-specific file path
|
|
29
|
+
* Pattern: ${sessionId}-agent-${agentId}.json
|
|
30
|
+
* Stored in ~/.kode/ directory
|
|
31
|
+
*/
|
|
32
|
+
export function getAgentFilePath(agentId: string): string {
|
|
33
|
+
const sessionId = getSessionId()
|
|
34
|
+
const filename = `${sessionId}-agent-${agentId}.json`
|
|
35
|
+
const configDir = getConfigDirectory()
|
|
36
|
+
|
|
37
|
+
// Ensure kode config directory exists
|
|
38
|
+
if (!existsSync(configDir)) {
|
|
39
|
+
mkdirSync(configDir, { recursive: true })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return join(configDir, filename)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Read agent-specific data from storage
|
|
47
|
+
*/
|
|
48
|
+
export function readAgentData<T = any>(agentId: string): T | null {
|
|
49
|
+
const filePath = getAgentFilePath(agentId)
|
|
50
|
+
|
|
51
|
+
if (!existsSync(filePath)) {
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const content = readFileSync(filePath, 'utf-8')
|
|
57
|
+
return JSON.parse(content) as T
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(`Failed to read agent data for ${agentId}:`, error)
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Write agent-specific data to storage
|
|
66
|
+
*/
|
|
67
|
+
export function writeAgentData<T = any>(agentId: string, data: T): void {
|
|
68
|
+
const filePath = getAgentFilePath(agentId)
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8')
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(`Failed to write agent data for ${agentId}:`, error)
|
|
74
|
+
throw error
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get default agent ID if none is provided
|
|
80
|
+
*/
|
|
81
|
+
export function getDefaultAgentId(): string {
|
|
82
|
+
return 'default'
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Resolve agent ID from context
|
|
87
|
+
*/
|
|
88
|
+
export function resolveAgentId(agentId?: string): string {
|
|
89
|
+
return agentId || getDefaultAgentId()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Generate a new unique Agent ID
|
|
94
|
+
*/
|
|
95
|
+
export function generateAgentId(): string {
|
|
96
|
+
return randomUUID()
|
|
97
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { last } from 'lodash-es'
|
|
2
|
+
import { Command } from '../commands'
|
|
3
|
+
import { getSystemPrompt } from '../constants/prompts'
|
|
4
|
+
import { getContext } from '../context'
|
|
5
|
+
import { getTotalCost } from '../cost-tracker'
|
|
6
|
+
import { Message, query } from '../query'
|
|
7
|
+
import { CanUseToolFn } from '../hooks/useCanUseTool'
|
|
8
|
+
import { Tool } from '../Tool'
|
|
9
|
+
import { getModelManager } from '../utils/model'
|
|
10
|
+
import { setCwd } from './state'
|
|
11
|
+
import { getMessagesPath, overwriteLog } from './log'
|
|
12
|
+
import { createUserMessage } from './messages'
|
|
13
|
+
|
|
14
|
+
type Props = {
|
|
15
|
+
commands: Command[]
|
|
16
|
+
safeMode?: boolean
|
|
17
|
+
hasPermissionsToUseTool: CanUseToolFn
|
|
18
|
+
messageLogName: string
|
|
19
|
+
prompt: string
|
|
20
|
+
cwd: string
|
|
21
|
+
tools: Tool[]
|
|
22
|
+
verbose?: boolean
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Sends a single prompt to the Claude API and returns the response.
|
|
26
|
+
// Assumes that claude is being used non-interactively -- will not
|
|
27
|
+
// ask the user for permissions or further input.
|
|
28
|
+
export async function ask({
|
|
29
|
+
commands,
|
|
30
|
+
safeMode,
|
|
31
|
+
hasPermissionsToUseTool,
|
|
32
|
+
messageLogName,
|
|
33
|
+
prompt,
|
|
34
|
+
cwd,
|
|
35
|
+
tools,
|
|
36
|
+
verbose = false,
|
|
37
|
+
}: Props): Promise<{
|
|
38
|
+
resultText: string
|
|
39
|
+
totalCost: number
|
|
40
|
+
messageHistoryFile: string
|
|
41
|
+
}> {
|
|
42
|
+
await setCwd(cwd)
|
|
43
|
+
const message = createUserMessage(prompt)
|
|
44
|
+
const messages: Message[] = [message]
|
|
45
|
+
|
|
46
|
+
const [systemPrompt, context, model] = await Promise.all([
|
|
47
|
+
getSystemPrompt(),
|
|
48
|
+
getContext(),
|
|
49
|
+
getModelManager().getModelName('main'),
|
|
50
|
+
])
|
|
51
|
+
|
|
52
|
+
for await (const m of query(
|
|
53
|
+
messages,
|
|
54
|
+
systemPrompt,
|
|
55
|
+
context,
|
|
56
|
+
hasPermissionsToUseTool,
|
|
57
|
+
{
|
|
58
|
+
options: {
|
|
59
|
+
commands,
|
|
60
|
+
tools,
|
|
61
|
+
verbose,
|
|
62
|
+
safeMode,
|
|
63
|
+
forkNumber: 0,
|
|
64
|
+
messageLogName: 'unused',
|
|
65
|
+
maxThinkingTokens: 0,
|
|
66
|
+
},
|
|
67
|
+
abortController: new AbortController(),
|
|
68
|
+
messageId: undefined,
|
|
69
|
+
readFileTimestamps: {},
|
|
70
|
+
setToolJSX: () => {}, // No-op function for non-interactive use
|
|
71
|
+
},
|
|
72
|
+
)) {
|
|
73
|
+
messages.push(m)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const result = last(messages)
|
|
77
|
+
if (!result || result.type !== 'assistant') {
|
|
78
|
+
throw new Error('Expected content to be an assistant message')
|
|
79
|
+
}
|
|
80
|
+
if (result.message.content[0]?.type !== 'text') {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Expected first content item to be text, but got ${JSON.stringify(
|
|
83
|
+
result.message.content[0],
|
|
84
|
+
null,
|
|
85
|
+
2,
|
|
86
|
+
)}`,
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Write log that can be retrieved with `claude log`
|
|
91
|
+
const messageHistoryFile = getMessagesPath(messageLogName, 0, 0)
|
|
92
|
+
overwriteLog(messageHistoryFile, messages)
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
resultText: result.message.content[0].text,
|
|
96
|
+
totalCost: getTotalCost(),
|
|
97
|
+
messageHistoryFile,
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { USE_BEDROCK, USE_VERTEX } from './model'
|
|
2
|
+
import { getGlobalConfig } from './config'
|
|
3
|
+
|
|
4
|
+
export function isAnthropicAuthEnabled(): boolean {
|
|
5
|
+
return false
|
|
6
|
+
// return !(USE_BEDROCK || USE_VERTEX)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function isLoggedInToAnthropic(): boolean {
|
|
10
|
+
return false
|
|
11
|
+
// const config = getGlobalConfig()
|
|
12
|
+
// return !!config.primaryApiKey
|
|
13
|
+
}
|