diff --git a/README.md b/README.md index 43ae160..ba4d684 100644 --- a/README.md +++ b/README.md @@ -1,177 +1,3 @@ # aishell -**AI-powered shell automation tool** - A generic alternative to Claude Code - -## Overview - -aishellは、AIがシェルを操作するための汎用的なツールです。Claude Codeのような機能を、より柔軟で拡張可能な形で提供します。 - -**主な特徴:** -- **マルチLLMプロバイダー対応**: OpenAI、Claude、ローカルLLM(gpt-oss等) -- **Function Calling**: LLMがツールを直接呼び出してシェルを操作 -- **MCPサーバー**: Claude Desktopとの連携も可能 -- **AIOS統合**: aigptと組み合わせてAIによるOS管理を実現 - -## Installation - -```bash -# Rust環境が必要 -cargo build --release - -# バイナリをインストール -cargo install --path . -``` - -## Usage - -### 1. 対話型シェル (Interactive Shell) - -```bash -# OpenAI互換APIを使用 -export OPENAI_API_KEY="your-api-key" -aishell shell - -# 別のモデルを指定 -aishell shell -m gpt-4o - -# gpt-ossなどのOpenAI互換サーバーを使用 -export OPENAI_BASE_URL="http://localhost:8080/v1" -aishell shell -``` - -**使用例:** -``` -aishell> List all Rust files in src/ -[Executing tool: list] -src/main.rs -src/lib.rs -... - -aishell> Create a new file hello.txt with "Hello, World!" -[Executing tool: write] -Successfully wrote to file: hello.txt - -aishell> Show me the git status -[Executing tool: bash] -On branch main -... -``` - -### 2. ワンショット実行 (Single Command) - -```bash -aishell exec "Show me the current directory structure" -``` - -### 3. MCPサーバーモード (Claude Desktop Integration) - -```bash -aishell server -``` - -**Claude Desktop設定** (`~/Library/Application Support/Claude/claude_desktop_config.json`): -```json -{ - "mcpServers": { - "aishell": { - "command": "/path/to/aishell", - "args": ["server"] - } - } -} -``` - -## Architecture - -``` -aishell/ -├── src/ -│ ├── cli/ # 対話型インターフェイス (REPL) -│ ├── llm/ # LLMプロバイダー (OpenAI互換) -│ ├── shell/ # シェル実行エンジン -│ ├── mcp/ # MCPサーバー実装 -│ └── config/ # 設定管理 -``` - -**実行フロー:** -``` -User Input → LLM (Function Calling) → Tool Execution → Shell → Result → LLM → User -``` - -## Available Tools - -aishellは以下のツールをLLMに提供します: - -- **bash**: シェルコマンドを実行 -- **read**: ファイルを読み込み -- **write**: ファイルに書き込み -- **list**: ファイル一覧を取得 - -## Environment Variables - -| 変数 | 説明 | デフォルト | -|------|------|----------| -| `OPENAI_API_KEY` | OpenAI APIキー | (必須) | -| `OPENAI_BASE_URL` | APIベースURL | `https://api.openai.com/v1` | -| `OPENAI_MODEL` | 使用するモデル | `gpt-4` | - -## Integration with AIOS - -aishellは[aigpt](https://github.com/syui/aigpt)と組み合わせることで、AIOS(AI Operating System)の一部として機能します: - -- **aigpt**: AIメモリー、パーソナリティ分析 -- **aishell**: シェル操作、自動化 -- **AIOS**: これらを統合したAIによるOS管理システム - -## Comparison with Claude Code - -| 機能 | Claude Code | aishell | -|------|------------|---------| -| LLM | Claude専用 | **マルチプロバイダー** | -| 実行環境 | Electron Desktop | **CLI/MCP** | -| カスタマイズ | 限定的 | **完全制御** | -| ローカルLLM | 非対応 | **対応可能** | -| AIOS統合 | 不可 | **ネイティブ対応** | - -## Development - -```bash -# 開発ビルド -cargo build - -# テスト実行 -cargo test - -# ログ有効化 -RUST_LOG=debug aishell shell -``` - -## Technical Stack - -- **Language**: Rust 2021 -- **CLI**: clap 4.5 -- **Async Runtime**: tokio 1.40 -- **HTTP Client**: reqwest 0.12 -- **Shell Execution**: duct 0.13 -- **REPL**: rustyline 14.0 - -## Roadmap - -- [ ] Anthropic Claude API対応 -- [ ] Ollama対応(ローカルLLM) -- [ ] より高度なツールセット(git統合、ファイル検索等) -- [ ] 設定ファイルサポート -- [ ] セッション履歴の永続化 -- [ ] プラグインシステム - -## License - -MIT License - -## Author - -syui - -## Related Projects - -- [aigpt](https://github.com/syui/aigpt) - AI Memory System +A single-stream shell where commands and AI coexist — type a command, it runs; type anything else, AI responds. diff --git a/claude.md b/claude.md index f69c834..a23984e 100644 --- a/claude.md +++ b/claude.md @@ -1,41 +1,168 @@ # aishell +A single-stream shell where commands and AI coexist. -## 概要 - -Claude Codeのような、AIがshellを操作するためのツール。 -例えば、gpt-ossのようなllmを使用することを想定。場合によっては、MCPを駆使する。 - -## 主な機能 - -1. **マルチLLMプロバイダー対応** - - OpenAI API互換(OpenAI, gpt-oss, etc.) - - 将来的にClaude API、Ollamaなども対応予定 - -2. **Function Calling (Tool use)** - - LLMが直接ツールを呼び出してシェルを操作 - - bash, read, write, list等のツールを提供 - -3. **MCPサーバーモード** - - Claude Desktopとの連携が可能 - - aigptと同様のMCPプロトコル実装 - -## アーキテクチャ +## Architecture ``` -User → CLI → LLM Provider → Function Calling → Shell Executor → Result +┌──────────────────────────────────────────────┐ +│ aishell │ +│ │ +│ ┌──────────┐ judge ┌───────────────┐ │ +│ │ rustyline │───────────→│ sh -c command │ │ +│ │ (input) │ is_command └───────────────┘ │ +│ └──────────┘ │ +│ │ !is_command │ +│ ▼ │ +│ ┌──────────┐ stdin(JSON) ┌──────────────┐ │ +│ │ send() │─────────────→│ claude │ │ +│ │ (async) │ │ (persistent) │ │ +│ └──────────┘ │ stream-json │ │ +│ └──────────────┘ │ +│ ┌──────────┐ stdout(JSON) │ │ +│ │ reader │←────────────────────┘ │ +│ │ thread │ mpsc channel │ +│ └──────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────┐ │ +│ │ drain() │──→ println! (unified stream) │ +│ └──────────┘ │ +│ │ +│ ┌───────────────────────────────────────┐ │ +│ │ ● [1] responding... | [2] thinking... │ │ +│ └───────────────────────────────────────┘ │ +└──────────────────────────────────────────────┘ ``` -## AIOS統合 +## Claude Process (ai.rs) -- **aigpt**: メモリー、パーソナリティ分析 -- **aishell**: シェル操作、自動化 -- **統合**: AIによるOS管理の実現 +### Startup -## 技術スタック +One persistent process for the entire session: -- Rust 2021 -- tokio (async runtime) -- reqwest (HTTP client) -- duct (shell execution) -- clap (CLI framework) +``` +claude --input-format stream-json --output-format stream-json \ + --verbose --dangerously-skip-permissions +``` + +- `--input-format stream-json`: accepts JSON lines on stdin +- `--output-format stream-json`: emits JSON events on stdout +- Process stays alive until aishell exits. No restart per message. + +### Input Format + +```json +{"type":"user","message":{"role":"user","content":"user input here"}} +``` + +Written to claude's stdin via `Arc>`. + +### Output Events + +``` +type: "system" → init event (tools list, MCP servers, model info) +type: "assistant" → response content + content[].type: "text" → AI text (accumulated) + content[].type: "tool_use" → tool execution (name shown in status) +type: "result" → turn complete (final text, cost, usage) +``` + +### Thread Model + +``` +Main Thread Background Thread + │ │ + ├─ readline() ├─ BufReader::lines() on claude stdout + ├─ judge::is_command() ├─ serde_json::from_str() each line + ├─ command → executor::execute() ├─ "assistant" → accumulate text, update status + ├─ AI → claude.send() (non-blocking) ├─ "tool_use" → update status + ├─ drain_responses() before prompt ├─ "result" → mpsc::send() completed text + └─ status.set(status_line()) └─ remove session from status vec + +Polling Thread (200ms interval) + ├─ try_recv() completed responses → print immediately + └─ update status bar +``` + +### Shared State + +```rust +stdin: Arc> // main → claude stdin writes +status: Arc>> // both threads read/write status +output_tx: mpsc::Sender // background → main completed responses +output_rx: mpsc::Receiver // main drains with try_recv() +id_tx: mpsc::Sender // main → background session ID assignment +``` + +### Non-blocking Send + +```rust +pub fn send(&mut self, input: &str) -> usize { + let id = self.next_id; // assign session ID + self.next_id += 1; + status.push(SessionStatus { id, state: "thinking..." }); + self.id_tx.send(id); // notify reader thread + writeln!(stdin, "{}", json); // write JSON to claude stdin + stdin.flush(); + // returns immediately — does NOT wait for response + id +} +``` + +## Input Detection (judge.rs) + +Priority order: + +1. Shell operators (`|`, `>`, `<`, `;`, `&`) outside quotes → shell +2. Variable assignment (`FOO=bar`) → shell +3. Shell builtins (cd, echo, export, etc. — 50 builtins) → shell +4. Absolute/relative path to existing file → shell +5. Command found in PATH → shell +6. **None of the above → AI** + +Quote-aware: operators inside `'...'` or `"..."` are ignored. + +## Command Execution (executor.rs) + +- `cd` → `env::set_current_dir()` (changes process directory) +- `cd -` → OLDPWD support, `~` → HOME expansion +- Everything else → `sh -c "input"` (pipes, redirects, globs all work) + +## Status Bar (status.rs) + +Terminal last line reserved for Claude status: + +``` +● idle ← waiting +● [1] thinking... ← processing +● [1] responding... ← generating text +● [1] running: Bash... ← executing tool +● [1] responding... | [2] thinking... ← multiple sessions +``` + +Implementation: +- ANSI escape `\x1b[1;{rows-1}r` sets scroll region excluding last line +- `\x1b7` save cursor → draw status on last row → `\x1b8` restore cursor +- Auto-cleanup on Drop (reset scroll region) + +## Files + +``` +src/ +├── main.rs Main loop: input → judge → execute/AI → drain responses +├── lib.rs Module declarations +├── ai.rs ClaudeManager: persistent process, async send/receive +├── judge.rs is_command(): input classification (6 tests) +├── executor.rs execute(): sh -c + cd handling +└── status.rs StatusBar: ANSI last-line status display +``` + +## Dependencies + +```toml +rustyline = "14.0" # line input + history +serde = "1" # JSON serialization +serde_json = "1" # stream-json protocol parsing +terminal_size = "0.4" # terminal dimensions for status bar +```