clean code
This commit is contained in:
parent
59dce97350
commit
61a8ce0d22
12
AGENTS.md
12
AGENTS.md
@ -1,6 +1,6 @@
|
|||||||
# AGENTS.md
|
# AGENTS.md
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
This file provides guidance to Kode automation agents (including those compatible with Claude Code's `.claude` ecosystem) when working with code in this repository.
|
||||||
|
|
||||||
## Development Commands
|
## Development Commands
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ SKIP_BUNDLED_CHECK=true npm publish
|
|||||||
## High-Level Architecture
|
## High-Level Architecture
|
||||||
|
|
||||||
### Core System Design
|
### Core System Design
|
||||||
Kode implements a **three-layer parallel architecture** inspired by Claude Code:
|
Kode implements a **three-layer parallel architecture** refined for fast iteration across terminal workflows while remaining compatible with the Claude Code agent ecosystem:
|
||||||
|
|
||||||
1. **User Interaction Layer** (`src/screens/REPL.tsx`)
|
1. **User Interaction Layer** (`src/screens/REPL.tsx`)
|
||||||
- Interactive terminal interface using Ink (React for CLI)
|
- Interactive terminal interface using Ink (React for CLI)
|
||||||
@ -74,9 +74,9 @@ Kode implements a **three-layer parallel architecture** inspired by Claude Code:
|
|||||||
### Agent System (`src/utils/agentLoader.ts`)
|
### Agent System (`src/utils/agentLoader.ts`)
|
||||||
**Dynamic Agent Configuration Loading** with 5-tier priority system:
|
**Dynamic Agent Configuration Loading** with 5-tier priority system:
|
||||||
1. Built-in (code-embedded)
|
1. Built-in (code-embedded)
|
||||||
2. `~/.claude/agents/` (Claude user)
|
2. `~/.claude/agents/` (Claude Code user directory compatibility)
|
||||||
3. `~/.kode/agents/` (Kode user)
|
3. `~/.kode/agents/` (Kode user)
|
||||||
4. `./.claude/agents/` (Claude project)
|
4. `./.claude/agents/` (Claude Code project directory compatibility)
|
||||||
5. `./.kode/agents/` (Kode project)
|
5. `./.kode/agents/` (Kode project)
|
||||||
|
|
||||||
Agents are defined as markdown files with YAML frontmatter:
|
Agents are defined as markdown files with YAML frontmatter:
|
||||||
@ -99,7 +99,7 @@ Each tool follows a consistent pattern in `src/tools/[ToolName]/`:
|
|||||||
- Permission-aware execution
|
- Permission-aware execution
|
||||||
|
|
||||||
### Service Layer
|
### Service Layer
|
||||||
- **Claude Service** (`src/services/claude.ts`): Primary AI model interface
|
- **Anthropic Service** (`src/services/claude.ts`): Claude API integration
|
||||||
- **OpenAI Service** (`src/services/openai.ts`): OpenAI-compatible models
|
- **OpenAI Service** (`src/services/openai.ts`): OpenAI-compatible models
|
||||||
- **Model Adapter Factory** (`src/services/modelAdapterFactory.ts`): Unified model interface
|
- **Model Adapter Factory** (`src/services/modelAdapterFactory.ts`): Unified model interface
|
||||||
- **MCP Client** (`src/services/mcpClient.ts`): Model Context Protocol for tool extensions
|
- **MCP Client** (`src/services/mcpClient.ts`): Model Context Protocol for tool extensions
|
||||||
@ -204,4 +204,4 @@ const description = typeof tool.description === 'function'
|
|||||||
1. Create `.md` file with proper YAML frontmatter
|
1. Create `.md` file with proper YAML frontmatter
|
||||||
2. Place in appropriate directory based on scope
|
2. Place in appropriate directory based on scope
|
||||||
3. Test with `/agents` command
|
3. Test with `/agents` command
|
||||||
4. Verify tool permissions work correctly
|
4. Verify tool permissions work correctly
|
||||||
|
|||||||
12
CLAUDE.md
12
CLAUDE.md
@ -1,6 +1,6 @@
|
|||||||
# CLAUDE.md
|
# CLAUDE.md
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
This file provides guidance to Kode automation agents (including those compatible with Claude Code's `.claude` ecosystem) when working with code in this repository.
|
||||||
|
|
||||||
## Development Commands
|
## Development Commands
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ SKIP_BUNDLED_CHECK=true npm publish
|
|||||||
## High-Level Architecture
|
## High-Level Architecture
|
||||||
|
|
||||||
### Core System Design
|
### Core System Design
|
||||||
Kode implements a **three-layer parallel architecture** inspired by Claude Code:
|
Kode implements a **three-layer parallel architecture** refined for fast iteration across terminal workflows while remaining compatible with the Claude Code agent ecosystem:
|
||||||
|
|
||||||
1. **User Interaction Layer** (`src/screens/REPL.tsx`)
|
1. **User Interaction Layer** (`src/screens/REPL.tsx`)
|
||||||
- Interactive terminal interface using Ink (React for CLI)
|
- Interactive terminal interface using Ink (React for CLI)
|
||||||
@ -74,9 +74,9 @@ Kode implements a **three-layer parallel architecture** inspired by Claude Code:
|
|||||||
### Agent System (`src/utils/agentLoader.ts`)
|
### Agent System (`src/utils/agentLoader.ts`)
|
||||||
**Dynamic Agent Configuration Loading** with 5-tier priority system:
|
**Dynamic Agent Configuration Loading** with 5-tier priority system:
|
||||||
1. Built-in (code-embedded)
|
1. Built-in (code-embedded)
|
||||||
2. `~/.claude/agents/` (Claude user)
|
2. `~/.claude/agents/` (Claude Code user directory compatibility)
|
||||||
3. `~/.kode/agents/` (Kode user)
|
3. `~/.kode/agents/` (Kode user)
|
||||||
4. `./.claude/agents/` (Claude project)
|
4. `./.claude/agents/` (Claude Code project directory compatibility)
|
||||||
5. `./.kode/agents/` (Kode project)
|
5. `./.kode/agents/` (Kode project)
|
||||||
|
|
||||||
Agents are defined as markdown files with YAML frontmatter:
|
Agents are defined as markdown files with YAML frontmatter:
|
||||||
@ -99,7 +99,7 @@ Each tool follows a consistent pattern in `src/tools/[ToolName]/`:
|
|||||||
- Permission-aware execution
|
- Permission-aware execution
|
||||||
|
|
||||||
### Service Layer
|
### Service Layer
|
||||||
- **Claude Service** (`src/services/claude.ts`): Primary AI model interface
|
- **Anthropic Service** (`src/services/claude.ts`): Claude API integration
|
||||||
- **OpenAI Service** (`src/services/openai.ts`): OpenAI-compatible models
|
- **OpenAI Service** (`src/services/openai.ts`): OpenAI-compatible models
|
||||||
- **Model Adapter Factory** (`src/services/modelAdapterFactory.ts`): Unified model interface
|
- **Model Adapter Factory** (`src/services/modelAdapterFactory.ts`): Unified model interface
|
||||||
- **MCP Client** (`src/services/mcpClient.ts`): Model Context Protocol for tool extensions
|
- **MCP Client** (`src/services/mcpClient.ts`): Model Context Protocol for tool extensions
|
||||||
@ -204,4 +204,4 @@ const description = typeof tool.description === 'function'
|
|||||||
1. Create `.md` file with proper YAML frontmatter
|
1. Create `.md` file with proper YAML frontmatter
|
||||||
2. Place in appropriate directory based on scope
|
2. Place in appropriate directory based on scope
|
||||||
3. Test with `/agents` command
|
3. Test with `/agents` command
|
||||||
4. Verify tool permissions work correctly
|
4. Verify tool permissions work correctly
|
||||||
|
|||||||
@ -30,17 +30,17 @@ This change reflects our belief that the future of software development is colla
|
|||||||
### Full Compatibility with Multiple Standards
|
### Full Compatibility with Multiple Standards
|
||||||
|
|
||||||
- ✅ **AGENTS.md** - Native support for the OpenAI-initiated standard format
|
- ✅ **AGENTS.md** - Native support for the OpenAI-initiated standard format
|
||||||
- ✅ **CLAUDE.md** - Full backward compatibility with Claude Code configurations
|
- ✅ **CLAUDE.md** - Full backward compatibility with Claude Code `.claude` configurations
|
||||||
- ✅ **Subagent System** - Advanced agent delegation and task orchestration
|
- ✅ **Subagent System** - Advanced agent delegation and task orchestration
|
||||||
- ✅ **Cross-platform** - Works with 20+ AI models and providers
|
- ✅ **Cross-platform** - Works with 20+ AI models and providers
|
||||||
|
|
||||||
Use `# Your documentation request` to generate and maintain your AGENTS.md file automatically, while maintaining full compatibility with existing Claude Code workflows.
|
Use `# Your documentation request` to generate and maintain your AGENTS.md file automatically, while preserving compatibility with existing `.claude` workflows.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Kode is a powerful AI assistant that lives in your terminal. It can understand your codebase, edit files, run commands, and handle entire workflows for you.
|
Kode is a powerful AI assistant that lives in your terminal. It can understand your codebase, edit files, run commands, and handle entire workflows for you.
|
||||||
|
|
||||||
> **⚠️ Security Notice**: Kode runs in YOLO mode by default (equivalent to Claude's `--dangerously-skip-permissions` flag), bypassing all permission checks for maximum productivity. YOLO mode is recommended only for trusted, secure environments when working on non-critical projects. If you're working with important files or using models of questionable capability, we strongly recommend using `kode --safe` to enable permission checks and manual approval for all operations.
|
> **⚠️ Security Notice**: Kode runs in YOLO mode by default (equivalent to Claude Code's `--dangerously-skip-permissions` flag), bypassing all permission checks for maximum productivity. YOLO mode is recommended only for trusted, secure environments when working on non-critical projects. If you're working with important files or using models of questionable capability, we strongly recommend using `kode --safe` to enable permission checks and manual approval for all operations.
|
||||||
>
|
>
|
||||||
> **📊 Model Performance**: For optimal performance, we recommend using newer, more capable models designed for autonomous task completion. Avoid older Q&A-focused models like GPT-4o or Gemini 2.5 Pro, which are optimized for answering questions rather than sustained independent task execution. Choose models specifically trained for agentic workflows and extended reasoning capabilities.
|
> **📊 Model Performance**: For optimal performance, we recommend using newer, more capable models designed for autonomous task completion. Avoid older Q&A-focused models like GPT-4o or Gemini 2.5 Pro, which are optimized for answering questions rather than sustained independent task execution. Choose models specifically trained for agentic workflows and extended reasoning capabilities.
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
Kode 是一个强大的 AI 助手,运行在你的终端中。它能理解你的代码库、编辑文件、运行命令,并为你处理整个开发工作流。
|
Kode 是一个强大的 AI 助手,运行在你的终端中。它能理解你的代码库、编辑文件、运行命令,并为你处理整个开发工作流。
|
||||||
|
|
||||||
> **⚠️ 安全提示**:Kode 默认以 YOLO 模式运行(等同于 Claude 的 `--dangerously-skip-permissions` 标志),跳过所有权限检查以获得最大生产力。YOLO 模式仅建议在安全可信的环境中处理非重要项目时使用。如果您正在处理重要文件或使用能力存疑的模型,我们强烈建议使用 `kode --safe` 启用权限检查和手动审批所有操作。
|
> **⚠️ 安全提示**:Kode 默认以 YOLO 模式运行(等同于 Claude Code 的 `--dangerously-skip-permissions` 标志),跳过所有权限检查以获得最大生产力。YOLO 模式仅建议在安全可信的环境中处理非重要项目时使用。如果您正在处理重要文件或使用能力存疑的模型,我们强烈建议使用 `kode --safe` 启用权限检查和手动审批所有操作。
|
||||||
>
|
>
|
||||||
> **📊 模型性能建议**:为获得最佳体验,建议使用专为自主任务完成设计的新一代强大模型。避免使用 GPT-4o、Gemini 2.5 Pro 等较老的问答型模型,它们主要针对回答问题进行优化,而非持续的独立任务执行。请选择专门训练用于智能体工作流和扩展推理能力的模型。
|
> **📊 模型性能建议**:为获得最佳体验,建议使用专为自主任务完成设计的新一代强大模型。避免使用 GPT-4o、Gemini 2.5 Pro 等较老的问答型模型,它们主要针对回答问题进行优化,而非持续的独立任务执行。请选择专门训练用于智能体工作流和扩展推理能力的模型。
|
||||||
|
|
||||||
|
|||||||
@ -74,8 +74,8 @@ Agents can be defined at five levels with priority order (later overrides earlie
|
|||||||
- Provided with Kode
|
- Provided with Kode
|
||||||
- Cannot be modified
|
- Cannot be modified
|
||||||
|
|
||||||
2. **Claude User** (`~/.claude/agents/`)
|
2. **.claude User (Claude Code)** (`~/.claude/agents/`)
|
||||||
- Claude Code compatible user-level agents
|
- Compatibility with Claude Code user directories
|
||||||
- Personal agents available across all projects
|
- Personal agents available across all projects
|
||||||
|
|
||||||
3. **Kode User** (`~/.kode/agents/`)
|
3. **Kode User** (`~/.kode/agents/`)
|
||||||
@ -83,8 +83,8 @@ Agents can be defined at five levels with priority order (later overrides earlie
|
|||||||
- Overrides Claude user agents with same name
|
- Overrides Claude user agents with same name
|
||||||
- Create with `/agents` command or manually
|
- Create with `/agents` command or manually
|
||||||
|
|
||||||
4. **Claude Project** (`./.claude/agents/`)
|
4. **.claude Project (Claude Code)** (`./.claude/agents/`)
|
||||||
- Claude Code compatible project-specific agents
|
- Compatibility with Claude Code project directories
|
||||||
- Overrides user-level agents
|
- Overrides user-level agents
|
||||||
|
|
||||||
5. **Kode Project** (`./.kode/agents/`)
|
5. **Kode Project** (`./.kode/agents/`)
|
||||||
@ -227,4 +227,4 @@ Planned improvements:
|
|||||||
- Performance metrics per agent
|
- Performance metrics per agent
|
||||||
- Agent composition (agents using other agents)
|
- Agent composition (agents using other agents)
|
||||||
- Cloud-based agent sharing
|
- Cloud-based agent sharing
|
||||||
- Agent versioning and rollback
|
- Agent versioning and rollback
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import { randomUUID } from 'crypto'
|
|||||||
|
|
||||||
const execAsync = promisify(exec)
|
const execAsync = promisify(exec)
|
||||||
|
|
||||||
// Core constants aligned with Claude Code architecture
|
// Core constants aligned with the Claude Code agent architecture
|
||||||
const AGENT_LOCATIONS = {
|
const AGENT_LOCATIONS = {
|
||||||
USER: "user",
|
USER: "user",
|
||||||
PROJECT: "project",
|
PROJECT: "project",
|
||||||
@ -324,7 +324,7 @@ function validateAgentConfig(config: Partial<CreateState>, existingAgents: Agent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// File system operations with Claude Code alignment
|
// File system operations retained for Claude Code parity
|
||||||
function getAgentDirectory(location: AgentLocation): string {
|
function getAgentDirectory(location: AgentLocation): string {
|
||||||
if (location === AGENT_LOCATIONS.BUILT_IN || location === AGENT_LOCATIONS.ALL) {
|
if (location === AGENT_LOCATIONS.BUILT_IN || location === AGENT_LOCATIONS.ALL) {
|
||||||
throw new Error(`Cannot get directory path for ${location} agents`)
|
throw new Error(`Cannot get directory path for ${location} agents`)
|
||||||
@ -545,7 +545,7 @@ async function updateAgent(
|
|||||||
writeFileSync(filePath, content, { encoding: 'utf-8', flag: 'w' })
|
writeFileSync(filePath, content, { encoding: 'utf-8', flag: 'w' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enhanced UI Components with Claude Code alignment
|
// Enhanced UI components retained for Claude Code parity
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
title: string
|
title: string
|
||||||
@ -1574,7 +1574,7 @@ function AgentListView({
|
|||||||
<Box marginBottom={1}>
|
<Box marginBottom={1}>
|
||||||
<Text bold color={theme.primary}>💭 What are agents?</Text>
|
<Text bold color={theme.primary}>💭 What are agents?</Text>
|
||||||
</Box>
|
</Box>
|
||||||
<Text>Specialized AI assistants that Claude can delegate to for specific tasks.</Text>
|
<Text>Specialized AI assistants that Kode can delegate to for specific tasks, compatible with Claude Code `.claude` agent packs.</Text>
|
||||||
<Text>Each agent has its own context, prompt, and tools.</Text>
|
<Text>Each agent has its own context, prompt, and tools.</Text>
|
||||||
|
|
||||||
<Box marginTop={1} marginBottom={1}>
|
<Box marginTop={1} marginBottom={1}>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { Command } from '../commands'
|
import type { Command } from '../commands'
|
||||||
import { markProjectOnboardingComplete } from '../ProjectOnboarding'
|
import { markProjectOnboardingComplete } from '../components/ProjectOnboarding'
|
||||||
import { PROJECT_FILE } from '../constants/product'
|
import { PROJECT_FILE } from '../constants/product'
|
||||||
const command = {
|
const command = {
|
||||||
type: 'prompt',
|
type: 'prompt',
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import chalk from 'chalk'
|
|||||||
import { getTheme } from '../utils/theme'
|
import { getTheme } from '../utils/theme'
|
||||||
import { env } from '../utils/env'
|
import { env } from '../utils/env'
|
||||||
import { getGlobalConfig, saveGlobalConfig } from '../utils/config'
|
import { getGlobalConfig, saveGlobalConfig } from '../utils/config'
|
||||||
import { markProjectOnboardingComplete } from '../ProjectOnboarding'
|
import { markProjectOnboardingComplete } from '../components/ProjectOnboarding'
|
||||||
import { readFileSync, writeFileSync } from 'fs'
|
import { readFileSync, writeFileSync } from 'fs'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { safeParseJSON } from '../utils/json'
|
import { safeParseJSON } from '../utils/json'
|
||||||
|
|||||||
@ -175,10 +175,10 @@ export function Help({
|
|||||||
Custom commands loaded from:
|
Custom commands loaded from:
|
||||||
</Text>
|
</Text>
|
||||||
<Text color={theme.secondaryText}>
|
<Text color={theme.secondaryText}>
|
||||||
• {getCustomCommandDirectories().userClaude} (user: prefix)
|
• {getCustomCommandDirectories().userClaude} (Claude `.claude` user scope)
|
||||||
</Text>
|
</Text>
|
||||||
<Text color={theme.secondaryText}>
|
<Text color={theme.secondaryText}>
|
||||||
• {getCustomCommandDirectories().projectClaude} (project: prefix)
|
• {getCustomCommandDirectories().projectClaude} (Claude `.claude` project scope)
|
||||||
</Text>
|
</Text>
|
||||||
<Text color={theme.secondaryText}>
|
<Text color={theme.secondaryText}>
|
||||||
Use /refresh-commands to reload after changes
|
Use /refresh-commands to reload after changes
|
||||||
@ -190,10 +190,10 @@ export function Help({
|
|||||||
Create custom commands by adding .md files to:
|
Create custom commands by adding .md files to:
|
||||||
</Text>
|
</Text>
|
||||||
<Text color={theme.secondaryText}>
|
<Text color={theme.secondaryText}>
|
||||||
• {getCustomCommandDirectories().userClaude} (user: prefix)
|
• {getCustomCommandDirectories().userClaude} (Claude `.claude` user scope)
|
||||||
</Text>
|
</Text>
|
||||||
<Text color={theme.secondaryText}>
|
<Text color={theme.secondaryText}>
|
||||||
• {getCustomCommandDirectories().projectClaude} (project: prefix)
|
• {getCustomCommandDirectories().projectClaude} (Claude `.claude` project scope)
|
||||||
</Text>
|
</Text>
|
||||||
<Text color={theme.secondaryText}>
|
<Text color={theme.secondaryText}>
|
||||||
Use /refresh-commands to reload after creation
|
Use /refresh-commands to reload after creation
|
||||||
|
|||||||
@ -18,7 +18,7 @@ interface InvalidConfigDialogProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog shown when the Claude config file contains invalid JSON
|
* Dialog shown when the Kode config file contains invalid JSON
|
||||||
*/
|
*/
|
||||||
function InvalidConfigDialog({
|
function InvalidConfigDialog({
|
||||||
filePath,
|
filePath,
|
||||||
|
|||||||
@ -6,17 +6,17 @@ import {
|
|||||||
getGlobalConfig,
|
getGlobalConfig,
|
||||||
saveCurrentProjectConfig,
|
saveCurrentProjectConfig,
|
||||||
saveGlobalConfig,
|
saveGlobalConfig,
|
||||||
} from './utils/config.js'
|
} from '../utils/config.js'
|
||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { homedir } from 'os'
|
import { homedir } from 'os'
|
||||||
import terminalSetup from './commands/terminalSetup'
|
import terminalSetup from '../commands/terminalSetup'
|
||||||
import { getTheme } from './utils/theme'
|
import { getTheme } from '../utils/theme'
|
||||||
import { RELEASE_NOTES } from './constants/releaseNotes'
|
import { RELEASE_NOTES } from '../constants/releaseNotes'
|
||||||
import { gt } from 'semver'
|
import { gt } from 'semver'
|
||||||
import { isDirEmpty } from './utils/file'
|
import { isDirEmpty } from '../utils/file'
|
||||||
import { MACRO } from './constants/macros'
|
import { MACRO } from '../constants/macros'
|
||||||
import { PROJECT_FILE, PRODUCT_NAME } from './constants/product'
|
import { PROJECT_FILE, PRODUCT_NAME } from '../constants/product'
|
||||||
|
|
||||||
// Function to mark onboarding as complete
|
// Function to mark onboarding as complete
|
||||||
export function markProjectOnboardingComplete(): void {
|
export function markProjectOnboardingComplete(): void {
|
||||||
@ -74,9 +74,9 @@ export default function ProjectOnboarding({
|
|||||||
|
|
||||||
// Load what we need for onboarding
|
// Load what we need for onboarding
|
||||||
// NOTE: This whole component is statically rendered Once
|
// NOTE: This whole component is statically rendered Once
|
||||||
const hasClaudeMd = existsSync(join(workspaceDir, PROJECT_FILE))
|
const workspaceHasProjectGuide = existsSync(join(workspaceDir, PROJECT_FILE))
|
||||||
const isWorkspaceDirEmpty = isDirEmpty(workspaceDir)
|
const isWorkspaceDirEmpty = isDirEmpty(workspaceDir)
|
||||||
const needsClaudeMd = !hasClaudeMd && !isWorkspaceDirEmpty
|
const shouldRecommendProjectGuide = !workspaceHasProjectGuide && !isWorkspaceDirEmpty
|
||||||
const showTerminalTip =
|
const showTerminalTip =
|
||||||
terminalSetup.isEnabled && !getGlobalConfig().shiftEnterKeyBindingInstalled
|
terminalSetup.isEnabled && !getGlobalConfig().shiftEnterKeyBindingInstalled
|
||||||
|
|
||||||
@ -106,9 +106,9 @@ export default function ProjectOnboarding({
|
|||||||
</React.Fragment>,
|
</React.Fragment>,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (needsClaudeMd) {
|
if (shouldRecommendProjectGuide) {
|
||||||
items.push(
|
items.push(
|
||||||
<React.Fragment key="claudemd">
|
<React.Fragment key="projectGuide">
|
||||||
{/* @ts-expect-error - OrderedList.Item children prop issue */}
|
{/* @ts-expect-error - OrderedList.Item children prop issue */}
|
||||||
<OrderedList.Item>
|
<OrderedList.Item>
|
||||||
<Text color={theme.secondaryText}>
|
<Text color={theme.secondaryText}>
|
||||||
@ -308,7 +308,7 @@ function PromptInput({
|
|||||||
addToHistory(mode === 'koding' ? `#${input}` : input)
|
addToHistory(mode === 'koding' ? `#${input}` : input)
|
||||||
onInputChange('')
|
onInputChange('')
|
||||||
|
|
||||||
// Create additional context to inform Claude this is for KODING.md
|
// Create additional context to inform the assistant this is for KODING.md
|
||||||
const kodingContext =
|
const kodingContext =
|
||||||
'The user is using Koding mode. Format your response as a comprehensive, well-structured document suitable for adding to AGENTS.md. Use proper markdown formatting with headings, lists, code blocks, etc. The response should be complete and ready to add to AGENTS.md documentation.'
|
'The user is using Koding mode. Format your response as a comprehensive, well-structured document suitable for adding to AGENTS.md. Use proper markdown formatting with headings, lists, code blocks, etc. The response should be complete and ready to add to AGENTS.md documentation.'
|
||||||
|
|
||||||
@ -354,8 +354,8 @@ function PromptInput({
|
|||||||
if (messages.length) {
|
if (messages.length) {
|
||||||
await onQuery(messages)
|
await onQuery(messages)
|
||||||
|
|
||||||
// After query completes, the last message should be Claude's response
|
// After query completes, the last message should be the assistant's response
|
||||||
// We'll set up a one-time listener to capture and save Claude's response
|
// We'll set up a one-time listener to capture and save that response
|
||||||
// This will be handled by the REPL component or message handler
|
// This will be handled by the REPL component or message handler
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +524,7 @@ function PromptInput({
|
|||||||
onShowMessageSelector()
|
onShowMessageSelector()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift+Tab for mode cycling (matching original Claude Code implementation)
|
// Shift+Tab for mode cycling (retains legacy keyboard behavior)
|
||||||
if (key.shift && key.tab) {
|
if (key.shift && key.tab) {
|
||||||
cycleMode()
|
cycleMode()
|
||||||
return true // Explicitly handled
|
return true // Explicitly handled
|
||||||
|
|||||||
@ -74,7 +74,7 @@ export function AssistantTextMessage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (text) {
|
switch (text) {
|
||||||
// Local JSX commands don't need a response, but we still want Claude to see them
|
// Local JSX commands don't need a response, but we still want the assistant to see them
|
||||||
// Tool results render their own interrupt messages
|
// Tool results render their own interrupt messages
|
||||||
case NO_RESPONSE_REQUESTED:
|
case NO_RESPONSE_REQUESTED:
|
||||||
case INTERRUPT_MESSAGE_FOR_TOOL_USE:
|
case INTERRUPT_MESSAGE_FOR_TOOL_USE:
|
||||||
|
|||||||
@ -5,7 +5,7 @@ const pkg = require('../../package.json')
|
|||||||
|
|
||||||
export const MACRO = {
|
export const MACRO = {
|
||||||
VERSION: pkg.version,
|
VERSION: pkg.version,
|
||||||
README_URL: 'https://docs.anthropic.com/s/claude-code',
|
README_URL: 'https://github.com/shareAI-lab/kode#readme',
|
||||||
PACKAGE_URL: '@shareai-lab/kode',
|
PACKAGE_URL: '@shareai-lab/kode',
|
||||||
ISSUES_EXPLAINER: 'report the issue at https://github.com/shareAI-lab/kode/issues',
|
ISSUES_EXPLAINER: 'report the issue at https://github.com/shareAI-lab/kode/issues',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,8 @@ import { lastX } from './utils/generators'
|
|||||||
import { getGitEmail } from './utils/user'
|
import { getGitEmail } from './utils/user'
|
||||||
import { PROJECT_FILE } from './constants/product'
|
import { PROJECT_FILE } from './constants/product'
|
||||||
/**
|
/**
|
||||||
* Find all AGENTS.md and CLAUDE.md files in the current working directory
|
* Locate AGENTS.md and CLAUDE.md files for backward compatibility with
|
||||||
|
* existing documentation workflows.
|
||||||
*/
|
*/
|
||||||
export async function getClaudeFiles(): Promise<string | null> {
|
export async function getClaudeFiles(): Promise<string | null> {
|
||||||
const abortController = new AbortController()
|
const abortController = new AbortController()
|
||||||
|
|||||||
@ -377,7 +377,6 @@ ${commandList}`,
|
|||||||
),
|
),
|
||||||
getClients(),
|
getClients(),
|
||||||
])
|
])
|
||||||
// logStartup()
|
|
||||||
const inputPrompt = [prompt, stdinContent].filter(Boolean).join('\n')
|
const inputPrompt = [prompt, stdinContent].filter(Boolean).join('\n')
|
||||||
if (print) {
|
if (print) {
|
||||||
if (!inputPrompt) {
|
if (!inputPrompt) {
|
||||||
@ -1291,7 +1290,6 @@ ${commandList}`,
|
|||||||
loadLogList(CACHE_PATHS.messages()),
|
loadLogList(CACHE_PATHS.messages()),
|
||||||
getClients(),
|
getClients(),
|
||||||
])
|
])
|
||||||
// logStartup()
|
|
||||||
|
|
||||||
// If a specific conversation is requested, load and resume it directly
|
// If a specific conversation is requested, load and resume it directly
|
||||||
if (identifier !== undefined) {
|
if (identifier !== undefined) {
|
||||||
@ -1393,7 +1391,7 @@ ${commandList}`,
|
|||||||
})()
|
})()
|
||||||
})
|
})
|
||||||
|
|
||||||
// claude context (TODO: deprecate)
|
// legacy context (TODO: deprecate)
|
||||||
const context = program
|
const context = program
|
||||||
.command('context')
|
.command('context')
|
||||||
.description(
|
.description(
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { ToolUseBlockParam } from '@anthropic-ai/sdk/resources/index.mjs'
|
|||||||
import { Box, Newline, Static, Text } from 'ink'
|
import { Box, Newline, Static, Text } from 'ink'
|
||||||
import ProjectOnboarding, {
|
import ProjectOnboarding, {
|
||||||
markProjectOnboardingComplete,
|
markProjectOnboardingComplete,
|
||||||
} from '../ProjectOnboarding.js'
|
} from '../components/ProjectOnboarding.js'
|
||||||
import { CostThresholdDialog } from '../components/CostThresholdDialog'
|
import { CostThresholdDialog } from '../components/CostThresholdDialog'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useEffect, useMemo, useRef, useState, useCallback } from 'react'
|
import { useEffect, useMemo, useRef, useState, useCallback } from 'react'
|
||||||
@ -337,7 +337,7 @@ export function REPL({
|
|||||||
|
|
||||||
setMessages(oldMessages => [...oldMessages, ...newMessages])
|
setMessages(oldMessages => [...oldMessages, ...newMessages])
|
||||||
|
|
||||||
// Mark onboarding as complete when any user message is sent to Claude
|
// Mark onboarding as complete when any user message is sent to the assistant
|
||||||
markProjectOnboardingComplete()
|
markProjectOnboardingComplete()
|
||||||
|
|
||||||
// The last message is an assistant message if the user input was a bash command,
|
// The last message is an assistant message if the user input was a bash command,
|
||||||
|
|||||||
@ -148,9 +148,9 @@ class KodeContextManager {
|
|||||||
|
|
||||||
// 在调试模式下记录加载结果
|
// 在调试模式下记录加载结果
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.log(
|
debugLogger.info('KODE_CONTEXT_LOADED', {
|
||||||
`[KodeContext] Loaded ${this.projectDocsCache.length} characters from project docs`,
|
characters: this.projectDocsCache.length,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('[KodeContext] Failed to load project docs:', error)
|
console.warn('[KodeContext] Failed to load project docs:', error)
|
||||||
@ -1212,7 +1212,7 @@ export function formatSystemPromptWithContext(
|
|||||||
agentId?: string,
|
agentId?: string,
|
||||||
skipContextReminders = false, // Parameter kept for API compatibility but not used anymore
|
skipContextReminders = false, // Parameter kept for API compatibility but not used anymore
|
||||||
): { systemPrompt: string[]; reminders: string } {
|
): { systemPrompt: string[]; reminders: string } {
|
||||||
// 构建增强的系统提示 - 对齐官方 Claude Code 直接注入方式
|
// 构建增强的系统提示,保持与原先直接注入方式的兼容
|
||||||
const enhancedPrompt = [...systemPrompt]
|
const enhancedPrompt = [...systemPrompt]
|
||||||
let reminders = ''
|
let reminders = ''
|
||||||
|
|
||||||
@ -1759,7 +1759,10 @@ function getAssistantMessageFromError(error: unknown): AssistantMessage {
|
|||||||
}
|
}
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
console.log(error)
|
debugLogger.error('ANTHROPIC_API_ERROR', {
|
||||||
|
message: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return createAssistantAPIErrorMessage(
|
return createAssistantAPIErrorMessage(
|
||||||
`${API_ERROR_MESSAGE_PREFIX}: ${error.message}`,
|
`${API_ERROR_MESSAGE_PREFIX}: ${error.message}`,
|
||||||
|
|||||||
@ -136,7 +136,6 @@ export async function resolveFileReferences(content: string): Promise<string> {
|
|||||||
function validateAllowedTools(allowedTools: string[] | undefined): boolean {
|
function validateAllowedTools(allowedTools: string[] | undefined): boolean {
|
||||||
// Log allowed tools for debugging and future integration
|
// Log allowed tools for debugging and future integration
|
||||||
if (allowedTools && allowedTools.length > 0) {
|
if (allowedTools && allowedTools.length > 0) {
|
||||||
console.log('Command allowed tools:', allowedTools)
|
|
||||||
// TODO: Integrate with src/permissions.ts tool permission system
|
// TODO: Integrate with src/permissions.ts tool permission system
|
||||||
// TODO: Connect to Tool.tsx needsPermissions() mechanism
|
// TODO: Connect to Tool.tsx needsPermissions() mechanism
|
||||||
}
|
}
|
||||||
@ -147,8 +146,8 @@ function validateAllowedTools(allowedTools: string[] | undefined): boolean {
|
|||||||
* Frontmatter configuration for custom commands
|
* Frontmatter configuration for custom commands
|
||||||
*
|
*
|
||||||
* This interface defines the YAML frontmatter structure that can be used
|
* This interface defines the YAML frontmatter structure that can be used
|
||||||
* to configure custom commands. It follows the same pattern as Claude Desktop's
|
* to configure custom commands. It mirrors the Claude Desktop custom command
|
||||||
* custom command system but with additional fields for enhanced functionality.
|
* system for compatibility while adding Kode-specific enhancements.
|
||||||
*/
|
*/
|
||||||
export interface CustomCommandFrontmatter {
|
export interface CustomCommandFrontmatter {
|
||||||
/** Display name for the command (overrides filename-based naming) */
|
/** Display name for the command (overrides filename-based naming) */
|
||||||
@ -436,10 +435,10 @@ function createCustomCommand(
|
|||||||
async getPromptForCommand(args: string): Promise<MessageParam[]> {
|
async getPromptForCommand(args: string): Promise<MessageParam[]> {
|
||||||
let prompt = content.trim()
|
let prompt = content.trim()
|
||||||
|
|
||||||
// Process argument substitution following Claude Code conventions
|
// Process argument substitution following legacy conventions
|
||||||
// This supports both the official $ARGUMENTS format and legacy {arg} format
|
// This supports both the official $ARGUMENTS format and legacy {arg} format
|
||||||
|
|
||||||
// Step 1: Handle $ARGUMENTS placeholder (official Claude Code format)
|
// Step 1: Handle $ARGUMENTS placeholder (legacy command format)
|
||||||
if (prompt.includes('$ARGUMENTS')) {
|
if (prompt.includes('$ARGUMENTS')) {
|
||||||
prompt = prompt.replace(/\$ARGUMENTS/g, args || '')
|
prompt = prompt.replace(/\$ARGUMENTS/g, args || '')
|
||||||
}
|
}
|
||||||
@ -650,9 +649,6 @@ export const loadCustomCommands = memoize(
|
|||||||
*/
|
*/
|
||||||
export const reloadCustomCommands = (): void => {
|
export const reloadCustomCommands = (): void => {
|
||||||
loadCustomCommands.cache.clear()
|
loadCustomCommands.cache.clear()
|
||||||
console.log(
|
|
||||||
'Custom commands cache cleared. Commands will be reloaded on next use.',
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { getAvailableAgentTypes } from '../utils/agentLoader'
|
|||||||
import { existsSync } from 'fs'
|
import { existsSync } from 'fs'
|
||||||
import { resolve } from 'path'
|
import { resolve } from 'path'
|
||||||
import { getCwd } from '../utils/state'
|
import { getCwd } from '../utils/state'
|
||||||
|
import { debug as debugLogger } from '../utils/debugLogger'
|
||||||
|
|
||||||
export interface MentionContext {
|
export interface MentionContext {
|
||||||
type: 'agent' | 'file'
|
type: 'agent' | 'file'
|
||||||
@ -159,10 +160,10 @@ class MentionProcessorService {
|
|||||||
|
|
||||||
// Log cache refresh for debugging mention resolution issues
|
// Log cache refresh for debugging mention resolution issues
|
||||||
if (agents.length !== previousCacheSize) {
|
if (agents.length !== previousCacheSize) {
|
||||||
console.log('[MentionProcessor] Agent cache refreshed:', {
|
debugLogger.info('MENTION_PROCESSOR_CACHE_REFRESHED', {
|
||||||
agentCount: agents.length,
|
agentCount: agents.length,
|
||||||
previousCacheSize,
|
previousCacheSize,
|
||||||
cacheAge: now - this.lastAgentCheck
|
cacheAge: now - this.lastAgentCheck,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -232,17 +233,17 @@ class MentionProcessorService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Debug log for mention event emission tracking
|
// Debug log for mention event emission tracking
|
||||||
console.log('[MentionProcessor] Emitted mention event:', {
|
debugLogger.info('MENTION_PROCESSOR_EVENT_EMITTED', {
|
||||||
type: isAskModel ? 'ask-model' : 'agent',
|
type: isAskModel ? 'ask-model' : 'agent',
|
||||||
mention,
|
mention,
|
||||||
agentType: isAskModel ? undefined : agentType
|
agentType: isAskModel ? undefined : agentType,
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[MentionProcessor] Failed to emit mention event:', {
|
debugLogger.error('MENTION_PROCESSOR_EVENT_FAILED', {
|
||||||
mention,
|
mention,
|
||||||
agentType,
|
agentType,
|
||||||
isAskModel,
|
isAskModel,
|
||||||
error: error instanceof Error ? error.message : error
|
error: error instanceof Error ? error.message : error,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,4 +271,4 @@ export const processMentions = (input: string) =>
|
|||||||
* Clear mention processor caches
|
* Clear mention processor caches
|
||||||
*/
|
*/
|
||||||
export const clearMentionCache = () =>
|
export const clearMentionCache = () =>
|
||||||
mentionProcessor.clearCache()
|
mentionProcessor.clearCache()
|
||||||
|
|||||||
@ -55,12 +55,12 @@ const inputSchema = z.object({
|
|||||||
|
|
||||||
export const TaskTool = {
|
export const TaskTool = {
|
||||||
async prompt({ safeMode }) {
|
async prompt({ safeMode }) {
|
||||||
// Match original Claude Code - prompt returns full agent descriptions
|
// Ensure agent prompts remain compatible with Claude Code `.claude` agent packs
|
||||||
return await getPrompt(safeMode)
|
return await getPrompt(safeMode)
|
||||||
},
|
},
|
||||||
name: TOOL_NAME,
|
name: TOOL_NAME,
|
||||||
async description() {
|
async description() {
|
||||||
// Match original Claude Code exactly - simple description
|
// Ensure metadata stays compatible with Claude Code `.claude` agent packs
|
||||||
return "Launch a new task"
|
return "Launch a new task"
|
||||||
},
|
},
|
||||||
inputSchema,
|
inputSchema,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export async function getTaskTools(safeMode: boolean): Promise<Tool[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getPrompt(safeMode: boolean): Promise<string> {
|
export async function getPrompt(safeMode: boolean): Promise<string> {
|
||||||
// Extracted directly from original Claude Code obfuscated source
|
// Maintain compatibility with Claude Code `.claude` agent descriptions
|
||||||
const agents = await getActiveAgents()
|
const agents = await getActiveAgents()
|
||||||
|
|
||||||
// Format exactly as in original: (Tools: tool1, tool2)
|
// Format exactly as in original: (Tools: tool1, tool2)
|
||||||
@ -29,7 +29,7 @@ export async function getPrompt(safeMode: boolean): Promise<string> {
|
|||||||
return `- ${agent.agentType}: ${agent.whenToUse} (Tools: ${toolsStr})`
|
return `- ${agent.agentType}: ${agent.whenToUse} (Tools: ${toolsStr})`
|
||||||
}).join('\n')
|
}).join('\n')
|
||||||
|
|
||||||
// 100% exact copy from original Claude Code source
|
// Keep the wording aligned so shared `.claude` agent packs behave identically
|
||||||
return `Launch a new agent to handle complex, multi-step tasks autonomously.
|
return `Launch a new agent to handle complex, multi-step tasks autonomously.
|
||||||
|
|
||||||
Available agent types and the tools they have access to:
|
Available agent types and the tools they have access to:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Permission mode types based on original Claude Code implementation
|
// Permission mode types retained for compatibility with earlier agent implementations
|
||||||
export type PermissionMode =
|
export type PermissionMode =
|
||||||
| 'default'
|
| 'default'
|
||||||
| 'acceptEdits'
|
| 'acceptEdits'
|
||||||
@ -35,7 +35,7 @@ export interface ModeConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode configuration based on original Claude Code
|
// Mode configuration preserved for Claude Code parity
|
||||||
export const MODE_CONFIGS: Record<PermissionMode, ModeConfig> = {
|
export const MODE_CONFIGS: Record<PermissionMode, ModeConfig> = {
|
||||||
default: {
|
default: {
|
||||||
name: 'default',
|
name: 'default',
|
||||||
@ -100,7 +100,7 @@ export const MODE_CONFIGS: Record<PermissionMode, ModeConfig> = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode cycling function (based on original yg2 function)
|
// Mode cycling function preserved from the Claude Code workflow
|
||||||
export function getNextPermissionMode(
|
export function getNextPermissionMode(
|
||||||
currentMode: PermissionMode,
|
currentMode: PermissionMode,
|
||||||
isBypassAvailable: boolean = true,
|
isBypassAvailable: boolean = true,
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import wrapAnsi from 'wrap-ansi'
|
import wrapAnsi from 'wrap-ansi'
|
||||||
|
import { debug as debugLogger } from './debugLogger'
|
||||||
|
|
||||||
type WrappedText = string[]
|
type WrappedText = string[]
|
||||||
type Position = {
|
type Position = {
|
||||||
@ -320,11 +321,12 @@ export class MeasuredText {
|
|||||||
// For non-blank lines
|
// For non-blank lines
|
||||||
const startOffset = this.text.indexOf(text, searchOffset)
|
const startOffset = this.text.indexOf(text, searchOffset)
|
||||||
if (startOffset === -1) {
|
if (startOffset === -1) {
|
||||||
console.log('Debug: Failed to find wrapped line in original text')
|
debugLogger.error('CURSOR_WRAP_MISMATCH', {
|
||||||
console.log('Debug: Current text:', text)
|
currentText: text,
|
||||||
console.log('Debug: Full original text:', this.text)
|
originalText: this.text,
|
||||||
console.log('Debug: Search offset:', searchOffset)
|
searchOffset,
|
||||||
console.log('Debug: Wrapped text:', wrappedText)
|
wrappedText,
|
||||||
|
})
|
||||||
throw new Error('Failed to find wrapped line in original text')
|
throw new Error('Failed to find wrapped line in original text')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* Agent configuration loader
|
* Agent configuration loader
|
||||||
* Loads agent configurations from markdown files with YAML frontmatter
|
* Loads agent configurations from markdown files with YAML frontmatter.
|
||||||
* Following Claude Code's agent system architecture
|
* Maintains compatibility with Claude Code `.claude` agent directories while
|
||||||
|
* prioritizing Kode-specific overrides.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { existsSync, readFileSync, readdirSync, statSync, watch, FSWatcher } from 'fs'
|
import { existsSync, readFileSync, readdirSync, statSync, watch, FSWatcher } from 'fs'
|
||||||
@ -231,7 +232,7 @@ let watchers: FSWatcher[] = []
|
|||||||
export async function startAgentWatcher(onChange?: () => void): Promise<void> {
|
export async function startAgentWatcher(onChange?: () => void): Promise<void> {
|
||||||
await stopAgentWatcher() // Clean up any existing watchers
|
await stopAgentWatcher() // Clean up any existing watchers
|
||||||
|
|
||||||
// Watch both .claude and .kode directories
|
// Watch both Claude (.claude) and native (.kode) directories
|
||||||
const userClaudeDir = join(homedir(), '.claude', 'agents')
|
const userClaudeDir = join(homedir(), '.claude', 'agents')
|
||||||
const userKodeDir = join(homedir(), '.kode', 'agents')
|
const userKodeDir = join(homedir(), '.kode', 'agents')
|
||||||
const projectClaudeDir = join(getCwd(), '.claude', 'agents')
|
const projectClaudeDir = join(getCwd(), '.claude', 'agents')
|
||||||
|
|||||||
@ -22,7 +22,7 @@ type Props = {
|
|||||||
verbose?: boolean
|
verbose?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends a single prompt to the Claude API and returns the response.
|
// Sends a single prompt to the Anthropic Messages API and returns the response.
|
||||||
// Assumes that claude is being used non-interactively -- will not
|
// Assumes that claude is being used non-interactively -- will not
|
||||||
// ask the user for permissions or further input.
|
// ask the user for permissions or further input.
|
||||||
export async function ask({
|
export async function ask({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user