diff --git a/.claude/QUICK_START.md b/.claude/QUICK_START.md new file mode 100644 index 0000000..504ecd5 --- /dev/null +++ b/.claude/QUICK_START.md @@ -0,0 +1,37 @@ +# miyabi-cli-standalone - Quick Start Guide + +## 🚀 3分で始めるMiyabi + +### 1. 環境変数設定 + +```bash +export GITHUB_TOKEN=ghp_xxx +export ANTHROPIC_API_KEY=sk-xxx +``` + +### 2. ステータス確認 + +```bash +miyabi status +``` + +### 3. Issue作成 + +GitHubでIssueを作成し、以下のラベルを付与: +- `type:feature` または `type:bug` +- `priority:P1-High` + +### 4. Agent実行 + +```bash +miyabi agent coordinator --issue 1 +``` + +## 📚 詳細ドキュメント + +- [CLAUDE.md](../CLAUDE.md) - プロジェクトコンテキスト +- [.claude/README.md](./README.md) - .claudeディレクトリ説明 + +--- + +**Miyabi** - Beauty in Autonomous Development 🌸 diff --git a/.claude/README.md b/.claude/README.md new file mode 100644 index 0000000..593fbac --- /dev/null +++ b/.claude/README.md @@ -0,0 +1,53 @@ +# .claude Directory + +Claude Code設定ディレクトリ + +## 構造 + +``` +.claude/ +├── agents/ +│ ├── specs/ # Agent仕様定義 +│ ├── prompts/ # 実行プロンプト +│ └── README.md +├── commands/ # カスタムスラッシュコマンド +├── prompts/ # 汎用プロンプト +└── templates/ # テンプレート +``` + +## カスタムコマンド + +`commands/` 配下に `*.md` ファイルを作成: + +```markdown +# commands/build.md +プロジェクトをビルドして、エラーがあれば修正してください。 + +cargo build --release +``` + +使用: `/project:build` + +## Agent仕様 + +`agents/specs/` でAgent定義: +- 役割・責任範囲 +- 使用可能ツール +- エスカレーション条件 + +## プロンプト + +`prompts/` に再利用可能プロンプト: +- コードレビュー +- リファクタリング +- テスト生成 + +## 使い方 + +```bash +# カスタムコマンド実行 +/project:build + +# Agent実行 +miyabi agent run --issue <番号> +``` diff --git a/.claude/agents/README.md b/.claude/agents/README.md new file mode 100644 index 0000000..afd530d --- /dev/null +++ b/.claude/agents/README.md @@ -0,0 +1,59 @@ +# Miyabi Agents + +このディレクトリには、Miyabiプロジェクトで使用するAgent仕様とプロンプトを配置します。 + +## 📁 ディレクトリ構造 + +``` +agents/ +├── specs/ # Agent仕様定義 +│ ├── coding/ # コーディング系Agent(7種類) +│ └── business/ # ビジネス系Agent(14種類) +└── prompts/ # 実行プロンプト + ├── coding/ # コーディング系Agentプロンプト + └── business/ # ビジネス系Agentプロンプト +``` + +## 🤖 Coding Agents(7種類) + +1. **CoordinatorAgent** - タスク統括・DAG分解 +2. **CodeGenAgent** - AI駆動コード生成 +3. **ReviewAgent** - コード品質レビュー +4. **IssueAgent** - Issue分析・ラベリング +5. **PRAgent** - Pull Request自動作成 +6. **DeploymentAgent** - CI/CDデプロイ自動化 +7. **RefresherAgent** - Issue状態監視・更新 + +## 💼 Business Agents(14種類) + +### 戦略・企画系(6種類) +- AIEntrepreneurAgent, ProductConceptAgent, ProductDesignAgent +- FunnelDesignAgent, PersonaAgent, SelfAnalysisAgent + +### マーケティング系(5種類) +- MarketResearchAgent, MarketingAgent, ContentCreationAgent +- SNSStrategyAgent, YouTubeAgent + +### 営業・顧客管理系(3種類) +- SalesAgent, CRMAgent, AnalyticsAgent + +## 📝 Agent仕様の書き方 + +詳細は各ディレクトリのREADME.mdを参照してください: +- [specs/coding/README.md](specs/coding/README.md) +- [specs/business/README.md](specs/business/README.md) + +## 🚀 Agent実行方法 + +```bash +# CoordinatorAgentでIssue処理 +miyabi agent run coordinator --issue 123 + +# 複数Issue並列処理 +miyabi agent run coordinator --issues 123,124,125 --concurrency 3 +``` + +## 🔗 参考リンク + +- [Miyabi Agent SDK](https://docs.rs/miyabi-agents) +- [CLAUDE.md](../../CLAUDE.md) - プロジェクトコンテキスト diff --git a/.claude/agents/issue-workflow-example.md b/.claude/agents/issue-workflow-example.md new file mode 100644 index 0000000..cb51b01 --- /dev/null +++ b/.claude/agents/issue-workflow-example.md @@ -0,0 +1,135 @@ +# Issue Creation Workflow Example + +このファイルは、miyabi-cli-standaloneプロジェクトでの標準的なIssue作成フローです。 + +## ステップ1: Issue作成 + +### GitHub Web UIで作成 +1. リポジトリの"Issues"タブをクリック +2. "New issue"をクリック +3. Issueテンプレートを使用(推奨) + +### GitHub CLIで作成(推奨) +```bash +gh issue create \ + --title "✨ Add user authentication" \ + --body "$(cat <<'EOF' +## 概要 +ユーザー認証機能を追加する + +## 要件 +- [ ] JWT トークン認証 +- [ ] ログイン/ログアウトエンドポイント +- [ ] トークンリフレッシュ機能 + +## 期待される成果 +- 認証付きAPIエンドポイント +- テストカバレッジ90%以上 +- セキュリティ監査パス +EOF +)" \ + --label "type:feature,priority:P1-High,state:pending" +``` + +## ステップ2: Agent実行 + +### 方法1: 新しいwork-onコマンド(推奨) +```bash +# Issue番号で実行 +miyabi work-on 1 + +# または作業説明で実行(Issue作成を提案) +miyabi work-on "Add user authentication" +``` + +### 方法2: 従来のagentコマンド +```bash +miyabi agent run coordinator --issue 1 +``` + +### 方法3: 並列実行 +```bash +miyabi parallel --issues 1,2,3 --concurrency 2 +``` + +## ステップ3: 進捗確認 + +```bash +# プロジェクトステータス確認 +miyabi status + +# Issue状態確認 +gh issue view 1 + +# Worktree確認 +git worktree list + +# ログ確認 +tail -f logs/miyabi-$(date +%Y%m%d).log +``` + +## ステップ4: レビュー + +Agentが自動的に: +1. コード生成 +2. テスト作成 +3. Linter実行 +4. PR作成 + +あなたがすべきこと: +1. PRレビュー +2. 追加修正(必要なら) +3. マージ + +## 実際の例 + +### 成功例: Issue #42 "Setup CI/CD pipeline" + +```bash +$ miyabi work-on 42 + +🚀 Let's work on it! + 📋 Issue #42 + +🤖 CoordinatorAgent starting... + ✅ Analyzed issue + ✅ Created 3 tasks + ✅ Assigned CodeGenAgent, ReviewAgent, DeploymentAgent + +⏱️ Estimated time: 15 minutes +🌳 Created worktree: .worktrees/issue-42 + +[15 minutes later] + +✅ All tasks completed! +📊 Quality score: 95/100 +🔗 PR created: #43 +``` + +## トラブルシューティング + +### Agentがスタックした場合 +```bash +# ログ確認 +grep -i "error" logs/miyabi-*.log + +# Worktreeクリーンアップ +git worktree prune + +# 再実行 +miyabi work-on 42 +``` + +### より詳しいヘルプ +```bash +# トラブルシューティングガイド +cat docs/TROUBLESHOOTING.md + +# Agent仕様確認 +cat .claude/agents/README.md +``` + +--- + +**miyabi-cli-standaloneプロジェクトの標準ワークフロー** +**Miyabi - Beauty in Autonomous Development 🌸** diff --git a/.claude/agents/prompts/coding/example-prompt.md b/.claude/agents/prompts/coding/example-prompt.md new file mode 100644 index 0000000..408efc3 --- /dev/null +++ b/.claude/agents/prompts/coding/example-prompt.md @@ -0,0 +1,53 @@ +# Example Agent Prompt + +このファイルは、Agentプロンプトのサンプルです。 + +## プロンプト構造 + +```markdown +# [Task名] + +## Context +プロジェクトのコンテキスト情報 + +## Objective +このAgentが達成すべき目標 + +## Inputs +- Issue URL: https://github.com/user/repo/issues/123 +- Task ID: TASK-456 +- Dependencies: TASK-123, TASK-124 + +## Instructions +1. ステップ1を実行 +2. ステップ2を実行 +3. ... + +## Output Format +期待される出力形式(JSON, Markdown, Code等) + +## Success Criteria +- 基準1 +- 基準2 +``` + +## 使用方法 + +Worktree内でClaude Codeセッションを起動する際、このプロンプトが自動的に読み込まれます。 + +```bash +cd .worktrees/issue-123 +# Claude Codeがこのプロンプトを参照して実行 +``` + +## カスタマイズ + +プロジェクト固有のプロンプトを作成する場合: + +1. このファイルをコピー +2. 内容をカスタマイズ +3. `.claude/agents/prompts/coding/` に配置 + +## 🔗 参考 + +実際のプロンプト例は、Miyabiプロジェクトの `.claude/agents/prompts/coding/` を参照してください。 diff --git a/.claude/agents/specs/business/README.md b/.claude/agents/specs/business/README.md new file mode 100644 index 0000000..4485ef7 --- /dev/null +++ b/.claude/agents/specs/business/README.md @@ -0,0 +1,64 @@ +# Business Agent 仕様 + +このディレクトリには、ビジネス系Agent(14種類)の仕様を配置します。 + +## Agent仕様ファイルのフォーマット + +各Agentの仕様は以下の構造で記述します: + +```markdown +# [Agent名] 仕様 + +## 概要 +Agentの役割とビジネス目標 + +## 入力 +- ユーザー要求(市場情報、目標KPI等) +- 必須パラメータ + +## 実行フェーズ +1. Phase 1: データ収集 +2. Phase 2: 分析 +3. Phase 3: 戦略立案 +4. ... + +## 出力 +- 生成するビジネスドキュメント +- レポート形式 + +## 品質基準 +- 検証項目 +- スコアリング基準(100点満点) + +## 実行例 +\`\`\`bash +miyabi agent run ai-entrepreneur --output business-plan.md +\`\`\` +``` + +## 📊 Business Agent一覧 + +### 戦略・企画系 +- **AIEntrepreneurAgent** - 包括的ビジネスプラン作成 +- **ProductConceptAgent** - 製品コンセプト設計 +- **ProductDesignAgent** - サービス詳細設計 +- **FunnelDesignAgent** - 導線設計 +- **PersonaAgent** - ターゲット顧客ペルソナ +- **SelfAnalysisAgent** - 自己分析 + +### マーケティング系 +- **MarketResearchAgent** - 市場調査 +- **MarketingAgent** - マーケティング戦略 +- **ContentCreationAgent** - コンテンツ制作 +- **SNSStrategyAgent** - SNS戦略 +- **YouTubeAgent** - YouTube運用最適化 + +### 営業・顧客管理系 +- **SalesAgent** - セールスプロセス最適化 +- **CRMAgent** - 顧客関係管理 +- **AnalyticsAgent** - データ分析・PDCA + +## 🔗 参考 + +- [SaaS Business Model Guide](https://github.com/ShunsukeHayashi/Miyabi/blob/main/docs/SAAS_BUSINESS_MODEL.md) +- [Business Agents User Guide](https://github.com/ShunsukeHayashi/Miyabi/blob/main/docs/BUSINESS_AGENTS_USER_GUIDE.md) diff --git a/.claude/agents/specs/business/coordinator.md b/.claude/agents/specs/business/coordinator.md new file mode 100644 index 0000000..df20c02 --- /dev/null +++ b/.claude/agents/specs/business/coordinator.md @@ -0,0 +1,33 @@ +# Coordinator Agent Spec + +## Role +タスク調整とAgent間連携を担当 + +## Responsibilities +- Issue分析と分解 +- Agent割り当て +- 進捗管理 +- 品質ゲートチェック + +## Tools +- GitHub (Issues, PRs) +- Agent invocation +- Read/Grep + +## Workflow +1. Issue受領 +2. 要件分析 +3. タスク分解 +4. Agent割り当て +5. 進捗監視 +6. PR作成 + +## Escalation +- ブロッカー発生 → User +- 優先度判断 → User +- スコープ変更 → User + +## Output +- タスク計画 +- 進捗レポート +- PR diff --git a/.claude/agents/specs/coding/README.md b/.claude/agents/specs/coding/README.md new file mode 100644 index 0000000..add8b2d --- /dev/null +++ b/.claude/agents/specs/coding/README.md @@ -0,0 +1,50 @@ +# Coding Agent 仕様 + +このディレクトリには、コーディング系Agent(7種類)の仕様を配置します。 + +## Agent仕様ファイルのフォーマット + +各Agentの仕様は以下の構造で記述します: + +```markdown +# [Agent名] 仕様 + +## 概要 +Agentの役割と責任範囲 + +## 入力 +- 受け取るTask/Issueの形式 +- 必須パラメータ + +## 処理フロー +1. ステップ1 +2. ステップ2 +3. ... + +## 出力 +- 生成する成果物 +- 更新するIssue/PR + +## エスカレーション条件 +- 上位Agentへのエスカレーション基準 +- エラーハンドリング + +## 実行例 +\`\`\`bash +miyabi agent run [agent-type] --issue 123 +\`\`\` +``` + +## 📋 テンプレート + +新しいAgent仕様を作成する場合、以下のテンプレートを使用してください: + +```bash +cp example-agent-spec.md my-custom-agent.md +``` + +## 🔗 参考 + +既存のAgent仕様は以下を参照: +- Miyabiプロジェクトの `.claude/agents/specs/coding/` ディレクトリ +- [Agent Operations Manual](https://github.com/ShunsukeHayashi/Miyabi/blob/main/docs/AGENT_OPERATIONS_MANUAL.md) diff --git a/.claude/agents/specs/coding/codegen-agent-example.md b/.claude/agents/specs/coding/codegen-agent-example.md new file mode 100644 index 0000000..3e84889 --- /dev/null +++ b/.claude/agents/specs/coding/codegen-agent-example.md @@ -0,0 +1,87 @@ +# CodeGenAgent Specification + +## 概要 +CodeGenAgentは、AI駆動のコード生成を担当するSpecialist Agentです。 +Claude Sonnet 4を使用して、型安全で高品質なRustコードを生成します。 + +## 入力 +- **Task**: CoordinatorAgentから受け取ったTask + - Task ID + - 依存関係(Dependencies) + - 生成すべきコードの仕様 +- **Issue Context**: 元のIssue情報 + +## 処理フロー + +### 1. 要件分析 +- Taskの内容を解析 +- 必要なモジュール・トレイト・構造体を特定 +- 既存コードとの整合性確認 + +### 2. コード生成 +```rust +// 例: 新しいAgent構造体の生成 +pub struct NewAgent { + config: AgentConfig, +} + +#[async_trait] +impl BaseAgent for NewAgent { + async fn execute(&self, task: Task) -> Result { + // Implementation + Ok(AgentResult::success(data)) + } +} +``` + +### 3. テスト生成 +```rust +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test] + async fn test_new_agent() { + let agent = NewAgent::new(config); + let result = agent.execute(task).await.unwrap(); + assert_eq!(result.status, ResultStatus::Success); + } +} +``` + +### 4. ドキュメント生成 +- Rustdocコメント(`///`)の追加 +- 使用例の記述 +- パラメータ・戻り値の説明 + +## 出力 +- **生成コード**: Rust source files +- **テスト**: `#[cfg(test)]` mod +- **ドキュメント**: Rustdoc comments +- **Commit**: Conventional Commits形式 + +## エスカレーション条件 +- 既存コードとの大規模なコンフリクト +- セキュリティ上の懸念(unsafe使用等) +- 外部依存の追加が必要 + +## 品質基準 +- ✅ Clippy警告0件 +- ✅ テストカバレッジ80%以上 +- ✅ すべてのpublic APIにRustdoc +- ✅ エラーハンドリング完備 + +## 実行例 +```bash +miyabi agent run codegen --issue 123 +``` + +または簡易コマンド: +```bash +miyabi work-on 123 +``` + +--- + +**このファイルはClaude Codeが参照する実際のAgent仕様です。** +**プロジェクト固有の要件に合わせてカスタマイズしてください。** diff --git a/.claude/agents/specs/coding/developer.md b/.claude/agents/specs/coding/developer.md new file mode 100644 index 0000000..d6a39b6 --- /dev/null +++ b/.claude/agents/specs/coding/developer.md @@ -0,0 +1,30 @@ +# Developer Agent Spec + +## Role +Rustコード実装を担当する開発Agent + +## Responsibilities +- 機能実装 +- バグ修正 +- コードレビュー対応 +- テスト作成 + +## Tools +- Read/Write/Edit +- Bash (cargo commands) +- Grep/Glob + +## Constraints +- Conventional Commits準拠 +- `cargo clippy` 警告ゼロ +- テストカバレッジ維持 + +## Escalation +- アーキテクチャ変更 → Architect Agent +- 要件不明確 → User +- 外部依存の問題 → User + +## Output +- 実装コード +- テストコード +- コミットメッセージ diff --git a/.claude/agents/specs/coding/reviewer.md b/.claude/agents/specs/coding/reviewer.md new file mode 100644 index 0000000..a5214a2 --- /dev/null +++ b/.claude/agents/specs/coding/reviewer.md @@ -0,0 +1,32 @@ +# Reviewer Agent Spec + +## Role +コードレビューを担当するAgent + +## Responsibilities +- コード品質チェック +- セキュリティレビュー +- パフォーマンス分析 +- ベストプラクティス適用 + +## Tools +- Read +- Grep/Glob +- Bash (lint/test) + +## Review Checklist +- [ ] 可読性 +- [ ] エラーハンドリング +- [ ] テストカバレッジ +- [ ] ドキュメント +- [ ] セキュリティ +- [ ] パフォーマンス + +## Escalation +- 重大なセキュリティ問題 → User +- アーキテクチャ懸念 → Architect Agent + +## Output +- レビューコメント +- 改善提案 +- 承認/要修正判定 diff --git a/.claude/agents/specs/coding/tester.md b/.claude/agents/specs/coding/tester.md new file mode 100644 index 0000000..b1153e1 --- /dev/null +++ b/.claude/agents/specs/coding/tester.md @@ -0,0 +1,35 @@ +# Tester Agent Spec + +## Role +テスト作成・実行を担当するAgent + +## Responsibilities +- ユニットテスト作成 +- 統合テスト作成 +- テスト実行・分析 +- カバレッジ向上 + +## Tools +- Read/Write/Edit +- Bash (cargo test) +- Grep/Glob + +## Test Types +- Unit tests +- Integration tests +- Property-based tests +- Benchmark tests + +## Constraints +- AAA pattern (Arrange-Act-Assert) +- 意味のあるテスト名 +- エッジケース網羅 + +## Escalation +- テスト環境の問題 → User +- 仕様不明確 → Developer Agent + +## Output +- テストコード +- カバレッジレポート +- 失敗分析 diff --git a/.claude/commands/build.md b/.claude/commands/build.md new file mode 100644 index 0000000..280ac36 --- /dev/null +++ b/.claude/commands/build.md @@ -0,0 +1,7 @@ +プロジェクトをビルドしてください。 + +```bash +cargo build --release +``` + +エラーがあれば修正してください。 diff --git a/.claude/commands/lint.md b/.claude/commands/lint.md new file mode 100644 index 0000000..e10a10e --- /dev/null +++ b/.claude/commands/lint.md @@ -0,0 +1,8 @@ +Lintを実行してコード品質をチェックしてください。 + +```bash +cargo clippy --all-targets -- -D warnings +cargo fmt --all --check +``` + +警告やエラーがあれば修正してください。 diff --git a/.claude/commands/review.md b/.claude/commands/review.md new file mode 100644 index 0000000..04593b3 --- /dev/null +++ b/.claude/commands/review.md @@ -0,0 +1,14 @@ +現在の変更をコードレビューしてください。 + +```bash +git diff +``` + +以下の観点でレビュー: +- コード品質 +- パフォーマンス +- セキュリティ +- エラーハンドリング +- テストカバレッジ + +改善点があれば提案してください。 diff --git a/.claude/commands/status.md b/.claude/commands/status.md new file mode 100644 index 0000000..292dfe3 --- /dev/null +++ b/.claude/commands/status.md @@ -0,0 +1,11 @@ +プロジェクトの状態を確認してください。 + +1. Gitステータス +2. Miyabiステータス +3. 未完了のTODO +4. 最近のコミット + +```bash +git status +miyabi status +``` diff --git a/.claude/commands/test.md b/.claude/commands/test.md new file mode 100644 index 0000000..e264902 --- /dev/null +++ b/.claude/commands/test.md @@ -0,0 +1,7 @@ +全てのテストを実行してください。 + +```bash +cargo test --all +``` + +失敗したテストがあれば原因を分析し、修正してください。 diff --git a/.claude/prompts/debug.md b/.claude/prompts/debug.md new file mode 100644 index 0000000..ebaf373 --- /dev/null +++ b/.claude/prompts/debug.md @@ -0,0 +1,31 @@ +# Debug Prompt + +問題をデバッグして修正してください。 + +## プロセス + +1. **問題の再現** - 症状の確認 +2. **原因調査** - ログ、スタックトレース分析 +3. **仮説立案** - 可能性のある原因 +4. **検証** - 仮説のテスト +5. **修正** - 根本原因の解決 +6. **回帰テスト** - 再発防止の確認 + +## デバッグツール + +```bash +# ログ確認 +RUST_LOG=debug cargo run + +# バックトレース +RUST_BACKTRACE=1 cargo run + +# テスト +cargo test -- --nocapture +``` + +## 出力 + +- 根本原因の説明 +- 修正コード +- 再発防止策 diff --git a/.claude/prompts/implement-feature.md b/.claude/prompts/implement-feature.md new file mode 100644 index 0000000..4d734d0 --- /dev/null +++ b/.claude/prompts/implement-feature.md @@ -0,0 +1,30 @@ +# Feature Implementation Prompt + +新機能を実装してください。 + +## プロセス + +1. **要件理解** - 仕様の確認と質問 +2. **設計** - アーキテクチャ決定 +3. **実装** - コード作成 +4. **テスト** - ユニット/統合テスト +5. **ドキュメント** - 必要に応じて + +## コーディング規約 + +### Rust +- `cargo fmt` でフォーマット +- `cargo clippy` 警告ゼロ +- Result型でエラーハンドリング +- 適切なドキュメントコメント + +### 構造 +- 単一責任の関数/構造体 +- 適切な抽象化レベル +- テスト可能な設計 + +## 出力 + +- 実装コード +- テストコード +- 使用例 diff --git a/.claude/prompts/refactor.md b/.claude/prompts/refactor.md new file mode 100644 index 0000000..5e8a3a0 --- /dev/null +++ b/.claude/prompts/refactor.md @@ -0,0 +1,22 @@ +# Refactoring Prompt + +対象コードをリファクタリングしてください。 + +## 方針 + +1. **可読性向上** - 命名、構造の改善 +2. **DRY原則** - 重複コードの排除 +3. **SOLID原則** - 責務の分離 +4. **パフォーマンス** - 不要な処理の削除 + +## 制約 + +- 既存の機能を維持 +- テストが通ること +- 破壊的変更を避ける + +## 出力 + +- 変更内容の説明 +- 改善点のリスト +- 必要に応じてテストの追加 diff --git a/.claude/templates/issue.md b/.claude/templates/issue.md new file mode 100644 index 0000000..e201af6 --- /dev/null +++ b/.claude/templates/issue.md @@ -0,0 +1,24 @@ +# Issue Template + +## Title +[type]: Short description + +## Description +明確で簡潔な説明 + +## Acceptance Criteria +- [ ] Criterion 1 +- [ ] Criterion 2 +- [ ] Criterion 3 + +## Technical Notes +実装に関する技術的な注意点 + +## Labels +- `type:feature` / `type:bug` / `type:refactor` +- `priority:high` / `priority:medium` / `priority:low` +- `component:tui` / `component:cli` / `component:core` + +## Related +- Related Issue: #xxx +- Related PR: #xxx diff --git a/.claude/templates/pr.md b/.claude/templates/pr.md new file mode 100644 index 0000000..b426ae1 --- /dev/null +++ b/.claude/templates/pr.md @@ -0,0 +1,33 @@ +# Pull Request Template + +## Summary +変更内容の要約(1-3行) + +## Changes +- Change 1 +- Change 2 +- Change 3 + +## Type +- [ ] Feature +- [ ] Bug Fix +- [ ] Refactor +- [ ] Documentation +- [ ] Test + +## Testing +- [ ] Unit tests added/updated +- [ ] Integration tests added/updated +- [ ] Manual testing performed + +## Checklist +- [ ] `cargo fmt` passed +- [ ] `cargo clippy` passed +- [ ] `cargo test` passed +- [ ] Documentation updated + +## Screenshots +(if applicable) + +## Related Issues +Closes #xxx diff --git a/.claude/templates/rust-module.md b/.claude/templates/rust-module.md new file mode 100644 index 0000000..673c6ab --- /dev/null +++ b/.claude/templates/rust-module.md @@ -0,0 +1,52 @@ +# Rust Module Template + +```rust +//! Module description +//! +//! # Examples +//! +//! ```rust +//! use crate::module_name; +//! +//! // Example usage +//! ``` + +use anyhow::Result; + +/// Description +pub struct StructName { + /// Field description + field: Type, +} + +impl StructName { + /// Creates a new instance + pub fn new() -> Self { + Self { + field: Default::default(), + } + } + + /// Method description + pub fn method(&self) -> Result<()> { + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_example() { + // Arrange + let instance = StructName::new(); + + // Act + let result = instance.method(); + + // Assert + assert!(result.is_ok()); + } +} +``` diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..43ce0a1 --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +# GitHub Configuration +# Get token at: https://github.com/settings/tokens +# Required scopes: repo, workflow, admin:org (for Projects) +GITHUB_TOKEN=ghp_your_github_token_here + +# Repository Information +# Format: owner/repo (e.g., YourUsername/my-project) +REPOSITORY=ShunsukeHayashi/miyabi-cli-standalone + +# Anthropic API Key (optional for local development) +# Get key at: https://console.anthropic.com/ +# Required for running agents locally +ANTHROPIC_API_KEY=sk-ant-your_anthropic_key_here + +# Device Identifier (for logging) +DEVICE_IDENTIFIER=MyComputer + +# Agent Configuration +LOG_DIRECTORY=.ai/logs +REPORT_DIRECTORY=.ai/parallel-reports +DEFAULT_CONCURRENCY=2 + +# Development Options +USE_TASK_TOOL=false +USE_WORKTREE=false diff --git a/.gitignore b/.gitignore index 9a5aced..52b3061 100644 --- a/.gitignore +++ b/.gitignore @@ -137,3 +137,36 @@ dist # Vite logs files vite.config.js.timestamp-* vite.config.ts.timestamp-* + +# Agentic OS +# Dependencies +node_modules/ +package-lock.json + +# Build output +dist/ +*.tsbuildinfo + +# Environment variables +.env +.env.local + +# IDE +.vscode/ +.idea/ + +# OS +.DS_Store +Thumbs.db + +# Test coverage +coverage/ + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.worktrees/ +.ai/ +.env diff --git a/.miyabi.yml b/.miyabi.yml new file mode 100644 index 0000000..61cbfa8 --- /dev/null +++ b/.miyabi.yml @@ -0,0 +1,21 @@ +# Miyabi Configuration +project_name: miyabi-cli-standalone +version: "0.1.0" + +# GitHub settings (use environment variables for sensitive data) +# github_token: ${{ GITHUB_TOKEN }} + +# Agent settings +agents: + enabled: true + use_worktree: true + worktree_base_path: ".worktrees" + +# Logging +logging: + level: info + directory: "./logs" + +# Reporting +reporting: + directory: "./reports" diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..fe12968 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,119 @@ +ターゲットとする機能のベースライン: codex cli Ref_URL=https://github.com/openai/codex.git + +ターゲットとする機能をベースに拡張すべき機能を有するPJ: /Users/shunsuke/dev/01-miyabi/_core/miyabi-private + +=== + + +# miyabi-cli-standalone + +**Miyabi CLI Standalone** - 軽量スタンドアロン版 Miyabi CLI/TUI + +## プロジェクト概要 + +Miyabi本体から独立した軽量CLIツール。TUI (Terminal User Interface) とCLI機能を提供。 + +## 技術スタック + +- **言語**: Rust 2021 Edition, TypeScript +- **TUIフレームワーク**: Ratatui + Crossterm +- **CLIフレームワーク**: Clap +- **非同期ランタイム**: Tokio + +## ディレクトリ構造 + +``` +miyabi-cli-standalone/ +├── crates/ +│ ├── miyabi-cli/ # CLI実装 +│ ├── miyabi-core/ # コアライブラリ +│ └── miyabi-tui/ # TUI実装 +├── src/ # TypeScriptソース +│ └── index.ts +├── tests/ # テスト +├── .claude/ # Claude Code設定 +│ ├── agents/ # Agent仕様 +│ ├── commands/ # カスタムコマンド +│ └── prompts/ # プロンプト +├── docs/ # ドキュメント +├── logs/ # ログ +├── reports/ # レポート +├── Cargo.toml # Rustワークスペース設定 +├── package.json # Node.js設定 +└── .miyabi.yml # Miyabi設定 +``` + +## 開発コマンド + +### Rust + +```bash +# ビルド +cargo build --release + +# テスト +cargo test --all + +# Lint +cargo clippy --all-targets -- -D warnings + +# フォーマット +cargo fmt --all +``` + +### TypeScript + +```bash +# インストール +npm install + +# ビルド +npm run build + +# Lint +npm run lint +``` + +## コミット規約 + +Conventional Commits準拠: +- `feat:` - 新機能 +- `fix:` - バグ修正 +- `refactor:` - リファクタリング +- `docs:` - ドキュメント +- `test:` - テスト +- `chore:` - その他 + +## 環境変数 + +```bash +GITHUB_TOKEN=ghp_xxx # GitHub PAT +RUST_LOG=info # ログレベル +RUST_BACKTRACE=1 # バックトレース +``` + +## Miyabi統合 + +```bash +# ステータス確認 +miyabi status + +# Agent実行 +miyabi agent run coordinator --issue <番号> +``` + +## コーディング規約 + +### Rust +- `cargo fmt` でフォーマット +- `cargo clippy` 警告ゼロ +- Result型でエラーハンドリング +- async/awaitでの非同期処理 + +### TypeScript +- ESLint設定に従う +- 厳格な型付け + +--- + +**このファイルはClaude Codeが自動参照します。** diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3f389e4 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1463 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cc" +version = "1.2.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chrono" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "compact_str" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "convert_case" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "crossterm" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +dependencies = [ + "bitflags", + "crossterm_winapi", + "mio", + "parking_lot", + "rustix 0.38.44", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" +dependencies = [ + "bitflags", + "crossterm_winapi", + "derive_more", + "document-features", + "futures-core", + "mio", + "parking_lot", + "rustix 1.1.2", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "iana-time-zone" +version = "0.1.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "instability" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" +dependencies = [ + "darling", + "indoc", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "mio" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "miyabi-cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "crossterm 0.29.0", + "miyabi-core", + "miyabi-tui", + "ratatui", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "miyabi-core" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "uuid", +] + +[[package]] +name = "miyabi-tui" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "crossterm 0.29.0", + "futures", + "miyabi-core", + "ratatui", + "serde", + "serde_json", + "textwrap", + "thiserror", + "tokio", + "unicode-width 0.2.0", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "ratatui" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +dependencies = [ + "bitflags", + "cassowary", + "compact_str", + "crossterm 0.28.1", + "indoc", + "instability", + "itertools", + "lru", + "paste", + "strum", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.0", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width 0.2.0", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-truncate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" +dependencies = [ + "itertools", + "unicode-segmentation", + "unicode-width 0.1.14", +] + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +dependencies = [ + "getrandom", + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e385310 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,56 @@ +[workspace] +resolver = "2" +members = [ + "crates/miyabi-cli", + "crates/miyabi-tui", + "crates/miyabi-core", +] + +[workspace.package] +version = "0.1.0" +edition = "2021" +rust-version = "1.75" +authors = ["Miyabi Team"] +license = "MIT" +repository = "https://github.com/ShunsukeHayashi/miyabi-cli-standalone" +homepage = "https://github.com/ShunsukeHayashi/miyabi-cli-standalone" +description = "Miyabi - Autonomous AI Development Framework" +keywords = ["ai", "cli", "tui", "autonomous", "development"] +categories = ["command-line-utilities", "development-tools"] + +[workspace.dependencies] +# Async Runtime +tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-std", "sync", "process", "signal"] } +futures = "0.3" + +# TUI Framework +ratatui = { version = "0.29.0", features = [ + "scrolling-regions", + "unstable-backend-writer", + "unstable-rendered-line-info", + "unstable-widget-ref", +] } +crossterm = { version = "0.29.0", features = ["bracketed-paste", "event-stream"] } + +# Text Processing +textwrap = "0.16" +unicode-width = "0.2" + +# CLI +clap = { version = "4", features = ["derive"] } + +# Error Handling +anyhow = "1" +thiserror = "2" + +# Serialization +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +# Logging +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } + +# Utilities +chrono = { version = "0.4", features = ["serde"] } +uuid = { version = "1", features = ["v4", "serde"] } diff --git a/GOALS.md b/GOALS.md new file mode 100644 index 0000000..0840e02 --- /dev/null +++ b/GOALS.md @@ -0,0 +1,188 @@ +# Miyabi CLI - Development Goals + +## Reference Projects + +### Baseline +- **Codex CLI**: https://github.com/openai/codex.git + +### Extension Source +- **Miyabi Private**: /Users/shunsuke/dev/01-miyabi/_core/miyabi-private + +--- + +## Mission +**Codex CLI同等の品質を持つ、Production-Ready Miyabi CLIを構築する** + +--- + +## Gap Analysis Summary + +| Metric | Codex CLI | Current Miyabi | Target | +|--------|-----------|----------------|--------| +| Total Lines | 20,969 | 1,200 | 15,000+ | +| Files | 50+ | 10 | 40+ | +| Features | Complete | Basic | Full Parity | + +--- + +## Phase 1: Core TUI Foundation ✅ COMPLETED +**Status**: Done (1,200 lines) + +- [x] Cargo workspace setup +- [x] wrapping.rs - Text wrapping with textwrap +- [x] history_cell.rs - Card design UI +- [x] markdown_render.rs - Basic markdown +- [x] app.rs - Main TUI loop +- [x] event.rs - Event handling + +--- + +## Phase 2: Advanced Text Rendering 🔄 IN PROGRESS +**Target**: +1,500 lines + +### 2.1 markdown_stream.rs (690 lines) +- [ ] Streaming markdown rendering +- [ ] Progressive display during generation +- [ ] Cursor position tracking +- [ ] Partial code block handling + +### 2.2 diff_render.rs (715 lines) +- [ ] Git diff visualization +- [ ] Syntax highlighting for diffs +- [ ] Line number display +- [ ] Add/Remove/Change indicators + +--- + +## Phase 3: Chat Composer Separation +**Target**: +4,000 lines + +### 3.1 chat_composer.rs (3,938 lines) +- [ ] Separate input handling from main app +- [ ] Multi-line input support +- [ ] Command history +- [ ] Auto-completion +- [ ] Syntax highlighting in input + +### 3.2 textarea.rs (2,213 lines) +- [ ] Full-featured text area widget +- [ ] Selection support +- [ ] Copy/paste +- [ ] Undo/redo + +--- + +## Phase 4: Approval & Feedback +**Target**: +1,500 lines + +### 4.1 approval_overlay.rs (656 lines) +- [ ] Tool execution approval UI +- [ ] Y/N/Always/Never options +- [ ] Risk level display +- [ ] Preview of changes + +### 4.2 feedback_view.rs (555 lines) +- [ ] User feedback collection +- [ ] Rating system +- [ ] Comment input + +--- + +## Phase 5: Advanced Navigation +**Target**: +2,500 lines + +### 5.1 resume_picker.rs (1,580 lines) +- [ ] Session resume selection +- [ ] Conversation history browser +- [ ] Search functionality +- [ ] Preview pane + +### 5.2 pager_overlay.rs (913 lines) +- [ ] Full-screen content viewer +- [ ] Scroll and search +- [ ] Jump to line +- [ ] Keyboard shortcuts + +--- + +## Phase 6: LLM Integration +**Target**: +2,000 lines + +### 6.1 Claude API Integration +- [ ] Anthropic API client +- [ ] Streaming responses +- [ ] Token counting +- [ ] Rate limiting +- [ ] Error handling + +### 6.2 Conversation Management +- [ ] Context window management +- [ ] Message history +- [ ] System prompts +- [ ] Tool definitions + +--- + +## Phase 7: Tool Execution +**Target**: +2,500 lines + +### 7.1 A2A Bridge Integration +- [ ] Tool registry +- [ ] Execution engine +- [ ] Result formatting +- [ ] Error recovery + +### 7.2 Built-in Tools +- [ ] File operations (Read, Write, Edit) +- [ ] Bash execution +- [ ] Search (Glob, Grep) +- [ ] Web fetch + +--- + +## Success Criteria + +### Functional Requirements +- [ ] Real Claude API conversations +- [ ] Tool execution with approval +- [ ] Session persistence and resume +- [ ] Markdown rendering with streaming +- [ ] Full keyboard navigation + +### Quality Requirements +- [ ] 15,000+ lines of code +- [ ] 90%+ test coverage +- [ ] < 100ms response latency +- [ ] Memory efficient (< 100MB) +- [ ] Cross-platform (macOS, Linux) + +### User Experience +- [ ] Intuitive keyboard shortcuts +- [ ] Clear visual feedback +- [ ] Smooth scrolling +- [ ] Proper error messages +- [ ] Help system + +--- + +## Timeline + +| Phase | Duration | Deliverable | +|-------|----------|-------------| +| Phase 1 | ✅ Done | Core TUI | +| Phase 2 | 1 week | Streaming Markdown | +| Phase 3 | 2 weeks | Chat Composer | +| Phase 4 | 1 week | Approval System | +| Phase 5 | 1 week | Navigation | +| Phase 6 | 2 weeks | LLM Integration | +| Phase 7 | 2 weeks | Tool Execution | + +**Total**: ~10 weeks to Production-Ready + +--- + +## Next Action + +**Phase 2.1: Implement markdown_stream.rs** + +Create streaming markdown renderer that can display partial content during LLM generation. diff --git a/crates/miyabi-cli/Cargo.toml b/crates/miyabi-cli/Cargo.toml new file mode 100644 index 0000000..2e0a286 --- /dev/null +++ b/crates/miyabi-cli/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "miyabi-cli" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +description = "Miyabi CLI - Main command-line interface" + +[[bin]] +name = "miyabi" +path = "src/main.rs" + +[dependencies] +# Workspace crates +miyabi-core = { path = "../miyabi-core" } +miyabi-tui = { path = "../miyabi-tui" } + +# CLI +clap = { workspace = true } + +# TUI Framework +ratatui = { workspace = true } +crossterm = { workspace = true } + +# Async Runtime +tokio = { workspace = true } + +# Error Handling +anyhow = { workspace = true } + +# Logging +tracing = { workspace = true } +tracing-subscriber = { workspace = true } diff --git a/crates/miyabi-cli/src/main.rs b/crates/miyabi-cli/src/main.rs new file mode 100644 index 0000000..1cf7a81 --- /dev/null +++ b/crates/miyabi-cli/src/main.rs @@ -0,0 +1,70 @@ +//! Miyabi CLI - Main entry point + +use clap::{Parser, Subcommand}; +use tracing_subscriber::EnvFilter; + +#[derive(Parser)] +#[command(name = "miyabi")] +#[command(author, version, about = "Miyabi - Autonomous AI Development Framework", long_about = None)] +struct Cli { + #[command(subcommand)] + command: Option, +} + +#[derive(Subcommand)] +enum Commands { + /// Start the TUI interface + Tui, + /// Show status + Status, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // Initialize logging + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let cli = Cli::parse(); + + match cli.command { + Some(Commands::Tui) | None => { + // Run TUI + use miyabi_tui::App; + use crossterm::{ + event::{DisableMouseCapture, EnableMouseCapture}, + execute, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, + }; + use ratatui::prelude::*; + use std::io; + + enable_raw_mode()?; + let mut stdout = io::stdout(); + execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; + let backend = CrosstermBackend::new(stdout); + let mut terminal = Terminal::new(backend)?; + + let mut app = App::new(); + let res = app.run(&mut terminal).await; + + disable_raw_mode()?; + execute!( + terminal.backend_mut(), + LeaveAlternateScreen, + DisableMouseCapture + )?; + terminal.show_cursor()?; + + if let Err(err) = res { + eprintln!("Error: {}", err); + } + } + Some(Commands::Status) => { + println!("Miyabi Status: Ready"); + } + } + + Ok(()) +} diff --git a/crates/miyabi-core/Cargo.toml b/crates/miyabi-core/Cargo.toml new file mode 100644 index 0000000..b0fd5f3 --- /dev/null +++ b/crates/miyabi-core/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "miyabi-core" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +description = "Miyabi Core - Shared types and utilities" + +[dependencies] +tokio = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +anyhow = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } +chrono = { workspace = true } +uuid = { workspace = true } diff --git a/crates/miyabi-core/src/error.rs b/crates/miyabi-core/src/error.rs new file mode 100644 index 0000000..ea744e5 --- /dev/null +++ b/crates/miyabi-core/src/error.rs @@ -0,0 +1,23 @@ +//! Error types for Miyabi + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + + #[error("JSON error: {0}")] + Json(#[from] serde_json::Error), + + #[error("Configuration error: {0}")] + Config(String), + + #[error("Agent error: {0}")] + Agent(String), + + #[error("{0}")] + Other(String), +} + +pub type Result = std::result::Result; diff --git a/crates/miyabi-core/src/lib.rs b/crates/miyabi-core/src/lib.rs new file mode 100644 index 0000000..e7ed082 --- /dev/null +++ b/crates/miyabi-core/src/lib.rs @@ -0,0 +1,9 @@ +//! Miyabi Core - Shared types and utilities +//! +//! This crate provides core types and utilities shared across the Miyabi framework. + +pub mod error; +pub mod types; + +pub use error::Error; +pub use types::*; diff --git a/crates/miyabi-core/src/types.rs b/crates/miyabi-core/src/types.rs new file mode 100644 index 0000000..466854c --- /dev/null +++ b/crates/miyabi-core/src/types.rs @@ -0,0 +1,77 @@ +//! Core types for Miyabi + +use serde::{Deserialize, Serialize}; +use chrono::{DateTime, Utc}; + +/// Message role in a conversation +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum Role { + User, + Assistant, + System, + Tool, +} + +/// Chat message +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ChatMessage { + pub role: Role, + pub content: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_call_id: Option, + pub timestamp: DateTime, +} + +impl ChatMessage { + pub fn user(content: impl Into) -> Self { + Self { + role: Role::User, + content: content.into(), + tool_name: None, + tool_call_id: None, + timestamp: Utc::now(), + } + } + + pub fn assistant(content: impl Into) -> Self { + Self { + role: Role::Assistant, + content: content.into(), + tool_name: None, + tool_call_id: None, + timestamp: Utc::now(), + } + } + + pub fn system(content: impl Into) -> Self { + Self { + role: Role::System, + content: content.into(), + tool_name: None, + tool_call_id: None, + timestamp: Utc::now(), + } + } + + pub fn tool(name: impl Into, content: impl Into, call_id: impl Into) -> Self { + Self { + role: Role::Tool, + content: content.into(), + tool_name: Some(name.into()), + tool_call_id: Some(call_id.into()), + timestamp: Utc::now(), + } + } +} + +/// Tool execution result +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolResult { + pub name: String, + pub content: String, + pub success: bool, + pub execution_time_ms: u64, +} diff --git a/crates/miyabi-tui/Cargo.toml b/crates/miyabi-tui/Cargo.toml new file mode 100644 index 0000000..24bccdb --- /dev/null +++ b/crates/miyabi-tui/Cargo.toml @@ -0,0 +1,45 @@ +[package] +name = "miyabi-tui" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +homepage.workspace = true +description = "Miyabi TUI - Terminal User Interface following Codex patterns" + +[[bin]] +name = "miyabi-tui" +path = "src/main.rs" + +[lib] +name = "miyabi_tui" +path = "src/lib.rs" + +[dependencies] +# Workspace dependencies +miyabi-core = { path = "../miyabi-core" } + +# TUI Framework +ratatui = { workspace = true } +crossterm = { workspace = true } + +# Text Processing +textwrap = { workspace = true } +unicode-width = { workspace = true } + +# Async Runtime +tokio = { workspace = true } +futures = { workspace = true } + +# Error Handling +anyhow = { workspace = true } +thiserror = { workspace = true } + +# Serialization +serde = { workspace = true } +serde_json = { workspace = true } + +# Utilities +chrono = { workspace = true } diff --git a/crates/miyabi-tui/src/app.rs b/crates/miyabi-tui/src/app.rs new file mode 100644 index 0000000..a6da0bc --- /dev/null +++ b/crates/miyabi-tui/src/app.rs @@ -0,0 +1,223 @@ +//! Main TUI Application + +use ratatui::{ + layout::{Constraint, Direction, Layout, Rect}, + style::{Color, Modifier, Style}, + text::{Line, Span}, + widgets::{Block, Borders, Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState}, + Frame, +}; +use crossterm::event::{KeyCode, KeyModifiers}; + +use crate::event::{Event, EventHandler}; +use crate::history_cell::{ + HistoryCell, UserMessageCell, AssistantMessageCell, SystemMessageCell, SystemMessageType, +}; + +/// Main application state +pub struct App { + /// Whether the app should quit + pub should_quit: bool, + /// Current input buffer + pub input: String, + /// Chat history cells + pub cells: Vec>, + /// Scroll position + pub scroll: u16, + /// Maximum scroll + pub max_scroll: u16, +} + +impl App { + /// Create a new app + pub fn new() -> Self { + let timestamp = chrono::Local::now().format("%H:%M").to_string(); + + let welcome_cell: Box = Box::new(SystemMessageCell { + content: "Welcome to Miyabi CLI! Type your message and press Enter.".to_string(), + timestamp: timestamp.clone(), + message_type: SystemMessageType::Info, + }); + + Self { + should_quit: false, + input: String::new(), + cells: vec![welcome_cell], + scroll: 0, + max_scroll: 0, + } + } + + /// Run the main app loop + pub async fn run( + &mut self, + terminal: &mut ratatui::Terminal, + ) -> anyhow::Result<()> { + let mut events = EventHandler::new(100); + + loop { + terminal.draw(|f| self.draw(f))?; + + if let Some(event) = events.next().await { + match event { + Event::Key(key) => { + if key.modifiers.contains(KeyModifiers::CONTROL) && key.code == KeyCode::Char('c') { + self.should_quit = true; + } else { + match key.code { + KeyCode::Enter => { + if !self.input.is_empty() { + self.send_message(); + } + } + KeyCode::Char(c) => { + self.input.push(c); + } + KeyCode::Backspace => { + self.input.pop(); + } + KeyCode::Esc => { + self.should_quit = true; + } + KeyCode::Up => { + self.scroll = self.scroll.saturating_sub(1); + } + KeyCode::Down => { + if self.scroll < self.max_scroll { + self.scroll += 1; + } + } + KeyCode::PageUp => { + self.scroll = self.scroll.saturating_sub(10); + } + KeyCode::PageDown => { + self.scroll = (self.scroll + 10).min(self.max_scroll); + } + _ => {} + } + } + } + Event::Resize(_, _) => {} + Event::Tick => {} + Event::Mouse(_) => {} + } + } + + if self.should_quit { + break; + } + } + + Ok(()) + } + + /// Draw the UI + fn draw(&mut self, frame: &mut Frame) { + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(3), // Header + Constraint::Min(1), // Chat area + Constraint::Length(3), // Input + ]) + .split(frame.area()); + + self.draw_header(frame, chunks[0]); + self.draw_chat(frame, chunks[1]); + self.draw_input(frame, chunks[2]); + } + + fn draw_header(&self, frame: &mut Frame, area: Rect) { + let title = Paragraph::new(Line::from(vec![ + Span::styled(" Miyabi ", Style::default().fg(Color::Magenta).add_modifier(Modifier::BOLD)), + Span::styled("CLI", Style::default().fg(Color::Cyan)), + ])) + .block(Block::default().borders(Borders::ALL).border_style(Style::default().fg(Color::Rgb(86, 95, 137)))); + + frame.render_widget(title, area); + } + + fn draw_chat(&mut self, frame: &mut Frame, area: Rect) { + let block = Block::default() + .borders(Borders::ALL) + .border_style(Style::default().fg(Color::Rgb(86, 95, 137))) + .title(Span::styled(" Chat ", Style::default().fg(Color::Rgb(192, 202, 245)))); + + let inner = block.inner(area); + frame.render_widget(block, area); + + // Render cells + let mut lines: Vec> = Vec::new(); + let width = inner.width.saturating_sub(4); + + for cell in &self.cells { + lines.push(Line::from("")); + lines.extend(cell.render(width)); + } + + let total_lines = lines.len() as u16; + self.max_scroll = total_lines.saturating_sub(inner.height); + + let paragraph = Paragraph::new(lines) + .scroll((self.scroll, 0)); + + frame.render_widget(paragraph, inner); + + // Scrollbar + if self.max_scroll > 0 { + let scrollbar = Scrollbar::default() + .orientation(ScrollbarOrientation::VerticalRight) + .thumb_style(Style::default().fg(Color::Magenta)); + + let mut scrollbar_state = ScrollbarState::new(self.max_scroll as usize) + .position(self.scroll as usize); + + frame.render_stateful_widget(scrollbar, area, &mut scrollbar_state); + } + } + + fn draw_input(&self, frame: &mut Frame, area: Rect) { + let input = Paragraph::new(Line::from(vec![ + Span::styled("› ", Style::default().fg(Color::Cyan)), + Span::raw(self.input.clone()), + Span::styled("█", Style::default().fg(Color::Cyan)), + ])) + .block( + Block::default() + .borders(Borders::ALL) + .border_style(Style::default().fg(Color::Rgb(86, 95, 137))) + .title(Span::styled(" Input ", Style::default().fg(Color::Rgb(192, 202, 245)))), + ); + + frame.render_widget(input, area); + } + + /// Send a message + fn send_message(&mut self) { + let message = std::mem::take(&mut self.input); + let timestamp = chrono::Local::now().format("%H:%M").to_string(); + + // Add user message + self.cells.push(Box::new(UserMessageCell { + content: message.clone(), + timestamp: timestamp.clone(), + })); + + // Add demo assistant response + let response = format!("You said: {}\n\nThis is a **demo response** with `markdown` support!", message); + self.cells.push(Box::new(AssistantMessageCell { + content: response, + timestamp, + streaming: false, + })); + + // Auto-scroll to bottom + self.scroll = self.max_scroll; + } +} + +impl Default for App { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/miyabi-tui/src/event.rs b/crates/miyabi-tui/src/event.rs new file mode 100644 index 0000000..8b9d0fa --- /dev/null +++ b/crates/miyabi-tui/src/event.rs @@ -0,0 +1,75 @@ +//! Event handling for the TUI + +use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, MouseEvent}; +use std::time::Duration; +use tokio::sync::mpsc; + +/// Terminal events +#[derive(Debug, Clone)] +pub enum Event { + /// Terminal tick + Tick, + /// Key press + Key(KeyEvent), + /// Mouse event + Mouse(MouseEvent), + /// Terminal resize + Resize(u16, u16), +} + +/// Event handler for terminal events +pub struct EventHandler { + /// Event sender + #[allow(dead_code)] + sender: mpsc::UnboundedSender, + /// Event receiver + receiver: mpsc::UnboundedReceiver, +} + +impl EventHandler { + /// Create a new event handler with the given tick rate + pub fn new(tick_rate: u64) -> Self { + let tick_rate = Duration::from_millis(tick_rate); + let (sender, receiver) = mpsc::unbounded_channel(); + + let sender_clone = sender.clone(); + + // Spawn event polling task + tokio::spawn(async move { + loop { + if event::poll(tick_rate).unwrap_or(false) { + match event::read() { + Ok(CrosstermEvent::Key(key)) => { + if sender_clone.send(Event::Key(key)).is_err() { + break; + } + } + Ok(CrosstermEvent::Mouse(mouse)) => { + if sender_clone.send(Event::Mouse(mouse)).is_err() { + break; + } + } + Ok(CrosstermEvent::Resize(w, h)) => { + if sender_clone.send(Event::Resize(w, h)).is_err() { + break; + } + } + _ => {} + } + } else { + // Send tick event + if sender_clone.send(Event::Tick).is_err() { + break; + } + } + } + }); + + Self { sender, receiver } + } + + /// Get the next event + pub async fn next(&mut self) -> Option { + self.receiver.recv().await + } +} diff --git a/crates/miyabi-tui/src/history_cell.rs b/crates/miyabi-tui/src/history_cell.rs new file mode 100644 index 0000000..39152c0 --- /dev/null +++ b/crates/miyabi-tui/src/history_cell.rs @@ -0,0 +1,272 @@ +//! History Cell Abstraction - Premium Card Design +//! +//! Following OpenAI Codex TUI patterns with functional colors: +//! - Cyan: User input, tool names +//! - Green: Success +//! - Red: Errors +//! - Magenta: Assistant/Miyabi brand +//! - Dim: Secondary, timestamps + +use ratatui::{ + style::{Color, Modifier, Style}, + text::{Line, Span}, +}; + +use crate::markdown_render::MarkdownRenderer; +use crate::wrapping::wrap_text; + +/// Trait for renderable history items +pub trait HistoryCell: Send + Sync { + fn render(&self, width: u16) -> Vec>; + fn timestamp(&self) -> &str; + fn is_streaming(&self) -> bool { + false + } +} + +/// User message cell - Cyan accented card +pub struct UserMessageCell { + pub content: String, + pub timestamp: String, +} + +impl HistoryCell for UserMessageCell { + fn render(&self, width: u16) -> Vec> { + let mut lines = Vec::new(); + let inner_width = (width as usize).saturating_sub(6).min(70); + let border = "─".repeat(inner_width); + + // Top border + lines.push(Line::from(vec![ + Span::styled("┌", Style::default().fg(Color::Cyan)), + Span::styled(border.clone(), Style::default().fg(Color::Cyan)), + Span::styled("┐", Style::default().fg(Color::Cyan)), + ])); + + // Header + lines.push(Line::from(vec![ + Span::styled("│ ", Style::default().fg(Color::Cyan)), + Span::styled("You", Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD)), + Span::styled( + format!("{:>width$}", self.timestamp, width = inner_width - 4), + Style::default().add_modifier(Modifier::DIM) + ), + Span::styled(" │", Style::default().fg(Color::Cyan)), + ])); + + // Content with proper text wrapping + let content_width = inner_width.saturating_sub(2); + for line in self.content.lines() { + let wrapped = wrap_text(line, content_width); + for wrapped_line in wrapped { + let content_str: String = wrapped_line.spans.iter() + .map(|s| s.content.as_ref()) + .collect(); + let padded = format!("{: &str { + &self.timestamp + } +} + +/// Assistant message cell - Magenta accented card with markdown +pub struct AssistantMessageCell { + pub content: String, + pub timestamp: String, + pub streaming: bool, +} + +impl HistoryCell for AssistantMessageCell { + fn render(&self, width: u16) -> Vec> { + let mut lines = Vec::new(); + let inner_width = (width as usize).saturating_sub(6).min(70); + let border = "─".repeat(inner_width); + + // Top border + lines.push(Line::from(vec![ + Span::styled("┌", Style::default().fg(Color::Magenta)), + Span::styled(border.clone(), Style::default().fg(Color::Magenta)), + Span::styled("┐", Style::default().fg(Color::Magenta)), + ])); + + // Header with streaming indicator + let header_text = if self.streaming { "Assistant ●" } else { "Assistant" }; + let header_style = Style::default().fg(Color::Magenta).add_modifier(Modifier::BOLD); + + lines.push(Line::from(vec![ + Span::styled("│ ", Style::default().fg(Color::Magenta)), + Span::styled(header_text, header_style), + Span::styled( + format!("{:>width$}", self.timestamp, width = inner_width - header_text.len() - 1), + Style::default().add_modifier(Modifier::DIM) + ), + Span::styled(" │", Style::default().fg(Color::Magenta)), + ])); + + // Markdown rendered content + let renderer = MarkdownRenderer::new(); + let md_lines = renderer.render(&self.content); + + if md_lines.is_empty() && self.streaming { + lines.push(Line::from(vec![ + Span::styled("│ ", Style::default().fg(Color::Magenta)), + Span::styled("...", Style::default().add_modifier(Modifier::DIM)), + Span::styled( + format!("{:>width$}", "", width = inner_width - 5), + Style::default() + ), + Span::styled(" │", Style::default().fg(Color::Magenta)), + ])); + } else { + for md_line in md_lines { + let mut content_spans = vec![ + Span::styled("│ ", Style::default().fg(Color::Magenta)), + ]; + content_spans.extend(md_line.spans); + content_spans.push(Span::styled(" │", Style::default().fg(Color::Magenta))); + lines.push(Line::from(content_spans)); + } + } + + // Bottom border + lines.push(Line::from(vec![ + Span::styled("└", Style::default().fg(Color::Magenta)), + Span::styled(border, Style::default().fg(Color::Magenta)), + Span::styled("┘", Style::default().fg(Color::Magenta)), + ])); + + lines + } + + fn timestamp(&self) -> &str { + &self.timestamp + } + + fn is_streaming(&self) -> bool { + self.streaming + } +} + +/// Tool result cell - Green/Red based on success +pub struct ToolResultCell { + pub tool_name: String, + pub content: String, + pub timestamp: String, + pub execution_time_ms: u64, + pub success: bool, +} + +impl HistoryCell for ToolResultCell { + fn render(&self, width: u16) -> Vec> { + let mut lines = Vec::new(); + let inner_width = (width as usize).saturating_sub(8).min(68); + let border = "═".repeat(inner_width); + let border_color = if self.success { Color::Green } else { Color::Red }; + + // Top border (double line for tool) + lines.push(Line::from(vec![ + Span::styled(" ╔", Style::default().fg(border_color)), + Span::styled(border.clone(), Style::default().fg(border_color)), + Span::styled("╗", Style::default().fg(border_color)), + ])); + + // Header with status icon + let icon = if self.success { "✔" } else { "✗" }; + let time_str = format!("{}ms", self.execution_time_ms); + + lines.push(Line::from(vec![ + Span::styled(" ║ ", Style::default().fg(border_color)), + Span::styled(format!("{} ", icon), Style::default().fg(border_color)), + Span::styled(self.tool_name.clone(), Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD)), + Span::styled( + format!("{:>width$}", time_str, width = inner_width - self.tool_name.len() - 4), + Style::default().add_modifier(Modifier::DIM) + ), + Span::styled(" ║", Style::default().fg(border_color)), + ])); + + // Content with proper text wrapping + let content_width = inner_width.saturating_sub(2); + for line in self.content.lines() { + let wrapped = wrap_text(line, content_width); + for wrapped_line in wrapped { + let content_str: String = wrapped_line.spans.iter() + .map(|s| s.content.as_ref()) + .collect(); + let padded = format!("{: &str { + &self.timestamp + } +} + +/// System message cell +pub struct SystemMessageCell { + pub content: String, + pub timestamp: String, + pub message_type: SystemMessageType, +} + +#[derive(Clone, Copy)] +pub enum SystemMessageType { + Info, + Warning, + Error, + Success, +} + +impl HistoryCell for SystemMessageCell { + fn render(&self, _width: u16) -> Vec> { + let (icon, color) = match self.message_type { + SystemMessageType::Info => ("ℹ", Color::Cyan), + SystemMessageType::Warning => ("⚠", Color::Yellow), + SystemMessageType::Error => ("✗", Color::Red), + SystemMessageType::Success => ("✔", Color::Green), + }; + + vec![ + Line::from(vec![ + Span::styled(format!("{} ", icon), Style::default().fg(color)), + Span::styled(self.content.clone(), Style::default().add_modifier(Modifier::DIM)), + ]), + ] + } + + fn timestamp(&self) -> &str { + &self.timestamp + } +} diff --git a/crates/miyabi-tui/src/lib.rs b/crates/miyabi-tui/src/lib.rs new file mode 100644 index 0000000..18f1632 --- /dev/null +++ b/crates/miyabi-tui/src/lib.rs @@ -0,0 +1,16 @@ +//! Miyabi TUI - Terminal User Interface +//! +//! A premium TUI following the OpenAI Codex patterns for clean, +//! functional design with proper text wrapping and markdown rendering. + +pub mod app; +pub mod event; +pub mod wrapping; +pub mod history_cell; +pub mod markdown_render; + +pub use app::App; +pub use event::{Event, EventHandler}; +pub use wrapping::{word_wrap_line, wrap_text, display_width, WrapOptions}; +pub use history_cell::{HistoryCell, UserMessageCell, AssistantMessageCell, ToolResultCell, SystemMessageCell}; +pub use markdown_render::{MarkdownRenderer, MarkdownStyles}; diff --git a/crates/miyabi-tui/src/main.rs b/crates/miyabi-tui/src/main.rs new file mode 100644 index 0000000..4e2759f --- /dev/null +++ b/crates/miyabi-tui/src/main.rs @@ -0,0 +1,41 @@ +//! Miyabi TUI - Terminal User Interface +//! +//! A premium terminal interface following OpenAI Codex patterns. + +use miyabi_tui::App; +use crossterm::{ + event::{DisableMouseCapture, EnableMouseCapture}, + execute, + terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, +}; +use ratatui::prelude::*; +use std::io; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + // Setup terminal + enable_raw_mode()?; + let mut stdout = io::stdout(); + execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; + let backend = CrosstermBackend::new(stdout); + let mut terminal = Terminal::new(backend)?; + + // Create app and run + let mut app = App::new(); + let res = app.run(&mut terminal).await; + + // Restore terminal + disable_raw_mode()?; + execute!( + terminal.backend_mut(), + LeaveAlternateScreen, + DisableMouseCapture + )?; + terminal.show_cursor()?; + + if let Err(err) = res { + eprintln!("Error: {}", err); + } + + Ok(()) +} diff --git a/crates/miyabi-tui/src/markdown_render.rs b/crates/miyabi-tui/src/markdown_render.rs new file mode 100644 index 0000000..9fbb0e4 --- /dev/null +++ b/crates/miyabi-tui/src/markdown_render.rs @@ -0,0 +1,241 @@ +//! Markdown to Terminal Renderer +//! +//! Converts markdown text to styled ratatui Lines/Spans + +use ratatui::{ + style::{Color, Modifier, Style}, + text::{Line, Span}, +}; + +/// Markdown styling configuration +pub struct MarkdownStyles { + pub h1: Style, + pub h2: Style, + pub h3: Style, + pub bold: Style, + pub italic: Style, + pub code: Style, + pub code_block: Style, + pub link: Style, + pub list_marker: Style, + pub blockquote: Style, +} + +impl Default for MarkdownStyles { + fn default() -> Self { + Self { + h1: Style::default() + .fg(Color::Rgb(224, 175, 104)) + .add_modifier(Modifier::BOLD | Modifier::UNDERLINED), + h2: Style::default() + .fg(Color::Rgb(224, 175, 104)) + .add_modifier(Modifier::BOLD), + h3: Style::default() + .fg(Color::Rgb(192, 202, 245)) + .add_modifier(Modifier::ITALIC), + bold: Style::default().add_modifier(Modifier::BOLD), + italic: Style::default().add_modifier(Modifier::ITALIC), + code: Style::default().fg(Color::Rgb(125, 207, 255)), + code_block: Style::default().fg(Color::Rgb(125, 207, 255)), + link: Style::default() + .fg(Color::Rgb(125, 207, 255)) + .add_modifier(Modifier::UNDERLINED), + list_marker: Style::default().fg(Color::Rgb(158, 206, 106)), + blockquote: Style::default().fg(Color::Rgb(158, 206, 106)), + } + } +} + +/// Markdown renderer +pub struct MarkdownRenderer { + styles: MarkdownStyles, +} + +impl MarkdownRenderer { + pub fn new() -> Self { + Self { + styles: MarkdownStyles::default(), + } + } + + pub fn with_styles(styles: MarkdownStyles) -> Self { + Self { styles } + } + + /// Render markdown text to styled Lines + pub fn render(&self, text: &str) -> Vec> { + let mut lines = Vec::new(); + let mut in_code_block = false; + let mut code_block_content: Vec = Vec::new(); + + for line in text.lines() { + if line.trim().starts_with("```") { + if in_code_block { + // End code block + lines.push(Line::from(Span::styled( + "┌─────────────────────────────────────────────────────────────┐", + Style::default().fg(Color::Rgb(86, 95, 137)), + ))); + for code_line in &code_block_content { + lines.push(Line::from(vec![ + Span::styled("│ ", Style::default().fg(Color::Rgb(86, 95, 137))), + Span::styled(code_line.clone(), self.styles.code_block), + ])); + } + lines.push(Line::from(Span::styled( + "└─────────────────────────────────────────────────────────────┘", + Style::default().fg(Color::Rgb(86, 95, 137)), + ))); + code_block_content.clear(); + in_code_block = false; + } else { + in_code_block = true; + } + continue; + } + + if in_code_block { + code_block_content.push(line.to_string()); + continue; + } + + let rendered = self.render_line(line); + lines.push(rendered); + } + + lines + } + + fn render_line(&self, line: &str) -> Line<'static> { + let trimmed = line.trim(); + + // Headers + if trimmed.starts_with("### ") { + return Line::from(vec![ + Span::styled(" ", Style::default()), + Span::styled(trimmed[4..].to_string(), self.styles.h3), + ]); + } + if trimmed.starts_with("## ") { + return Line::from(vec![ + Span::styled(" ", Style::default()), + Span::styled(trimmed[3..].to_string(), self.styles.h2), + ]); + } + if trimmed.starts_with("# ") { + return Line::from(vec![ + Span::styled(" ", Style::default()), + Span::styled(trimmed[2..].to_string(), self.styles.h1), + ]); + } + + // Blockquotes + if trimmed.starts_with("> ") { + return Line::from(vec![ + Span::styled(" > ", self.styles.blockquote), + Span::styled(trimmed[2..].to_string(), Style::default().fg(Color::Rgb(192, 202, 245))), + ]); + } + + // Unordered lists + if trimmed.starts_with("- ") || trimmed.starts_with("* ") { + let indent = line.len() - line.trim_start().len(); + let prefix = " ".repeat(indent / 2); + return Line::from(vec![ + Span::raw(prefix), + Span::styled("• ", self.styles.list_marker), + Span::styled(trimmed[2..].to_string(), Style::default()), + ]); + } + + // Horizontal rule + if trimmed == "---" || trimmed == "***" || trimmed == "___" { + return Line::from(Span::styled( + "────────────────────────────────────────────────────────────", + Style::default().fg(Color::Rgb(86, 95, 137)), + )); + } + + // Regular paragraph with inline formatting + self.render_inline_line(line) + } + + fn render_inline_line(&self, line: &str) -> Line<'static> { + let mut spans = Vec::new(); + let mut current = String::new(); + let mut chars = line.chars().peekable(); + let mut in_bold = false; + let mut in_italic = false; + let mut in_code = false; + + while let Some(c) = chars.next() { + match c { + '`' if !in_bold && !in_italic => { + if !current.is_empty() { + spans.push(Span::styled( + current.clone(), + if in_code { self.styles.code } else { Style::default().fg(Color::Rgb(192, 202, 245)) }, + )); + current.clear(); + } + in_code = !in_code; + } + '*' if chars.peek() == Some(&'*') && !in_code => { + chars.next(); + if !current.is_empty() { + let style = if in_bold { + self.styles.bold + } else if in_italic { + self.styles.italic + } else { + Style::default().fg(Color::Rgb(192, 202, 245)) + }; + spans.push(Span::styled(current.clone(), style)); + current.clear(); + } + in_bold = !in_bold; + } + '*' | '_' if !in_code && !in_bold => { + if !current.is_empty() { + let style = if in_italic { + self.styles.italic + } else { + Style::default().fg(Color::Rgb(192, 202, 245)) + }; + spans.push(Span::styled(current.clone(), style)); + current.clear(); + } + in_italic = !in_italic; + } + _ => { + current.push(c); + } + } + } + + if !current.is_empty() { + let style = if in_code { + self.styles.code + } else if in_bold { + self.styles.bold + } else if in_italic { + self.styles.italic + } else { + Style::default().fg(Color::Rgb(192, 202, 245)) + }; + spans.push(Span::styled(current, style)); + } + + if spans.is_empty() { + Line::from("") + } else { + Line::from(spans) + } + } +} + +impl Default for MarkdownRenderer { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/miyabi-tui/src/wrapping.rs b/crates/miyabi-tui/src/wrapping.rs new file mode 100644 index 0000000..0a327dd --- /dev/null +++ b/crates/miyabi-tui/src/wrapping.rs @@ -0,0 +1,268 @@ +//! Text Wrapping Module +//! +//! Provides intelligent text wrapping for terminal display, +//! following the OpenAI Codex TUI pattern with textwrap integration. + +use ratatui::text::{Line, Span}; +use std::borrow::Cow; +use textwrap::{wrap_algorithms::Penalties, Options, WordSeparator, WordSplitter, WrapAlgorithm}; +use unicode_width::UnicodeWidthStr; + +/// Wrapping options configuration +pub struct WrapOptions<'a> { + /// Target width for wrapping + pub width: usize, + /// Prefix for the first line + pub initial_indent: Cow<'a, str>, + /// Prefix for subsequent lines + pub subsequent_indent: Cow<'a, str>, + /// Whether to break words that exceed width + pub break_words: bool, +} + +impl<'a> Default for WrapOptions<'a> { + fn default() -> Self { + Self { + width: 80, + initial_indent: Cow::Borrowed(""), + subsequent_indent: Cow::Borrowed(""), + break_words: false, + } + } +} + +impl<'a> WrapOptions<'a> { + /// Create options with specified width + pub fn new(width: usize) -> Self { + Self { + width, + ..Default::default() + } + } + + /// Set initial indent + pub fn initial_indent(mut self, indent: impl Into>) -> Self { + self.initial_indent = indent.into(); + self + } + + /// Set subsequent indent + pub fn subsequent_indent(mut self, indent: impl Into>) -> Self { + self.subsequent_indent = indent.into(); + self + } + + /// Set word breaking behavior + pub fn break_words(mut self, break_words: bool) -> Self { + self.break_words = break_words; + self + } + + /// Convert to textwrap Options + fn to_textwrap_options(&self) -> Options<'_> { + Options::new(self.width) + .initial_indent(&self.initial_indent) + .subsequent_indent(&self.subsequent_indent) + .break_words(self.break_words) + .word_separator(WordSeparator::UnicodeBreakProperties) + .word_splitter(WordSplitter::NoHyphenation) + .wrap_algorithm(WrapAlgorithm::OptimalFit(Penalties::default())) + } +} + +/// Wrap a single line of text into multiple lines +pub fn word_wrap_line(line: &Line<'_>, width: usize) -> Vec> { + let options = WrapOptions::new(width); + word_wrap_line_with_options(line, &options) +} + +/// Wrap a single line with custom options +pub fn word_wrap_line_with_options( + line: &Line<'_>, + options: &WrapOptions<'_>, +) -> Vec> { + if line.spans.is_empty() { + return vec![Line::from("")]; + } + + // Track spans with their byte ranges in the flattened string + let mut flat_text = String::new(); + let mut span_ranges: Vec<(usize, usize, ratatui::style::Style)> = Vec::new(); + + for span in &line.spans { + let start = flat_text.len(); + flat_text.push_str(&span.content); + let end = flat_text.len(); + span_ranges.push((start, end, span.style)); + } + + if flat_text.is_empty() { + return vec![Line::from("")]; + } + + // Use textwrap to compute line breaks + let textwrap_opts = options.to_textwrap_options(); + let wrapped = textwrap::wrap(&flat_text, textwrap_opts); + + let mut result = Vec::new(); + let mut current_pos = 0; + + for wrapped_line in wrapped { + let line_str = wrapped_line.trim_start(); + if line_str.is_empty() { + result.push(Line::from("")); + continue; + } + + // Find position in original text (skip leading whitespace) + let skip_ws = wrapped_line.len() - line_str.len(); + let line_start = current_pos + skip_ws; + let line_end = line_start + line_str.len(); + + // Build spans for this wrapped line + let mut line_spans = Vec::new(); + + for &(span_start, span_end, style) in &span_ranges { + // Check if this span overlaps with current line + if span_end <= line_start || span_start >= line_end { + continue; + } + + // Calculate overlap + let overlap_start = span_start.max(line_start); + let overlap_end = span_end.min(line_end); + + if overlap_start < overlap_end { + let text = &flat_text[overlap_start..overlap_end]; + line_spans.push(Span::styled(text.to_string(), style)); + } + } + + if line_spans.is_empty() { + result.push(Line::from(line_str.to_string())); + } else { + result.push(Line::from(line_spans)); + } + + current_pos = line_end; + } + + if result.is_empty() { + vec![Line::from("")] + } else { + result + } +} + +/// Wrap multiple lines of text +pub fn word_wrap_lines<'a, I>(lines: I, width: usize) -> Vec> +where + I: IntoIterator>, +{ + let mut result = Vec::new(); + for line in lines { + result.extend(word_wrap_line(&line, width)); + } + result +} + +/// Wrap plain text string into styled lines +pub fn wrap_text(text: &str, width: usize) -> Vec> { + let options = WrapOptions::new(width); + let textwrap_opts = options.to_textwrap_options(); + let wrapped = textwrap::wrap(text, textwrap_opts); + + wrapped + .into_iter() + .map(|s| Line::from(s.into_owned())) + .collect() +} + +/// Calculate display width of text (Unicode-aware) +pub fn display_width(text: &str) -> usize { + UnicodeWidthStr::width(text) +} + +/// Truncate text to fit within width, adding ellipsis if needed +pub fn truncate_with_ellipsis(text: &str, width: usize) -> String { + let text_width = display_width(text); + if text_width <= width { + return text.to_string(); + } + + if width < 3 { + return "...".chars().take(width).collect(); + } + + let target_width = width - 3; + let mut result = String::new(); + let mut current_width = 0; + + for ch in text.chars() { + let ch_width = UnicodeWidthStr::width(ch.to_string().as_str()); + if current_width + ch_width > target_width { + break; + } + result.push(ch); + current_width += ch_width; + } + + result.push_str("..."); + result +} + +/// Pad text to specified width +pub fn pad_to_width(text: &str, width: usize) -> String { + let text_width = display_width(text); + if text_width >= width { + return text.to_string(); + } + + let padding = width - text_width; + format!("{}{}", text, " ".repeat(padding)) +} + +#[cfg(test)] +mod tests { + use super::*; + use ratatui::style::{Color, Style}; + + #[test] + fn test_wrap_simple_text() { + let result = wrap_text("hello world", 5); + assert_eq!(result.len(), 2); + } + + #[test] + fn test_wrap_empty() { + let result = wrap_text("", 10); + assert_eq!(result.len(), 1); + } + + #[test] + fn test_display_width() { + assert_eq!(display_width("hello"), 5); + assert_eq!(display_width("日本語"), 6); + } + + #[test] + fn test_truncate_with_ellipsis() { + assert_eq!(truncate_with_ellipsis("hello world", 8), "hello..."); + assert_eq!(truncate_with_ellipsis("short", 10), "short"); + } + + #[test] + fn test_pad_to_width() { + assert_eq!(pad_to_width("hello", 10), "hello "); + assert_eq!(pad_to_width("hello", 5), "hello"); + } + + #[test] + fn test_word_wrap_line_preserves_style() { + let style = Style::default().fg(Color::Cyan); + let line = Line::from(vec![Span::styled("hello world foo bar", style)]); + + let wrapped = word_wrap_line(&line, 10); + assert!(wrapped.len() >= 2); + } +} diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md new file mode 100644 index 0000000..84ade53 --- /dev/null +++ b/docs/GETTING_STARTED.md @@ -0,0 +1,244 @@ +# Getting Started with miyabi-cli-standalone + +Miyabiプロジェクトへようこそ!このガイドでは、ゼロからMiyabiを使い始めるまでの手順を詳しく解説します。 + +## 📋 前提条件 + +### 必須 + +- **Rust**: 1.75.0以上 + ```bash + rustc --version # 確認 + ``` + +- **Git**: バージョン管理用 + ```bash + git --version + ``` + +- **GitHubアカウント**: Issue/PR管理用 + +### 推奨 + +- **GitHub CLI (`gh`)**: GitHub操作を簡単に + ```bash + brew install gh # macOS + gh --version + ``` + +## 🚀 セットアップ手順 + +### Step 1: 環境変数の設定 + +#### 1.1 GitHub Personal Access Token取得 + +1. https://github.com/settings/tokens/new にアクセス +2. Token名を入力(例: "Miyabi Local Dev") +3. 以下のスコープを選択: + - ✅ `repo` (Full control of private repositories) + - ✅ `workflow` (Update GitHub Action workflows) +4. "Generate token"をクリック +5. トークンをコピー(**一度しか表示されません!**) + +#### 1.2 環境変数をシェルプロファイルに追加 + +**Bash (.bashrc / .bash_profile):** +```bash +echo 'export GITHUB_TOKEN=ghp_xxxxx' >> ~/.bashrc +echo 'export ANTHROPIC_API_KEY=sk-ant-xxxxx' >> ~/.bashrc +source ~/.bashrc +``` + +**Zsh (.zshrc):** +```bash +echo 'export GITHUB_TOKEN=ghp_xxxxx' >> ~/.zshrc +echo 'export ANTHROPIC_API_KEY=sk-ant-xxxxx' >> ~/.zshrc +source ~/.zshrc +``` + +#### 1.3 環境変数確認 +```bash +echo $GITHUB_TOKEN +echo $ANTHROPIC_API_KEY +``` + +### Step 2: GitHubリポジトリ作成 + +#### 2.1 GitHub CLI使用(推奨) +```bash +cd miyabi-cli-standalone +gh repo create miyabi-cli-standalone --private --source=. --remote=origin +``` + +#### 2.2 手動作成 +1. https://github.com/new にアクセス +2. Repository nameに `miyabi-cli-standalone` を入力 +3. "Private"を選択 +4. "Create repository"をクリック +5. ローカルリポジトリと接続: + ```bash + git remote add origin https://github.com/YOUR_USERNAME/miyabi-cli-standalone.git + git branch -M main + git add . + git commit -m "feat: initial commit 🚀" + git push -u origin main + ``` + +### Step 3: Label体系のセットアップ + +Miyabiは53ラベル体系で自動化を制御します。 + +#### 3.1 自動セットアップ(将来実装予定) +```bash +miyabi setup labels +``` + +#### 3.2 手動セットアップ +GitHubリポジトリの設定から、以下のラベルを作成: + +**STATE(8個)**: +- `📥 state:pending` (Gray) +- `🔍 state:analyzing` (Blue) +- `🏗️ state:implementing` (Yellow) +- `👀 state:reviewing` (Orange) +- `✅ state:done` (Green) +- `❌ state:blocked` (Red) +- `⏸️ state:on-hold` (Purple) +- `🔄 state:reopened` (Pink) + +(残り45ラベルは`.github/labels.yml`を参照) + +### Step 4: 最初のIssue作成 + +#### 4.1 GitHub Web UIで作成 +1. リポジトリの"Issues"タブをクリック +2. "New issue"をクリック +3. Title: "✨ Setup project configuration" +4. Body: + ```markdown + ## 概要 + プロジェクトの初期設定を行う + + ## タスク + - [ ] .miyabi.yml の設定確認 + - [ ] GitHub Actionsの設定 + - [ ] 開発環境の準備 + + ## 期待される成果 + - プロジェクトが動作可能な状態 + ``` +5. Labels: + - `✨ type:feature` + - `⚠️ priority:P1-High` + - `📥 state:pending` +6. "Submit new issue"をクリック + +#### 4.2 GitHub CLIで作成 +```bash +gh issue create --title "✨ Setup project configuration" \ + --body "初期設定タスク" \ + --label "type:feature,priority:P1-High,state:pending" +``` + +### Step 5: Agent実行 + +#### 5.1 ステータス確認 +```bash +miyabi status +``` + +出力例: +``` +📊 Project Status + +Miyabi Installation: + ✅ Miyabi is installed + ✓ .claude/agents + ✓ .github/workflows + +Environment: + ✅ GITHUB_TOKEN is set + ✅ DEVICE_IDENTIFIER: YourMac.local + +Git Repository: + ✅ Git repository detected + Branch: main + Remotes: origin +``` + +#### 5.2 CoordinatorAgent実行 +```bash +miyabi agent run coordinator --issue 1 +``` + +Agentは以下を実行します: +1. Issue分析 +2. Task分解(DAG構築) +3. Worktree作成 +4. Specialist Agent割り当て +5. 並列実行 +6. 結果統合 + +## 🎯 よくある使い方 + +### Issue処理の基本フロー +```bash +# 1. Issue作成(GitHub UI または gh CLI) +gh issue create --title "新機能実装" --label "type:feature" + +# 2. Agent実行 +miyabi agent run coordinator --issue 2 + +# 3. ステータス確認 +miyabi status + +# 4. ログ確認 +cat logs/miyabi-*.log +``` + +### 複数Issue並列処理 +```bash +miyabi agent run coordinator --issues 1,2,3 --concurrency 2 +``` + +### Worktree確認 +```bash +git worktree list +``` + +## 📚 次に読むべきドキュメント + +1. **CLAUDE.md** - プロジェクトコンテキスト(Claude Codeが自動参照) +2. **.claude/QUICK_START.md** - 3分で始めるクイックガイド +3. **.claude/agents/README.md** - Agent一覧と使い方 +4. **docs/TROUBLESHOOTING.md** - トラブルシューティング + +## 🆘 困ったときは + +### エラーが出た場合 +1. `docs/TROUBLESHOOTING.md` を確認 +2. `miyabi status` で環境確認 +3. GitHub Issuesで質問: https://github.com/ShunsukeHayashi/Miyabi/issues + +### ログ確認 +```bash +# 最新のログファイル +tail -f logs/miyabi-$(date +%Y%m%d).log + +# エラーログのみ抽出 +grep -i error logs/miyabi-*.log +``` + +## 🎉 次のステップ + +おめでとうございます!Miyabiのセットアップが完了しました。 + +次は: +1. **独自のAgent仕様作成**: `.claude/agents/specs/coding/` にカスタムAgent追加 +2. **Label体系のカスタマイズ**: プロジェクトに合わせたLabel追加 +3. **GitHub Actionsの設定**: `.github/workflows/` でCI/CD自動化 +4. **Worktree並列実行**: 複数Issueの同時処理 + +--- + +**Miyabi** - Beauty in Autonomous Development 🌸 diff --git a/docs/OPERATION_PLAN.md b/docs/OPERATION_PLAN.md new file mode 100644 index 0000000..426f369 --- /dev/null +++ b/docs/OPERATION_PLAN.md @@ -0,0 +1,341 @@ +# Operation Plan - miyabi-cli-standalone + +**Project**: miyabi-cli-standalone +**Created**: 2025-11-22 +**Execution Method**: Miyabi Autonomous Agents + +--- + +## 🚀 Quick Start + +### Prerequisites + +```bash +# 1. 環境確認 +miyabi status + +# 2. 環境変数設定 +export GITHUB_TOKEN=ghp_xxx +export ANTHROPIC_API_KEY=sk-ant-xxx + +# 3. Miyabiバイナリへのパス(オプション) +alias miyabi='/Users/shunsuke/Dev/01-miyabi/_core/miyabi-private/target/release/miyabi' +``` + +--- + +## 📋 Execution Workflow + +### Phase 1: Sprint 1 開始 + +#### Day 1: Parallel Foundation Tasks + +```bash +# Stream A: TUI +miyabi agent run coordinator --issue 10 # Core Structure +miyabi agent run coordinator --issue 15 # Diff Core + +# Stream B: LLM (CRITICAL) +miyabi agent run coordinator --issue 19 # API Client + +# Stream C: Tools +miyabi agent run coordinator --issue 24 # Tool Trait +``` + +#### 進捗監視 + +```bash +# ステータス確認 +miyabi status + +# Issue一覧 +gh issue list --repo ShunsukeHayashi/miyabi-cli-standalone \ + --label "🏗️ state:implementing" + +# PR確認 +gh pr list --repo ShunsukeHayashi/miyabi-cli-standalone +``` + +--- + +## 🔄 Daily Operations + +### Morning Routine + +```bash +# 1. 前日のPRをレビュー +gh pr list --repo ShunsukeHayashi/miyabi-cli-standalone --state open + +# 2. ブロッカー確認 +gh issue list --label "🚫 state:blocked" + +# 3. 今日のタスク開始 +miyabi agent run coordinator --issue <次のissue番号> +``` + +### Task Execution + +```bash +# 単一Issue実行 +miyabi agent run coordinator --issue <番号> + +# 並列実行(別ターミナルで) +miyabi agent run coordinator --issue 10 & +miyabi agent run coordinator --issue 15 & +miyabi agent run coordinator --issue 19 & +``` + +### Evening Review + +```bash +# 完了タスク確認 +gh issue list --label "✅ state:done" --state closed + +# 明日の計画 +gh issue list --label "📥 state:pending" --milestone "v0.2.0 - Advanced Text Rendering" +``` + +--- + +## 🎯 Sprint Execution Plan + +### Sprint 1 (Week 1) + +| Day | Tasks | Command | +|-----|-------|---------| +| Mon | #10, #15, #19, #24 | `miyabi agent run coordinator --issue 10` (x4 parallel) | +| Tue | Continue + Review | Review PRs, merge if ready | +| Wed | #11, #16, #20, #25 | Start dependent tasks | +| Thu | Continue + Review | Review PRs | +| Fri | Integration testing | Manual testing, bug fixes | + +### Sprint 2-4 + +同様のパターンで継続 + +--- + +## 📊 Monitoring Commands + +### Real-time Status + +```bash +# Miyabiステータス +miyabi status + +# GitHub Issues +gh issue list --repo ShunsukeHayashi/miyabi-cli-standalone + +# ラベル別 +gh issue list --label "📊 priority:P0-Critical" +gh issue list --label "🏗️ state:implementing" +gh issue list --label "👀 state:reviewing" +``` + +### PR Management + +```bash +# PR一覧 +gh pr list + +# 特定PRの詳細 +gh pr view <番号> + +# PRをマージ +gh pr merge <番号> --squash +``` + +### Logs + +```bash +# Miyabiログ +ls -la logs/ + +# 最新ログ +tail -f logs/*.log +``` + +--- + +## 🔧 Agent Commands Reference + +### Coordinator Agent + +```bash +# Issue分析と実装 +miyabi agent run coordinator --issue <番号> + +# ドライラン(実行せず計画のみ) +miyabi agent run coordinator --issue <番号> --dry-run + +# 詳細ログ +RUST_LOG=debug miyabi agent run coordinator --issue <番号> +``` + +### CodeGen Agent (自動呼び出し) + +Coordinatorが自動的にCodeGenを呼び出します。 + +### Review Agent (自動呼び出し) + +PR作成後、自動的にレビューが実行されます。 + +--- + +## 🚨 Troubleshooting + +### Agent が停止した場合 + +```bash +# 状態確認 +miyabi status + +# ログ確認 +cat logs/latest.log + +# Issue状態をリセット +gh issue edit <番号> --remove-label "🏗️ state:implementing" +gh issue edit <番号> --add-label "📥 state:pending" + +# 再実行 +miyabi agent run coordinator --issue <番号> +``` + +### Rate Limit エラー + +```bash +# GitHub API制限確認 +gh api rate_limit + +# 待機後再実行 +sleep 3600 # 1時間待機 +miyabi agent run coordinator --issue <番号> +``` + +### ビルドエラー + +```bash +# 手動ビルド確認 +cargo build --release + +# テスト実行 +cargo test --all + +# Lint +cargo clippy --all-targets +``` + +--- + +## 📈 Progress Tracking + +### Milestone Progress + +```bash +# マイルストーン一覧 +gh api repos/ShunsukeHayashi/miyabi-cli-standalone/milestones + +# 特定マイルストーンの進捗 +gh issue list --milestone "v0.2.0 - Advanced Text Rendering" +``` + +### Metrics + +```bash +# コード行数 +find crates -name "*.rs" | xargs wc -l | tail -1 + +# Issue統計 +gh issue list --state all --json state | jq 'group_by(.state) | map({state: .[0].state, count: length})' +``` + +--- + +## 🔄 CI/CD Integration + +### GitHub Actions + +PRがマージされると自動的に: +1. `cargo test` 実行 +2. `cargo clippy` チェック +3. `cargo fmt` 確認 + +### 手動トリガー + +```bash +# ワークフロー実行 +gh workflow run build.yml +``` + +--- + +## 📝 Best Practices + +### 1. Critical Path 優先 + +常にP0タスクを優先: +- #19 (API Client) → #20 → #22 +- #24 (Tool Trait) → #25 → #26 + +### 2. 並列実行 + +独立したタスクは並列実行: +- Stream A (#10-14, #15-18) +- Stream B (#19-23) +- Stream C (#24-28) + +### 3. 早期レビュー + +PRは作成後すぐにレビュー: +```bash +gh pr review <番号> --approve +gh pr merge <番号> --squash +``` + +### 4. ブロッカー対応 + +ブロッカーは即座に対応: +```bash +gh issue list --label "🚫 state:blocked" +``` + +--- + +## 🎯 Execution Checklist + +### Sprint Start + +- [ ] `miyabi status` で環境確認 +- [ ] 当該Sprintのタスク確認 +- [ ] Critical Pathタスクを優先開始 + +### Daily + +- [ ] PRレビュー・マージ +- [ ] ブロッカー確認 +- [ ] 新タスク開始 + +### Sprint End + +- [ ] 全PRマージ +- [ ] 統合テスト +- [ ] マイルストーン確認 +- [ ] 次Sprint計画 + +--- + +## 🚀 First Execution + +```bash +# 今すぐ開始 +cd /Users/shunsuke/Dev/miyabi-cli-standalone + +# Critical Path開始 +miyabi agent run coordinator --issue 19 # API Client (最重要) +miyabi agent run coordinator --issue 10 # Core Structure +miyabi agent run coordinator --issue 24 # Tool Trait +``` + +--- + +**Happy Coding with Miyabi! 🤖** diff --git a/docs/PREPARATION_OPS.md b/docs/PREPARATION_OPS.md new file mode 100644 index 0000000..0313402 --- /dev/null +++ b/docs/PREPARATION_OPS.md @@ -0,0 +1,384 @@ +# Preparation Operations - miyabi-cli-standalone + +**Purpose**: Sprint 1開始前の準備作業チェックリスト +**Target Date**: 2025-11-25 (Sprint 1 Start) + +--- + +## 📋 Pre-Sprint Checklist + +### 1. Environment Setup + +#### 1.1 Development Environment + +- [ ] **Rust toolchain** + ```bash + rustup update stable + rustup component add clippy rustfmt + cargo --version # 1.75+ + ``` + +- [ ] **GitHub CLI** + ```bash + gh --version + gh auth status + ``` + +- [ ] **Miyabi CLI** + ```bash + /Users/shunsuke/Dev/01-miyabi/_core/miyabi-private/target/release/miyabi --version + ``` + +#### 1.2 API Keys + +- [ ] **GitHub Token** + ```bash + # .env に設定 + echo "GITHUB_TOKEN=ghp_xxx" >> .env + + # 必要なスコープ: repo, workflow + gh auth refresh -s repo,workflow + ``` + +- [ ] **Anthropic API Key** + ```bash + echo "ANTHROPIC_API_KEY=sk-ant-xxx" >> .env + + # テスト + curl https://api.anthropic.com/v1/messages \ + -H "x-api-key: $ANTHROPIC_API_KEY" \ + -H "anthropic-version: 2023-06-01" \ + -d '{"model":"claude-sonnet-4-20250514","max_tokens":10,"messages":[{"role":"user","content":"Hi"}]}' + ``` + +#### 1.3 Project Dependencies + +- [ ] **Node.js dependencies** + ```bash + npm install + ``` + +- [ ] **Cargo dependencies** (初回ビルドで取得) + ```bash + cargo fetch + ``` + +--- + +### 2. Repository Setup + +#### 2.1 Labels Verification + +- [ ] **必要なラベル確認** + ```bash + gh label list --repo ShunsukeHayashi/miyabi-cli-standalone | wc -l + # Expected: 45+ labels + ``` + +- [ ] **不足ラベル追加** + ```bash + # 必要に応じて + gh label create "🔥 urgent" --color "d73a4a" --description "Urgent issue" + ``` + +#### 2.2 Milestones Verification + +- [ ] **マイルストーン確認** + ```bash + gh api repos/ShunsukeHayashi/miyabi-cli-standalone/milestones | jq '.[].title' + ``` + + Expected: + - v0.2.0 - Advanced Text Rendering + - v0.3.0 - Chat Composer + - v0.4.0 - Approval & Navigation + - v1.0.0 - Production Ready + +#### 2.3 Issues Verification + +- [ ] **Issue一覧確認** + ```bash + gh issue list --repo ShunsukeHayashi/miyabi-cli-standalone --state all | wc -l + # Expected: 28 issues + ``` + +- [ ] **Sprint 1タスク確認** + ```bash + gh issue list --milestone "v0.2.0 - Advanced Text Rendering" --label "📊 priority:P0-Critical" + ``` + +--- + +### 3. Codebase Preparation + +#### 3.1 Directory Structure + +- [ ] **必要ディレクトリ作成** + ```bash + mkdir -p crates/miyabi-cli/src + mkdir -p crates/miyabi-core/src + mkdir -p crates/miyabi-tui/src + mkdir -p tests + ``` + +#### 3.2 Cargo.toml Setup + +- [ ] **ワークスペース設定確認** + ```bash + cat Cargo.toml | grep "members" + ``` + +- [ ] **各crateのCargo.toml確認** + ```bash + ls crates/*/Cargo.toml + ``` + +#### 3.3 Initial Build Test + +- [ ] **ビルドテスト** + ```bash + cargo build + cargo test + cargo clippy + ``` + +--- + +### 4. CI/CD Setup + +#### 4.1 GitHub Actions + +- [ ] **ワークフロー確認** + ```bash + ls .github/workflows/ + ``` + +- [ ] **CI設定** (create if not exists) + ```yaml + # .github/workflows/ci.yml + name: CI + on: [push, pull_request] + jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - run: cargo build --all + - run: cargo test --all + - run: cargo clippy --all -- -D warnings + ``` + +#### 4.2 Branch Protection + +- [ ] **main ブランチ保護** + - Require PR reviews + - Require status checks + - Require linear history + +--- + +### 5. Documentation + +#### 5.1 Required Documents + +- [x] README.md +- [x] CLAUDE.md +- [x] GOALS.md +- [x] docs/WBS.md +- [x] docs/SPRINT_PLANNING.md +- [x] docs/OPERATION_PLAN.md +- [x] docs/PRODUCT_SPEC.md +- [x] docs/PREPARATION_OPS.md (this file) + +#### 5.2 PlantUML Diagrams + +- [x] docs/wbs-diagram.puml +- [x] docs/gantt-chart.puml + +--- + +### 6. Reference Materials + +#### 6.1 Codex CLI Reference + +- [ ] **Clone Codex CLI** + ```bash + git clone https://github.com/openai/codex.git /tmp/codex-reference + ``` + +- [ ] **主要ファイル確認** + ```bash + ls /tmp/codex-reference/codex-rs/tui/src/ + ``` + +- [ ] **参照用ブックマーク** + - markdown_stream.rs + - diff_render.rs + - chat_composer.rs + - textarea.rs + +#### 6.2 Miyabi Private Reference + +- [ ] **Agent実装参照** + ```bash + ls /Users/shunsuke/Dev/01-miyabi/_core/miyabi-private/crates/ + ``` + +--- + +### 7. Team Communication + +#### 7.1 Notification Setup + +- [ ] **Slack/Discord通知** (if applicable) + +- [ ] **GitHub通知設定** + - Watch repository + - Enable PR notifications + +#### 7.2 Daily Standup Schedule + +- [ ] **Standup時間設定** + - Time: 毎朝 9:00 + - Duration: 10分 + - Format: miyabi status確認 + +--- + +### 8. Monitoring Setup + +#### 8.1 Miyabi Monitoring + +- [ ] **ログディレクトリ確認** + ```bash + mkdir -p logs + mkdir -p reports + ``` + +- [ ] **ログローテーション設定** + ```bash + # 30日以上のログを削除 + find logs -mtime +30 -delete + ``` + +#### 8.2 GitHub Insights + +- [ ] **Pulse確認** + ``` + https://github.com/ShunsukeHayashi/miyabi-cli-standalone/pulse + ``` + +--- + +### 9. Sprint 1 Kickoff Preparation + +#### 9.1 First Tasks Ready + +- [ ] **Issue #10 (MarkdownStream core)** + ```bash + gh issue view 10 --repo ShunsukeHayashi/miyabi-cli-standalone + ``` + +- [ ] **Issue #15 (DiffRender core)** + ```bash + gh issue view 15 + ``` + +- [ ] **Issue #19 (API client)** + ```bash + gh issue view 19 + ``` + +- [ ] **Issue #24 (Tool trait)** + ```bash + gh issue view 24 + ``` + +#### 9.2 Agent Configuration + +- [ ] **Miyabi設定確認** + ```bash + cat .miyabi.yml + ``` + +- [ ] **.claude設定確認** + ```bash + ls .claude/ + ls .claude/agents/specs/ + ``` + +--- + +## 🚀 Kickoff Commands + +### Sprint 1 Day 1 (2025-11-25) + +```bash +# 1. 環境確認 +cd /Users/shunsuke/Dev/miyabi-cli-standalone +miyabi status + +# 2. Critical Path 開始 +miyabi agent run coordinator --issue 19 # API Client (CRITICAL) + +# 3. Parallel tasks 開始 +miyabi agent run coordinator --issue 10 # Markdown Core +miyabi agent run coordinator --issue 15 # Diff Core +miyabi agent run coordinator --issue 24 # Tool Trait + +# 4. 進捗監視 +watch -n 60 'gh issue list --label "🏗️ state:implementing"' +``` + +--- + +## ✅ Final Checklist + +### Must Have (Sprint開始前) + +- [ ] Rust toolchain ready +- [ ] API keys configured +- [ ] GitHub labels/milestones set +- [ ] Initial crate structure +- [ ] CI workflow active + +### Should Have + +- [ ] Codex CLI reference cloned +- [ ] PlantUML diagrams reviewed +- [ ] All documentation in place + +### Nice to Have + +- [ ] Notification integrations +- [ ] Performance baselines + +--- + +## 📞 Emergency Contacts + +| Issue | Action | +|-------|--------| +| API Key invalid | Regenerate at console.anthropic.com | +| GitHub rate limit | Wait 1 hour or use different token | +| Build failure | Check Cargo.toml, dependencies | +| Agent stuck | Check logs, reset issue state | + +--- + +## 📝 Sign-off + +| Item | Status | Date | Notes | +|------|--------|------|-------| +| Environment | ⬜ | | | +| Repository | ⬜ | | | +| Codebase | ⬜ | | | +| CI/CD | ⬜ | | | +| Documentation | ✅ | 2025-11-22 | Complete | +| References | ⬜ | | | +| Monitoring | ⬜ | | | + +--- + +**Ready for Sprint 1? Let's go! 🚀** diff --git a/docs/PRODUCT_SPEC.md b/docs/PRODUCT_SPEC.md new file mode 100644 index 0000000..b15432b --- /dev/null +++ b/docs/PRODUCT_SPEC.md @@ -0,0 +1,648 @@ +# Product Specification - miyabi-cli-standalone + +**Version**: 1.0.0 +**Status**: Draft +**Last Updated**: 2025-11-22 + +--- + +## 1. Executive Summary + +### 1.1 Product Vision +OpenAI Codex CLIと同等の機能を持ち、Miyabiの拡張機能を統合した次世代AI開発CLIツール + +### 1.2 Target Users +- ソフトウェア開発者 +- DevOpsエンジニア +- AI/MLエンジニア + +### 1.3 Core Value Proposition +- **高速**: Rust実装による100ms以下の起動時間 +- **美しい**: Ratatui TUIによるリッチなターミナル体験 +- **自律的**: 完全自律型タスク実行 +- **拡張性**: プラグイン対応 + +--- + +## 2. Functional Requirements + +### 2.1 TUI System + +#### FR-TUI-001: Markdown Streaming Renderer + +**Description**: LLMレスポンスをリアルタイムでレンダリング + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-TUI-001-1 | Character-by-character streaming | Must | Pending | +| FR-TUI-001-2 | Progressive code block rendering | Must | Pending | +| FR-TUI-001-3 | Syntax highlighting (50+ languages) | Must | Pending | +| FR-TUI-001-4 | Cursor position tracking | Should | Pending | +| FR-TUI-001-5 | Auto-scroll during streaming | Should | Pending | +| FR-TUI-001-6 | User scroll override | Could | Pending | + +**Acceptance Criteria**: +```gherkin +Scenario: Streaming text display + Given the LLM is generating a response + When text chunks arrive + Then each character is displayed immediately + And the display scrolls to show latest content + And there is no visible flickering +``` + +**Performance**: +- Render latency: < 16ms (60 FPS) +- Memory: < 10MB for 100K characters +- CPU: < 5% during streaming + +--- + +#### FR-TUI-002: Git Diff Visualization + +**Description**: Git diffの美しい視覚化 + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-TUI-002-1 | Unified diff parsing | Must | Pending | +| FR-TUI-002-2 | Color-coded additions/deletions | Must | Pending | +| FR-TUI-002-3 | Line numbers (old/new) | Must | Pending | +| FR-TUI-002-4 | Syntax highlighting in diff | Should | Pending | +| FR-TUI-002-5 | Hunk navigation (n/N) | Should | Pending | +| FR-TUI-002-6 | Split view mode | Could | Pending | + +**Color Scheme**: +``` +Addition: #2ea043 (Green) +Deletion: #f85149 (Red) +Context: Default +Hunk header: #8b949e (Gray) +``` + +**Acceptance Criteria**: +```gherkin +Scenario: View file diff + Given a unified diff output + When rendered in the TUI + Then additions are highlighted in green + And deletions are highlighted in red + And line numbers are correctly aligned +``` + +--- + +#### FR-TUI-003: Chat Composer + +**Description**: マルチライン入力とコマンド補完 + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-TUI-003-1 | Multi-line text input | Must | Pending | +| FR-TUI-003-2 | Command history (Up/Down) | Must | Pending | +| FR-TUI-003-3 | Tab completion | Should | Pending | +| FR-TUI-003-4 | Syntax highlighting in input | Should | Pending | +| FR-TUI-003-5 | Vim keybindings | Could | Pending | +| FR-TUI-003-6 | Emacs keybindings | Could | Pending | + +**Key Bindings**: +``` +Enter : Send message (single line) +Shift+Enter : New line +Ctrl+C : Cancel +Ctrl+L : Clear screen +Up/Down : History navigation +Tab : Auto-complete +``` + +--- + +#### FR-TUI-004: Text Area Widget + +**Description**: 完全機能テキストエディタ + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-TUI-004-1 | Text selection (Shift+Arrow) | Must | Pending | +| FR-TUI-004-2 | Copy/Paste (Ctrl+C/V) | Must | Pending | +| FR-TUI-004-3 | Undo/Redo (Ctrl+Z/Y) | Must | Pending | +| FR-TUI-004-4 | Word wrap | Should | Pending | +| FR-TUI-004-5 | Find & Replace | Could | Pending | + +--- + +#### FR-TUI-005: Approval Overlay + +**Description**: ツール実行の承認UI + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-TUI-005-1 | Show tool name and arguments | Must | Pending | +| FR-TUI-005-2 | Y/N/A/N options | Must | Pending | +| FR-TUI-005-3 | Risk level indicator | Should | Pending | +| FR-TUI-005-4 | Remember "Always" choices | Should | Pending | +| FR-TUI-005-5 | Preview changes | Could | Pending | + +**Risk Levels**: +- 🟢 Low: Read operations +- 🟡 Medium: Write to files +- 🔴 High: Execute commands, delete files + +--- + +### 2.2 LLM Integration + +#### FR-LLM-001: Anthropic API Client + +**Description**: Claude APIとの通信 + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-LLM-001-1 | POST /v1/messages | Must | Pending | +| FR-LLM-001-2 | SSE streaming | Must | Pending | +| FR-LLM-001-3 | API key authentication | Must | Pending | +| FR-LLM-001-4 | Error handling (4xx, 5xx) | Must | Pending | +| FR-LLM-001-5 | Retry with exponential backoff | Must | Pending | +| FR-LLM-001-6 | Request timeout (30s default) | Should | Pending | + +**API Endpoint**: +``` +POST https://api.anthropic.com/v1/messages +Headers: + x-api-key: $ANTHROPIC_API_KEY + anthropic-version: 2023-06-01 + content-type: application/json +``` + +**Error Handling**: +| Code | Action | +|------|--------| +| 400 | Show error, don't retry | +| 401 | Prompt for API key | +| 429 | Wait, retry with backoff | +| 500+ | Retry up to 3 times | + +--- + +#### FR-LLM-002: Conversation Management + +**Description**: 会話履歴と状態管理 + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-LLM-002-1 | Store message history | Must | Pending | +| FR-LLM-002-2 | System prompt support | Must | Pending | +| FR-LLM-002-3 | Conversation persistence | Should | Pending | +| FR-LLM-002-4 | Resume from previous session | Should | Pending | +| FR-LLM-002-5 | Export conversation | Could | Pending | + +**Data Model**: +```rust +struct Message { + role: Role, // user, assistant, system + content: Content, // text, tool_use, tool_result + timestamp: DateTime, +} + +struct Conversation { + id: Uuid, + messages: Vec, + system_prompt: Option, + created_at: DateTime, + updated_at: DateTime, +} +``` + +**Storage**: +- Location: `~/.miyabi/conversations/` +- Format: JSON +- Retention: 30 days default + +--- + +#### FR-LLM-003: Token Management + +**Description**: トークンカウントとコンテキスト管理 + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-LLM-003-1 | Token estimation | Must | Pending | +| FR-LLM-003-2 | Display current usage | Must | Pending | +| FR-LLM-003-3 | Auto-prune old messages | Must | Pending | +| FR-LLM-003-4 | Warning at 80% capacity | Should | Pending | +| FR-LLM-003-5 | Manual context clear | Should | Pending | + +**Limits**: +| Model | Context Window | Reserve | +|-------|----------------|---------| +| Claude Sonnet | 200K | 10K | +| Claude Haiku | 200K | 5K | + +**Pruning Strategy**: +1. Keep system prompt always +2. Keep last N messages +3. Summarize old messages + +--- + +#### FR-LLM-004: Tool Calling + +**Description**: Function calling の実装 + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-LLM-004-1 | Send tool definitions | Must | Pending | +| FR-LLM-004-2 | Parse tool_use blocks | Must | Pending | +| FR-LLM-004-3 | Execute tool | Must | Pending | +| FR-LLM-004-4 | Send tool_result | Must | Pending | +| FR-LLM-004-5 | Multi-turn tool use | Must | Pending | + +**Tool Schema Format**: +```json +{ + "name": "read_file", + "description": "Read the contents of a file", + "input_schema": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "Absolute path to the file" + } + }, + "required": ["path"] + } +} +``` + +--- + +### 2.3 Tool System + +#### FR-TOOL-001: Tool Registry + +**Description**: ツールの登録と管理 + +**Requirements**: +| ID | Requirement | Priority | Status | +|----|-------------|----------|--------| +| FR-TOOL-001-1 | Register tool by name | Must | Pending | +| FR-TOOL-001-2 | Lookup tool | Must | Pending | +| FR-TOOL-001-3 | List all tools | Should | Pending | +| FR-TOOL-001-4 | Dynamic registration | Could | Pending | + +**Tool Trait**: +```rust +#[async_trait] +pub trait Tool: Send + Sync { + fn name(&self) -> &str; + fn description(&self) -> &str; + fn input_schema(&self) -> Value; + async fn execute(&self, input: Value) -> Result; +} +``` + +--- + +#### FR-TOOL-002: Read Tool + +**Description**: ファイル読み込み + +**Parameters**: +| Name | Type | Required | Description | +|------|------|----------|-------------| +| file_path | string | Yes | Absolute path | +| offset | number | No | Start line (0-based) | +| limit | number | No | Max lines (default: 2000) | + +**Output**: +``` +Line numbered content (cat -n format) +``` + +**Errors**: +- File not found +- Permission denied +- Binary file + +--- + +#### FR-TOOL-003: Write Tool + +**Description**: ファイル書き込み + +**Parameters**: +| Name | Type | Required | Description | +|------|------|----------|-------------| +| file_path | string | Yes | Absolute path | +| content | string | Yes | Content to write | + +**Behavior**: +- Create directories if needed +- Overwrite existing file +- Preserve permissions + +--- + +#### FR-TOOL-004: Edit Tool + +**Description**: ファイル編集 + +**Parameters**: +| Name | Type | Required | Description | +|------|------|----------|-------------| +| file_path | string | Yes | Absolute path | +| old_string | string | Yes | Text to find | +| new_string | string | Yes | Replacement | +| replace_all | bool | No | Replace all occurrences | + +**Behavior**: +- Exact string match +- Fail if not unique (unless replace_all) +- Preserve indentation + +--- + +#### FR-TOOL-005: Bash Tool + +**Description**: コマンド実行 + +**Parameters**: +| Name | Type | Required | Description | +|------|------|----------|-------------| +| command | string | Yes | Command to execute | +| timeout | number | No | Timeout in ms (default: 120000) | +| cwd | string | No | Working directory | + +**Security**: +- Timeout enforcement +- Output truncation (30K chars) +- Dangerous command warning + +--- + +#### FR-TOOL-006: Glob Tool + +**Description**: ファイルパターン検索 + +**Parameters**: +| Name | Type | Required | Description | +|------|------|----------|-------------| +| pattern | string | Yes | Glob pattern (e.g., "**/*.rs") | +| path | string | No | Base directory | + +**Output**: +- Matching file paths +- Sorted by modification time + +--- + +#### FR-TOOL-007: Grep Tool + +**Description**: テキスト検索 + +**Parameters**: +| Name | Type | Required | Description | +|------|------|----------|-------------| +| pattern | string | Yes | Regex pattern | +| path | string | No | Search path | +| type | string | No | File type (e.g., "rs") | +| output_mode | string | No | content/files/count | + +**Output Modes**: +- `content`: Matching lines with context +- `files_with_matches`: File paths only +- `count`: Match counts + +--- + +## 3. Non-Functional Requirements + +### 3.1 Performance + +| Metric | Requirement | +|--------|-------------| +| Startup time | < 100ms | +| Memory usage | < 50MB idle, < 200MB active | +| Response latency | < 16ms (60 FPS) | +| File operation | < 100ms for 1MB file | + +### 3.2 Reliability + +| Metric | Requirement | +|--------|-------------| +| Crash rate | < 0.1% | +| Error recovery | Graceful degradation | +| Data integrity | No data loss on crash | + +### 3.3 Security + +| Area | Requirement | +|------|-------------| +| API keys | Environment variables only | +| File access | Validate paths, prevent traversal | +| Command execution | Timeout, sandboxing | +| Permissions | Follow least privilege | + +### 3.4 Usability + +| Aspect | Requirement | +|--------|-------------| +| Learning curve | < 5 minutes for basic use | +| Error messages | Clear, actionable | +| Help system | Built-in --help | +| Keyboard shortcuts | Discoverable, consistent | + +### 3.5 Compatibility + +| Platform | Support | +|----------|---------| +| macOS | 12+ (Monterey) | +| Linux | Ubuntu 20.04+, Debian 11+ | +| Windows | WSL2 | + +--- + +## 4. Technical Specifications + +### 4.1 Architecture + +``` +┌─────────────────────────────────────────┐ +│ miyabi-cli │ +│ (CLI entry point, argument parsing) │ +└─────────────────┬───────────────────────┘ + │ +┌─────────────────▼───────────────────────┐ +│ miyabi-tui │ +│ (Terminal UI, Ratatui widgets) │ +└─────────────────┬───────────────────────┘ + │ +┌─────────────────▼───────────────────────┐ +│ miyabi-core │ +│ (LLM client, Tool system, State) │ +└─────────────────────────────────────────┘ +``` + +### 4.2 Dependencies + +**Core**: +- tokio: Async runtime +- ratatui: TUI framework +- crossterm: Terminal backend +- clap: CLI parsing + +**LLM**: +- reqwest: HTTP client +- serde_json: JSON handling + +**Text**: +- pulldown-cmark: Markdown parsing +- syntect: Syntax highlighting + +### 4.3 Configuration + +**Config File**: `~/.miyabi/config.toml` + +```toml +[general] +theme = "dark" +editor = "vim" + +[llm] +model = "claude-sonnet-4-20250514" +max_tokens = 4096 +temperature = 0.7 + +[tools] +timeout = 120000 +auto_approve = ["read_file", "glob"] +``` + +--- + +## 5. User Interface Specifications + +### 5.1 Layout + +``` +┌─────────────────────────────────────────┐ +│ miyabi v1.0.0 Tokens: 1.2K/200K ⚡ │ Header +├─────────────────────────────────────────┤ +│ │ +│ User: How do I implement... │ +│ │ +│ Assistant: Here's how you can... │ +│ ```rust │ Chat History +│ fn main() { │ +│ println!("Hello"); │ +│ } │ +│ ``` │ +│ │ +├─────────────────────────────────────────┤ +│ > Type your message... │ Input +│ │ +├─────────────────────────────────────────┤ +│ Ctrl+C: Cancel Ctrl+L: Clear ?: Help │ Status Bar +└─────────────────────────────────────────┘ +``` + +### 5.2 Color Palette + +| Element | Light | Dark | +|---------|-------|------| +| Background | #FFFFFF | #0D1117 | +| Text | #24292F | #C9D1D9 | +| Code | #F6F8FA | #161B22 | +| Accent | #0969DA | #58A6FF | +| Success | #1A7F37 | #3FB950 | +| Error | #CF222E | #F85149 | +| Warning | #9A6700 | #D29922 | + +--- + +## 6. API Specifications + +### 6.1 CLI Interface + +```bash +miyabi [OPTIONS] [COMMAND] + +Commands: + chat Start interactive chat (default) + run Execute a single prompt + resume Resume previous session + config Manage configuration + version Show version + +Options: + -m, --model Model to use + -s, --system System prompt + -v, --verbose Verbose output + -h, --help Show help +``` + +### 6.2 Exit Codes + +| Code | Meaning | +|------|---------| +| 0 | Success | +| 1 | General error | +| 2 | Invalid arguments | +| 3 | API error | +| 4 | Tool execution error | + +--- + +## 7. Testing Requirements + +### 7.1 Unit Tests + +- Coverage: > 80% +- All public functions +- Edge cases covered + +### 7.2 Integration Tests + +- LLM API mocking +- Full conversation flow +- Tool execution + +### 7.3 E2E Tests + +- Complete user scenarios +- Performance benchmarks + +--- + +## 8. Documentation Requirements + +- README.md +- CHANGELOG.md +- API documentation (rustdoc) +- User guide +- Contributing guide + +--- + +## 9. Glossary + +| Term | Definition | +|------|------------| +| TUI | Terminal User Interface | +| LLM | Large Language Model | +| SSE | Server-Sent Events | +| Tool | Function callable by LLM | + +--- + +**Document Status**: Draft +**Next Review**: Sprint 1 End diff --git a/docs/SPRINT_PLANNING.md b/docs/SPRINT_PLANNING.md new file mode 100644 index 0000000..06541f2 --- /dev/null +++ b/docs/SPRINT_PLANNING.md @@ -0,0 +1,427 @@ +# Sprint Planning - miyabi-cli-standalone + +**Project**: miyabi-cli-standalone +**Total Sprints**: 4 +**Sprint Duration**: 5 days (1 week) +**Start Date**: 2025-11-25 + +--- + +## 📊 Overview + +| Sprint | Period | Milestone | Goal | +|--------|--------|-----------|------| +| 1 | Nov 25-29 | v0.2.0 | Foundation | +| 2 | Dec 2-6 | v0.2.0 | Parser & State | +| 3 | Dec 9-13 | v0.3.0/v1.0.0 | Integration | +| 4 | Dec 16-20 | v1.0.0 | Production Ready | + +--- + +# Sprint 1: Foundation + +**Period**: November 25-29, 2025 +**Goal**: Core structures for all streams + +## 🎯 Sprint Goal + +> 全3ストリーム(TUI、LLM、Tools)の基盤構造を確立する + +## 📋 Sprint Backlog + +| Issue | Task | Priority | Points | Agent | +|-------|------|----------|--------|-------| +| #10 | MarkdownStream core structure | P0 | 3 | CodeGen | +| #15 | DiffRender core structure | P1 | 3 | CodeGen | +| #19 | Anthropic API client | P0 | 5 | CodeGen | +| #24 | Tool trait and registry | P0 | 5 | CodeGen | + +**Total Points**: 16 + +## 📅 Daily Breakdown + +### Day 1 (Mon) - Kickoff + +**Morning** +```bash +# 全タスク並列開始 +miyabi agent run coordinator --issue 10 & +miyabi agent run coordinator --issue 15 & +miyabi agent run coordinator --issue 19 & +miyabi agent run coordinator --issue 24 & +``` + +**Tasks**: +- [ ] #10 開始 - MarkdownStream struct定義 +- [ ] #15 開始 - DiffRender struct定義 +- [ ] #19 開始 - AnthropicClient struct定義 +- [ ] #24 開始 - Tool trait定義 + +**End of Day**: 基本struct完成 + +### Day 2 (Tue) - Core Implementation + +**Tasks**: +- [ ] #10 完了 - State enum、buffer管理 +- [ ] #15 完了 - Diff parsing logic +- [ ] #19 継続 - Streaming SSE処理 +- [ ] #24 継続 - Registry実装 + +**Reviews**: +```bash +gh pr list --state open +gh pr review <番号> --approve +``` + +### Day 3 (Wed) - Integration + +**Tasks**: +- [ ] #19 完了 - Error handling、retry +- [ ] #24 完了 - Schema generation + +**Code Review**: +- [ ] #10 PR レビュー・マージ +- [ ] #15 PR レビュー・マージ + +### Day 4 (Thu) - Testing + +**Tasks**: +- [ ] 統合テスト実行 +- [ ] #19 PR レビュー・マージ +- [ ] #24 PR レビュー・マージ + +```bash +cargo test --all +cargo clippy --all-targets +``` + +### Day 5 (Fri) - Sprint Review + +**Tasks**: +- [ ] 全PRマージ確認 +- [ ] デモ準備 +- [ ] Sprint 2準備 + +## ✅ Acceptance Criteria + +- [ ] `MarkdownStream` が文字を受け取り状態遷移できる +- [ ] `DiffRender` がunified diffをパースできる +- [ ] `AnthropicClient` がAPIに接続しストリーム受信できる +- [ ] `Tool` traitが定義され、registryに登録できる +- [ ] 全テストがパス +- [ ] Clippyエラーなし + +## 🚧 Risks & Mitigations + +| Risk | Mitigation | +|------|------------| +| API接続失敗 | モック作成、retry実装 | +| 設計変更 | 早期レビュー | + +--- + +# Sprint 2: Parser & State + +**Period**: December 2-6, 2025 +**Goal**: Incremental parsing and state management + +## 🎯 Sprint Goal + +> パーサーと状態管理を実装し、基盤構造を完成させる + +## 📋 Sprint Backlog + +| Issue | Task | Priority | Points | Depends | +|-------|------|----------|--------|---------| +| #11 | Incremental markdown parser | P0 | 5 | #10 | +| #16 | Diff visualization | P1 | 5 | #15 | +| #20 | Conversation state | P0 | 5 | #19 | +| #25 | File operation tools | P0 | 5 | #24 | + +**Total Points**: 20 + +## 📅 Daily Breakdown + +### Day 1 (Mon) - Kickoff + +```bash +miyabi agent run coordinator --issue 11 & +miyabi agent run coordinator --issue 16 & +miyabi agent run coordinator --issue 20 & +miyabi agent run coordinator --issue 25 & +``` + +**Tasks**: +- [ ] #11 開始 - pulldown-cmark統合 +- [ ] #16 開始 - Color scheme実装 +- [ ] #20 開始 - Message history構造 +- [ ] #25 開始 - ReadTool実装 + +### Day 2 (Tue) - Core Features + +**Tasks**: +- [ ] #11 継続 - Partial parsing +- [ ] #16 継続 - Line numbers、indicators +- [ ] #20 継続 - Serialization +- [ ] #25 継続 - WriteTool、EditTool + +### Day 3 (Wed) - Completion + +**Tasks**: +- [ ] #11 完了 - Event→Span変換 +- [ ] #16 完了 - 全視覚要素 +- [ ] #20 完了 - Persistence +- [ ] #25 完了 - 全File tools + +### Day 4 (Thu) - Review + +**Tasks**: +- [ ] PRレビュー +- [ ] 統合テスト +- [ ] Bug fix + +### Day 5 (Fri) - Sprint Review + +**Tasks**: +- [ ] 全PRマージ +- [ ] v0.2.0リリース準備 +- [ ] Sprint 3準備 + +## ✅ Acceptance Criteria + +- [ ] Markdown streaming が部分コンテンツを正しくレンダリング +- [ ] Diff表示が色分け、行番号付き +- [ ] Conversation履歴が保存・復元可能 +- [ ] File tools (Read/Write/Edit) が全て動作 +- [ ] 全テストパス + +--- + +# Sprint 3: Integration + +**Period**: December 9-13, 2025 +**Goal**: LLM tools and advanced features + +## 🎯 Sprint Goal + +> LLMツール連携と高度な機能を実装する + +## 📋 Sprint Backlog + +| Issue | Task | Priority | Points | Depends | +|-------|------|----------|--------|---------| +| #12 | Code block handling | P1 | 3 | #11 | +| #17 | Syntax highlighting in diff | P2 | 3 | #16 | +| #21 | Token management | P1 | 5 | #20 | +| #22 | Tool definitions | P0 | 5 | #20 | +| #26 | Bash tool | P0 | 5 | #25 | + +**Total Points**: 21 + +## 📅 Daily Breakdown + +### Day 1 (Mon) - Kickoff + +```bash +miyabi agent run coordinator --issue 12 & +miyabi agent run coordinator --issue 17 & +miyabi agent run coordinator --issue 21 & +miyabi agent run coordinator --issue 22 & +miyabi agent run coordinator --issue 26 & +``` + +### Day 2 (Tue) - Implementation + +**Focus**: #22 (Tool definitions) - CRITICAL PATH + +### Day 3 (Wed) - Integration + +**Tasks**: +- [ ] Tool definitions と API client統合 +- [ ] Bash tool と File tools統合 + +### Day 4 (Thu) - Testing + +**Tasks**: +- [ ] End-to-end テスト +- [ ] Tool実行テスト + +### Day 5 (Fri) - Sprint Review + +**Milestone**: v0.3.0 機能フリーズ + +## ✅ Acceptance Criteria + +- [ ] Code blockがシンタックスハイライト付きでレンダリング +- [ ] DiffにもSyntax highlighting適用 +- [ ] Token count表示、自動pruning動作 +- [ ] Tool definitionsがAPI requestに含まれる +- [ ] Bash toolがコマンド実行、結果返却 + +--- + +# Sprint 4: Production Ready + +**Period**: December 16-20, 2025 +**Goal**: Polish and production readiness + +## 🎯 Sprint Goal + +> プロダクション品質に仕上げ、v1.0.0をリリースする + +## 📋 Sprint Backlog + +| Issue | Task | Priority | Points | Depends | +|-------|------|----------|--------|---------| +| #13 | Cursor tracking | P2 | 2 | #12 | +| #14 | Markdown tests | P2 | 3 | #13 | +| #18 | Diff navigation | P2 | 2 | #17 | +| #23 | Rate limiting | P2 | 3 | #22 | +| #27 | Search tools | P1 | 5 | #26 | +| #28 | Result formatting | P2 | 3 | #27 | + +**Total Points**: 18 + +## 📅 Daily Breakdown + +### Day 1 (Mon) - Kickoff + +```bash +miyabi agent run coordinator --issue 13 & +miyabi agent run coordinator --issue 18 & +miyabi agent run coordinator --issue 23 & +miyabi agent run coordinator --issue 27 & +``` + +### Day 2 (Tue) - Completion + +**Tasks**: +- [ ] #13 完了 +- [ ] #14 開始・完了 +- [ ] #18 完了 +- [ ] #23 完了 +- [ ] #27 完了 +- [ ] #28 開始 + +### Day 3 (Wed) - Final Integration + +**Tasks**: +- [ ] #28 完了 +- [ ] Full integration test +- [ ] Performance testing + +### Day 4 (Thu) - QA + +**Tasks**: +- [ ] Bug fixes +- [ ] Documentation +- [ ] Release notes + +### Day 5 (Fri) - Release + +**Tasks**: +- [ ] v1.0.0 タグ作成 +- [ ] Release作成 +- [ ] 🎉 Celebration! + +## ✅ Acceptance Criteria + +- [ ] 全機能が動作 +- [ ] ドキュメント完備 +- [ ] パフォーマンス基準達成 +- [ ] セキュリティチェック完了 +- [ ] v1.0.0 リリース + +--- + +## 📊 Sprint Metrics + +### Velocity Tracking + +| Sprint | Planned | Completed | Velocity | +|--------|---------|-----------|----------| +| 1 | 16 | - | - | +| 2 | 20 | - | - | +| 3 | 21 | - | - | +| 4 | 18 | - | - | + +**Total**: 75 points + +### Burndown + +Sprint終了時に更新 + +--- + +## 🔄 Ceremonies + +### Daily Standup (10min) + +```bash +# 毎朝実行 +miyabi status +gh issue list --label "🏗️ state:implementing" +``` + +### Sprint Planning (始め) + +1. Sprint Goal確認 +2. Backlog確定 +3. タスク割り当て +4. リスク確認 + +### Sprint Review (終わり) + +1. 完了タスクデモ +2. フィードバック収集 +3. 次Sprint調整 + +### Sprint Retrospective + +- What went well? +- What to improve? +- Action items + +--- + +## 🚀 Execution Commands + +### Sprint 1 Quick Start + +```bash +cd /Users/shunsuke/Dev/miyabi-cli-standalone + +# Critical Path開始 +miyabi agent run coordinator --issue 19 # API Client +miyabi agent run coordinator --issue 24 # Tool Trait + +# Parallel tasks +miyabi agent run coordinator --issue 10 # Markdown Core +miyabi agent run coordinator --issue 15 # Diff Core +``` + +### Progress Check + +```bash +# 完了タスク +gh issue list --state closed --label "✅ state:done" + +# 進行中 +gh issue list --label "🏗️ state:implementing" + +# PRs +gh pr list --state open +``` + +--- + +## 📝 Notes + +- 各SprintでCritical Pathを優先 +- ブロッカーは即座にエスカレーション +- PRは24時間以内にレビュー +- テストは継続的に実行 + +--- + +**Let's build something amazing! 🚀** diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md new file mode 100644 index 0000000..04d4863 --- /dev/null +++ b/docs/TROUBLESHOOTING.md @@ -0,0 +1,278 @@ +# Troubleshooting Guide + +Miyabi使用中に発生する可能性のある問題と解決策をまとめています。 + +## 🔧 環境関連 + +### GITHUB_TOKENが設定されていない + +**症状**: +``` +Error: GITHUB_TOKEN not set +``` + +**解決策**: +1. トークンを取得: https://github.com/settings/tokens/new +2. 環境変数を設定: + ```bash + export GITHUB_TOKEN=ghp_xxxxx + ``` +3. シェルプロファイルに追加(永続化): + ```bash + echo 'export GITHUB_TOKEN=ghp_xxxxx' >> ~/.zshrc + source ~/.zshrc + ``` + +### ANTHROPIC_API_KEYが設定されていない + +**症状**: +``` +Error: ANTHROPIC_API_KEY not set +``` + +**解決策**: +1. Anthropic Consoleでキー取得: https://console.anthropic.com/ +2. 環境変数を設定: + ```bash + export ANTHROPIC_API_KEY=sk-ant-xxxxx + ``` + +## 🐛 Git関連 + +### Git repositoryが見つからない + +**症状**: +``` +Error: Not a git repository +``` + +**解決策**: +```bash +cd your-project +git init +``` + +### Worktreeが残ったまま + +**症状**: +``` +Error: Worktree already exists: .worktrees/issue-123 +``` + +**解決策**: +```bash +# Worktree一覧確認 +git worktree list + +# 不要なWorktreeを削除 +git worktree remove .worktrees/issue-123 + +# すべてのstale Worktreeをクリーンアップ +git worktree prune +``` + +### マージコンフリクト + +**症状**: +``` +CONFLICT (content): Merge conflict in src/main.rs +``` + +**解決策**: +```bash +# コンフリクトファイルを確認 +git status + +# 手動でコンフリクトを解決 +# エディタでファイルを開き、<<<<<<<, =======, >>>>>>> マーカーを削除 + +# 解決後 +git add src/main.rs +git commit -m "fix: resolve merge conflict" +``` + +## 🤖 Agent関連 + +### Agent実行が失敗する + +**症状**: +``` +Error: Agent execution failed +``` + +**解決策**: +1. ログファイル確認: + ```bash + tail -f logs/miyabi-$(date +%Y%m%d).log + ``` +2. Issue番号が正しいか確認: + ```bash + gh issue list + ``` +3. Labelが正しく設定されているか確認 + +### Issue番号が見つからない + +**症状**: +``` +Error: Issue #123 not found +``` + +**解決策**: +```bash +# Issue一覧確認 +gh issue list --limit 50 + +# 正しい番号で再実行 +miyabi agent run coordinator --issue 正しい番号 +``` + +## 📦 インストール関連 + +### `miyabi` コマンドが見つからない + +**症状**: +``` +command not found: miyabi +``` + +**解決策**: +```bash +# crates.ioから再インストール +cargo install miyabi-cli --force + +# パス確認 +which miyabi + +# Cargo binディレクトリがPATHに含まれているか確認 +echo $PATH | grep -o "$HOME/.cargo/bin" + +# なければ追加 +echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.zshrc +source ~/.zshrc +``` + +### コンパイルエラー + +**症状**: +``` +error: failed to compile miyabi-cli +``` + +**解決策**: +```bash +# Rustを最新版にアップデート +rustup update stable + +# Cargoキャッシュをクリア +rm -rf ~/.cargo/registry +rm -rf ~/.cargo/git + +# 再インストール +cargo install miyabi-cli +``` + +## 🌐 GitHub関連 + +### API Rate Limit + +**症状**: +``` +Error: API rate limit exceeded +``` + +**解決策**: +1. GitHubにログイン状態か確認: + ```bash + gh auth status + ``` +2. Personal Access Tokenのスコープ確認 +3. しばらく待つ(Rate limitは1時間でリセット) + +### Permission denied + +**症状**: +``` +Error: Resource not accessible by personal access token +``` + +**解決策**: +1. トークンのスコープを確認: `repo`, `workflow` が必要 +2. 新しいトークンを生成 +3. 環境変数を更新 + +## 🔍 デバッグ方法 + +### 詳細ログを有効化 + +`.miyabi.yml` でログレベルを変更: +```yaml +logging: + level: debug # info → debug + directory: "./logs" +``` + +### ログファイルの確認 + +```bash +# 最新のログ +tail -100 logs/miyabi-$(date +%Y%m%d).log + +# エラーのみ抽出 +grep -i "error\|fail" logs/miyabi-*.log + +# 特定のAgentのログ +grep -i "CoordinatorAgent" logs/miyabi-*.log +``` + +### miyabi status の活用 + +```bash +miyabi status + +# 出力例: +# Miyabi Installation: ✅ or ❌ +# Environment: GITHUB_TOKEN, ANTHROPIC_API_KEY の状態 +# Git Repository: ブランチ、コミット状態 +# Worktrees: アクティブなWorktree数 +``` + +## 🆘 それでも解決しない場合 + +### サポートを受ける + +1. **GitHub Issues**: https://github.com/ShunsukeHayashi/Miyabi/issues + - 詳細なエラーメッセージを含めてください + - `miyabi status` の出力を添付 + - ログファイルの関連部分を添付 + +2. **Discord Community**: (準備中) + +3. **ドキュメント**: + - [GETTING_STARTED.md](GETTING_STARTED.md) + - [CLAUDE.md](../CLAUDE.md) + - [GitHub Discussions](https://github.com/ShunsukeHayashi/Miyabi/discussions) + +### 報告に含めるべき情報 + +```bash +# システム情報 +uname -a + +# Rustバージョン +rustc --version +cargo --version + +# miyabiバージョン +miyabi --version + +# プロジェクト状態 +miyabi status + +# 直近のログ +tail -50 logs/miyabi-$(date +%Y%m%d).log +``` + +--- + +**Miyabi** - Beauty in Autonomous Development 🌸 diff --git a/docs/WBS.md b/docs/WBS.md new file mode 100644 index 0000000..ae78f16 --- /dev/null +++ b/docs/WBS.md @@ -0,0 +1,178 @@ +# Work Breakdown Structure (WBS) + +**Project**: miyabi-cli-standalone +**Version**: v1.0.0 +**Created**: 2025-11-22 + +--- + +## 1. TUI Foundation (v0.2.0) + +### 1.1 Streaming Markdown Renderer (#2) +- **1.1.1** Core structure and state management (#10) - P0 - 4h +- **1.1.2** Incremental parser with pulldown-cmark (#11) - P0 - 6h +- **1.1.3** Code block handling with syntax highlighting (#12) - P1 - 4h +- **1.1.4** Cursor and scroll position tracking (#13) - P2 - 3h +- **1.1.5** Unit tests (#14) - P2 - 4h + +**Subtotal: ~700 lines, 21h** + +### 1.2 Git Diff Visualization (#3) +- **1.2.1** Core structure and diff parsing (#15) - P1 - 4h +- **1.2.2** Visualization with colors and indicators (#16) - P1 - 6h +- **1.2.3** Syntax highlighting in diff content (#17) - P2 - 4h +- **1.2.4** Scrollable view with navigation (#18) - P2 - 3h + +**Subtotal: ~650 lines, 17h** + +--- + +## 2. Chat Composer (v0.3.0) + +### 2.1 Chat Input Component (#4) +- **2.1.1** Separate input handling from main app +- **2.1.2** Multi-line input support +- **2.1.3** Command history navigation +- **2.1.4** Auto-completion +- **2.1.5** Syntax highlighting in input + +**Subtotal: ~3,938 lines** + +### 2.2 Text Area Widget (#5) +- **2.2.1** Full-featured text area widget +- **2.2.2** Text selection support +- **2.2.3** Copy/paste functionality +- **2.2.4** Undo/redo stack + +**Subtotal: ~2,213 lines** + +--- + +## 3. Approval & Navigation (v0.4.0) + +### 3.1 Approval Overlay (#6) +- **3.1.1** Tool execution approval UI +- **3.1.2** Y/N/Always/Never options +- **3.1.3** Risk level display +- **3.1.4** Preview of changes + +**Subtotal: ~656 lines** + +### 3.2 Session Resume (#7) +- **3.2.1** Session resume selection +- **3.2.2** Conversation history browser +- **3.2.3** Search functionality +- **3.2.4** Preview pane + +**Subtotal: ~1,580 lines** + +--- + +## 4. LLM Integration (v1.0.0) + +### 4.1 Claude API Integration (#8) +- **4.1.1** Anthropic API client with streaming (#19) - P0 - 8h +- **4.1.2** Conversation state and message history (#20) - P0 - 6h +- **4.1.3** Token counting and context window (#21) - P1 - 6h +- **4.1.4** Tool definitions and function calling (#22) - P0 - 8h +- **4.1.5** Rate limiting and retry logic (#23) - P2 - 4h + +**Subtotal: ~1,600 lines, 32h** + +--- + +## 5. Tool Execution System (v1.0.0) + +### 5.1 Tool System (#9) +- **5.1.1** Tool trait and registry system (#24) - P0 - 6h +- **5.1.2** File operation tools (Read, Write, Edit) (#25) - P0 - 8h +- **5.1.3** Bash tool with sandboxing (#26) - P0 - 8h +- **5.1.4** Search tools (Glob, Grep) (#27) - P1 - 6h +- **5.1.5** Result formatting and error handling (#28) - P2 - 4h + +**Subtotal: ~1,800 lines, 32h** + +--- + +## Summary + +| Phase | Milestone | Lines | Hours | Issues | +|-------|-----------|-------|-------|--------| +| 1 | v0.2.0 TUI Foundation | 1,350 | 38h | #2, #3, #10-18 | +| 2 | v0.3.0 Chat Composer | 6,151 | - | #4, #5 | +| 3 | v0.4.0 Approval & Nav | 2,236 | - | #6, #7 | +| 4 | v1.0.0 Production | 3,400 | 64h | #8, #9, #19-28 | + +**Total: ~13,137+ lines** + +--- + +## Critical Path + +``` +#19 → #20 → #22 → #24 → #25 → #26 → #27 → #28 + │ │ + API Tools +``` + +**Critical Path Duration: ~42h** + +--- + +## Dependencies Matrix + +| Task | Depends On | Blocks | +|------|------------|--------| +| #10 | - | #11 | +| #11 | #10 | #12 | +| #12 | #11 | #13 | +| #13 | #12 | #14 | +| #14 | #13 | - | +| #15 | - | #16 | +| #16 | #15 | #17 | +| #17 | #16 | #18 | +| #18 | #17 | - | +| #19 | - | #20, #23 | +| #20 | #19 | #21, #22 | +| #21 | #20 | - | +| #22 | #20 | - | +| #23 | #19 | - | +| #24 | - | #25, #26, #27 | +| #25 | #24 | #26 | +| #26 | #25 | #27 | +| #27 | #26 | #28 | +| #28 | #27 | - | + +--- + +## Resource Allocation + +### Parallel Streams (Max 3) + +**Stream A**: TUI (#10-14, #15-18) +**Stream B**: LLM (#19-23) +**Stream C**: Tools (#24-28) + +### Sprint Allocation + +| Sprint | Stream A | Stream B | Stream C | +|--------|----------|----------|----------| +| 1 | #10, #15 | #19 | #24 | +| 2 | #11, #16 | #20 | #25 | +| 3 | #12, #17 | #21, #22 | #26 | +| 4 | #13, #14, #18 | #23 | #27, #28 | + +--- + +## Risk Register + +| Risk | Impact | Mitigation | +|------|--------|------------| +| API rate limits | High | Implement caching, retry logic | +| Complex streaming | Medium | Incremental implementation | +| Tool security | High | Sandboxing, input validation | +| Performance | Medium | Benchmarking, profiling | + +--- + +**Last Updated**: 2025-11-22 diff --git a/docs/gantt-chart.puml b/docs/gantt-chart.puml new file mode 100644 index 0000000..5e4414b --- /dev/null +++ b/docs/gantt-chart.puml @@ -0,0 +1,118 @@ +@startgantt miyabi-cli-gantt + +title miyabi-cli-standalone - Project Timeline +project starts 2025-11-25 + +' === Milestones === +[v0.2.0 TUI Foundation] happens at 2025-12-06 +[v1.0.0 Production Ready] happens at 2025-12-20 + +' === Sprint 1: Foundation === +[Sprint 1] as [S1] lasts 5 days and is colored in LightBlue +[S1] starts 2025-11-25 + +-- Sprint 1: Foundation -- + +[#10 Core Structure] as [T10] lasts 1 day +[T10] starts at [S1]'s start +[T10] is colored in Coral + +[#15 Diff Core] as [T15] lasts 1 day +[T15] starts at [S1]'s start +[T15] is colored in Orange + +[#19 API Client] as [T19] lasts 2 days +[T19] starts at [S1]'s start +[T19] is colored in Coral + +[#24 Tool Trait] as [T24] lasts 2 days +[T24] starts at [S1]'s start +[T24] is colored in Coral + +' === Sprint 2: Parser & State === +[Sprint 2] as [S2] lasts 5 days and is colored in LightGreen +[S2] starts at [S1]'s end + +-- Sprint 2: Parser & State -- + +[#11 Incremental Parser] as [T11] lasts 2 days +[T11] starts at [T10]'s end +[T11] is colored in Coral + +[#16 Diff Visualization] as [T16] lasts 2 days +[T16] starts at [T15]'s end +[T16] is colored in Orange + +[#20 Conversation State] as [T20] lasts 2 days +[T20] starts at [T19]'s end +[T20] is colored in Coral + +[#25 File Tools] as [T25] lasts 2 days +[T25] starts at [T24]'s end +[T25] is colored in Coral + +' === Sprint 3: Integration === +[Sprint 3] as [S3] lasts 5 days and is colored in LightYellow +[S3] starts at [S2]'s end + +-- Sprint 3: Integration -- + +[#12 Code Blocks] as [T12] lasts 1 day +[T12] starts at [T11]'s end +[T12] is colored in Orange + +[#17 Syntax in Diff] as [T17] lasts 1 day +[T17] starts at [T16]'s end +[T17] is colored in Yellow + +[#21 Token Management] as [T21] lasts 2 days +[T21] starts at [T20]'s end +[T21] is colored in Orange + +[#22 Tool Definitions] as [T22] lasts 2 days +[T22] starts at [T20]'s end +[T22] is colored in Coral + +[#26 Bash Tool] as [T26] lasts 2 days +[T26] starts at [T25]'s end +[T26] is colored in Coral + +' === Sprint 4: Polish === +[Sprint 4] as [S4] lasts 5 days and is colored in LightCoral +[S4] starts at [S3]'s end + +-- Sprint 4: Polish -- + +[#13 Cursor Tracking] as [T13] lasts 1 day +[T13] starts at [T12]'s end +[T13] is colored in Yellow + +[#14 Tests] as [T14] lasts 1 day +[T14] starts at [T13]'s end +[T14] is colored in Yellow + +[#18 Navigation] as [T18] lasts 1 day +[T18] starts at [T17]'s end +[T18] is colored in Yellow + +[#23 Rate Limiting] as [T23] lasts 1 day +[T23] starts at [T22]'s end +[T23] is colored in Yellow + +[#27 Search Tools] as [T27] lasts 2 days +[T27] starts at [T26]'s end +[T27] is colored in Orange + +[#28 Result Formatting] as [T28] lasts 1 day +[T28] starts at [T27]'s end +[T28] is colored in Yellow + +' Critical path highlighting +[T19] is colored in Red +[T20] is colored in Red +[T22] is colored in Red +[T24] is colored in Red +[T25] is colored in Red +[T26] is colored in Red + +@endgantt diff --git a/docs/wbs-diagram.puml b/docs/wbs-diagram.puml new file mode 100644 index 0000000..5ec9f41 --- /dev/null +++ b/docs/wbs-diagram.puml @@ -0,0 +1,104 @@ +@startuml miyabi-cli-wbs + +!theme plain +title miyabi-cli-standalone - Critical Path & WBS + +' Define colors +!$critical = "#FF6B6B" +!$high = "#FFA94D" +!$medium = "#69DB7C" +!$low = "#74C0FC" + +' Milestones +rectangle "v0.2.0\nTUI Foundation" as M1 #LightBlue +rectangle "v0.3.0\nChat Composer" as M2 #LightGreen +rectangle "v0.4.0\nApproval & Nav" as M3 #LightYellow +rectangle "v1.0.0\nProduction" as M4 #LightCoral + +' === Stream A: TUI Rendering === +package "Stream A: TUI Rendering" { + rectangle "#10\nCore Structure" as T10 $critical + rectangle "#11\nParser" as T11 $critical + rectangle "#12\nCode Blocks" as T12 $high + rectangle "#13\nCursor" as T13 $medium + rectangle "#14\nTests" as T14 $medium + + rectangle "#15\nDiff Core" as T15 $high + rectangle "#16\nVisualization" as T16 $high + rectangle "#17\nSyntax" as T17 $medium + rectangle "#18\nNavigation" as T18 $medium +} + +' === Stream B: LLM Integration === +package "Stream B: LLM Integration" #FFE4E1 { + rectangle "#19\nAPI Client" as T19 $critical + rectangle "#20\nConversation" as T20 $critical + rectangle "#21\nTokens" as T21 $high + rectangle "#22\nTool Defs" as T22 $critical + rectangle "#23\nRate Limit" as T23 $medium +} + +' === Stream C: Tool System === +package "Stream C: Tool System" #E8F5E9 { + rectangle "#24\nTool Trait" as T24 $critical + rectangle "#25\nFile Tools" as T25 $critical + rectangle "#26\nBash Tool" as T26 $critical + rectangle "#27\nSearch" as T27 $high + rectangle "#28\nFormatting" as T28 $medium +} + +' Dependencies - Stream A +T10 --> T11 +T11 --> T12 +T12 --> T13 +T13 --> T14 + +T15 --> T16 +T16 --> T17 +T17 --> T18 + +' Dependencies - Stream B (CRITICAL PATH) +T19 --> T20 : **CRITICAL** +T20 --> T21 +T20 --> T22 : **CRITICAL** +T19 --> T23 + +' Dependencies - Stream C +T24 --> T25 : **CRITICAL** +T25 --> T26 : **CRITICAL** +T26 --> T27 +T27 --> T28 + +' Cross-stream dependencies +T22 ..> T24 : "requires" + +' Milestone connections +T14 --> M1 +T18 --> M1 +M1 --> M2 +M2 --> M3 +T23 --> M4 +T28 --> M4 + +' Legend +legend right + |= Color |= Priority | + | <$critical> | P0 Critical | + | <$high> | P1 High | + | <$medium> | P2 Medium | + | <$low> | P3 Low | +endlegend + +note bottom of T19 + **Critical Path Start** + API Client is the foundation + for all LLM functionality +end note + +note bottom of T28 + **Critical Path End** + Result formatting completes + the tool system +end note + +@enduml