Add Chinese translation for README and implement README translation script
- Created README.zh.md for Chinese localization of the project. - Developed a README translation script to support multiple languages using Claude Agent SDK. - Implemented CLI and programmatic usage for the translation tool. - Added examples for integrating the translation tool into build scripts and CI/CD pipelines. - Enhanced error handling and logging for translation processes. - Included support for various languages and output customization options.
This commit is contained in:
+435
@@ -0,0 +1,435 @@
|
||||
```markdown
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-dark-mode.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp">
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp" alt="Claude-Mem" width="400">
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
<h4 align="center"><a href="https://claude.com/claude-code" target="_blank">Claude Code</a>向けに構築された永続的メモリ圧縮システム</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-AGPL%203.0-blue.svg" alt="License">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/version-6.5.0-green.svg" alt="Version">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg" alt="Node">
|
||||
</a>
|
||||
<a href="https://github.com/thedotmack/awesome-claude-code">
|
||||
<img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Claude Code">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/cm-preview.gif" alt="Claude-Mem Preview" width="800">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#クイックスタート">クイックスタート</a> •
|
||||
<a href="#仕組み">仕組み</a> •
|
||||
<a href="#mcp検索ツール">検索ツール</a> •
|
||||
<a href="#ドキュメント">ドキュメント</a> •
|
||||
<a href="#設定">設定</a> •
|
||||
<a href="#トラブルシューティング">トラブルシューティング</a> •
|
||||
<a href="#ライセンス">ライセンス</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Claude-Memは、ツール使用の観察結果を自動的にキャプチャし、セマンティックサマリーを生成し、それらを将来のセッションで利用可能にすることで、セッション間でコンテキストをシームレスに保持します。これにより、Claudeはセッションが終了または再接続した後でも、プロジェクトに関する知識の連続性を維持できます。
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## クイックスタート
|
||||
|
||||
ターミナルで新しいClaude Codeセッションを開始し、以下のコマンドを入力してください:
|
||||
|
||||
```
|
||||
> /plugin marketplace add thedotmack/claude-mem
|
||||
|
||||
> /plugin install claude-mem
|
||||
```
|
||||
|
||||
Claude Codeを再起動します。以前のセッションのコンテキストが新しいセッションに自動的に表示されます。
|
||||
|
||||
**主な機能:**
|
||||
|
||||
- 🧠 **永続的メモリ** - コンテキストがセッション間で保持されます
|
||||
- 📊 **段階的開示** - トークンコストの可視化を伴う階層的メモリ取得
|
||||
- 🔍 **スキルベース検索** - mem-searchスキルでプロジェクト履歴をクエリ(約2,250トークン節約)
|
||||
- 🖥️ **Web Viewer UI** - http://localhost:37777でリアルタイムメモリストリーム
|
||||
- 💻 **Claude Desktopスキル** - Claude Desktopの会話からメモリを検索
|
||||
- 🔒 **プライバシー制御** - `<private>`タグを使用して機密コンテンツをストレージから除外
|
||||
- ⚙️ **コンテキスト設定** - どのコンテキストが注入されるかの詳細な制御
|
||||
- 🤖 **自動動作** - 手動介入不要
|
||||
- 🔗 **引用** - `claude-mem://` URIで過去の決定を参照
|
||||
- 🧪 **ベータチャンネル** - バージョン切り替えでEndless Modeなどの実験的機能を試す
|
||||
|
||||
---
|
||||
|
||||
## ドキュメント
|
||||
|
||||
📚 **[完全なドキュメントを表示](docs/)** - GitHubでMarkdownドキュメントを閲覧
|
||||
|
||||
💻 **ローカルプレビュー**: Mintlifyドキュメントをローカルで実行:
|
||||
|
||||
```bash
|
||||
cd docs
|
||||
npx mintlify dev
|
||||
```
|
||||
|
||||
### はじめに
|
||||
|
||||
- **[インストールガイド](https://docs.claude-mem.ai/installation)** - クイックスタートと高度なインストール
|
||||
- **[使用ガイド](https://docs.claude-mem.ai/usage/getting-started)** - Claude-Memの自動動作方法
|
||||
- **[検索ツール](https://docs.claude-mem.ai/usage/search-tools)** - 自然言語でプロジェクト履歴をクエリ
|
||||
- **[ベータ機能](https://docs.claude-mem.ai/beta-features)** - Endless Modeなどの実験的機能を試す
|
||||
|
||||
### ベストプラクティス
|
||||
|
||||
- **[コンテキストエンジニアリング](https://docs.claude-mem.ai/context-engineering)** - AIエージェントコンテキスト最適化の原則
|
||||
- **[段階的開示](https://docs.claude-mem.ai/progressive-disclosure)** - Claude-Memのコンテキストプライミング戦略の哲学
|
||||
|
||||
### アーキテクチャ
|
||||
|
||||
- **[概要](https://docs.claude-mem.ai/architecture/overview)** - システムコンポーネントとデータフロー
|
||||
- **[アーキテクチャの進化](https://docs.claude-mem.ai/architecture-evolution)** - v3からv5への道のり
|
||||
- **[フックアーキテクチャ](https://docs.claude-mem.ai/hooks-architecture)** - Claude-Memがライフサイクルフックを使用する方法
|
||||
- **[フックリファレンス](https://docs.claude-mem.ai/architecture/hooks)** - 7つのフックスクリプトの説明
|
||||
- **[Workerサービス](https://docs.claude-mem.ai/architecture/worker-service)** - HTTP APIとPM2管理
|
||||
- **[データベース](https://docs.claude-mem.ai/architecture/database)** - SQLiteスキーマとFTS5検索
|
||||
- **[検索アーキテクチャ](https://docs.claude-mem.ai/architecture/search-architecture)** - Chromaベクターデータベースとのハイブリッド検索
|
||||
|
||||
### 設定と開発
|
||||
|
||||
- **[設定](https://docs.claude-mem.ai/configuration)** - 環境変数と設定
|
||||
- **[開発](https://docs.claude-mem.ai/development)** - ビルド、テスト、コントリビュート
|
||||
- **[トラブルシューティング](https://docs.claude-mem.ai/troubleshooting)** - よくある問題と解決策
|
||||
|
||||
---
|
||||
|
||||
## 仕組み
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ セッション開始 → 最近の観察結果をコンテキストとして注入 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ユーザープロンプト → セッションを作成、ユーザープロンプトを保存 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ ツール実行 → 観察結果をキャプチャ(Read、Writeなど) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Worker処理 → Claude Agent SDKを使用して学習内容を抽出 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ セッション終了 → サマリーを生成、次のセッションに備える │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**コアコンポーネント:**
|
||||
|
||||
1. **5つのライフサイクルフック** - SessionStart、UserPromptSubmit、PostToolUse、Stop、SessionEnd(6つのフックスクリプト)
|
||||
2. **スマートインストール** - キャッシュされた依存関係チェッカー(プリフックスクリプト、ライフサイクルフックではありません)
|
||||
3. **Workerサービス** - Web Viewer UIと10の検索エンドポイントを備えたポート37777のHTTP API、PM2で管理
|
||||
4. **SQLiteデータベース** - セッション、観察結果、サマリーをFTS5全文検索で保存
|
||||
5. **mem-searchスキル** - 段階的開示を伴う自然言語クエリ(MCPと比較して約2,250トークン節約)
|
||||
6. **Chromaベクターデータベース** - インテリジェントなコンテキスト取得のためのハイブリッドセマンティック+キーワード検索
|
||||
|
||||
詳細は[アーキテクチャ概要](https://docs.claude-mem.ai/architecture/overview)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## mem-searchスキル
|
||||
|
||||
Claude-Memは、過去の作業について質問すると自動的に呼び出されるmem-searchスキルを通じてインテリジェントな検索を提供します:
|
||||
|
||||
**仕組み:**
|
||||
- 自然に質問するだけ: *「前回のセッションで何をしましたか?」*または*「このバグを以前修正しましたか?」*
|
||||
- Claudeは関連するコンテキストを見つけるためにmem-searchスキルを自動的に呼び出します
|
||||
- MCPアプローチと比較してセッション開始あたり約2,250トークン節約
|
||||
|
||||
**利用可能な検索操作:**
|
||||
|
||||
1. **観察結果を検索** - 観察結果全体にわたる全文検索
|
||||
2. **セッションを検索** - セッションサマリー全体にわたる全文検索
|
||||
3. **プロンプトを検索** - 生のユーザーリクエストを検索
|
||||
4. **コンセプト別** - コンセプトタグで検索(discovery、problem-solution、patternなど)
|
||||
5. **ファイル別** - 特定のファイルを参照する観察結果を検索
|
||||
6. **タイプ別** - タイプで検索(decision、bugfix、feature、refactor、discovery、change)
|
||||
7. **最近のコンテキスト** - プロジェクトの最近のセッションコンテキストを取得
|
||||
8. **タイムライン** - 特定の時点の周辺のコンテキストの統一タイムラインを取得
|
||||
9. **クエリによるタイムライン** - 観察結果を検索し、最適一致の周辺のタイムラインコンテキストを取得
|
||||
10. **APIヘルプ** - 検索APIドキュメントを取得
|
||||
|
||||
**自然言語クエリの例:**
|
||||
|
||||
```
|
||||
「前回のセッションでどんなバグを修正しましたか?」
|
||||
「認証をどのように実装しましたか?」
|
||||
「worker-service.tsにどんな変更が加えられましたか?」
|
||||
「このプロジェクトの最近の作業を見せてください」
|
||||
「ビューアUIを追加したときに何が起こっていましたか?」
|
||||
```
|
||||
|
||||
詳細な例は[検索ツールガイド](https://docs.claude-mem.ai/usage/search-tools)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## ベータ機能とEndless Mode
|
||||
|
||||
Claude-Memは実験的機能を備えた**ベータチャンネル**を提供しています。Web Viewer UIから直接安定版とベータ版を切り替えることができます。
|
||||
|
||||
### ベータを試す方法
|
||||
|
||||
1. http://localhost:37777を開く
|
||||
2. 設定(歯車アイコン)をクリック
|
||||
3. **Version Channel**で「Try Beta (Endless Mode)」をクリック
|
||||
4. Workerの再起動を待つ
|
||||
|
||||
バージョンを切り替えてもメモリデータは保持されます。
|
||||
|
||||
### Endless Mode(ベータ)
|
||||
|
||||
主要なベータ機能は**Endless Mode**です - セッション長を劇的に延長する生体模倣メモリアーキテクチャ:
|
||||
|
||||
**問題点**: 標準のClaude Codeセッションは約50回のツール使用後にコンテキスト制限に達します。各ツールは1〜10k+トークンを追加し、Claudeは各応答で以前のすべての出力を再合成します(O(N²)の複雑さ)。
|
||||
|
||||
**解決策**: Endless Modeはツール出力を約500トークンの観察結果に圧縮し、トランスクリプトをリアルタイムで変換します:
|
||||
|
||||
```
|
||||
作業メモリ(コンテキスト): 圧縮された観察結果(各約500トークン)
|
||||
アーカイブメモリ(ディスク): 呼び出しのために保存された完全なツール出力
|
||||
```
|
||||
|
||||
**期待される結果**:
|
||||
- コンテキストウィンドウで約95%のトークン削減
|
||||
- コンテキスト枯渇前に約20倍のツール使用
|
||||
- 二次O(N²)ではなく線形O(N)スケーリング
|
||||
- 完全な想起のために保存された完全なトランスクリプト
|
||||
|
||||
**注意点**: レイテンシーが追加されます(観察生成あたり60〜90秒)、まだ実験段階です。
|
||||
|
||||
詳細は[ベータ機能ドキュメント](https://docs.claude-mem.ai/beta-features)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## 新機能
|
||||
|
||||
**v6.4.9 - コンテキスト設定:**
|
||||
- コンテキスト注入の詳細な制御のための11の新しい設定
|
||||
- トークンエコノミクス表示、タイプ/コンセプト別の観察結果フィルタリングを設定
|
||||
- 観察結果の数と表示するフィールドを制御
|
||||
|
||||
**v6.4.0 - デュアルタグプライバシーシステム:**
|
||||
- ユーザー制御のプライバシーのための`<private>`タグ - 機密コンテンツをラップしてストレージから除外
|
||||
- システムレベルの`<claude-mem-context>`タグが再帰的な観察結果の保存を防止
|
||||
- エッジ処理により、プライベートコンテンツがデータベースに到達しないことを保証
|
||||
|
||||
**v6.3.0 - バージョンチャンネル:**
|
||||
- Web Viewer UIから安定版とベータ版を切り替え
|
||||
- 手動のgit操作なしでEndless Modeなどの実験的機能を試す
|
||||
|
||||
**以前のハイライト:**
|
||||
- **v6.0.0**: セッション管理とトランスクリプト処理の大幅な改善
|
||||
- **v5.5.0**: 100%の有効性を持つmem-searchスキルの強化
|
||||
- **v5.4.0**: スキルベース検索アーキテクチャ(セッションあたり約2,250トークン節約)
|
||||
- **v5.1.0**: リアルタイム更新を備えたWebベースのビューアUI
|
||||
- **v5.0.0**: Chromaベクターデータベースとのハイブリッド検索
|
||||
|
||||
完全なバージョン履歴は[CHANGELOG.md](CHANGELOG.md)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## システム要件
|
||||
|
||||
- **Node.js**: 18.0.0以上
|
||||
- **Claude Code**: プラグインサポート付きの最新バージョン
|
||||
- **PM2**: プロセスマネージャー(バンドル済み - グローバルインストール不要)
|
||||
- **SQLite 3**: 永続ストレージ用(バンドル済み)
|
||||
|
||||
---
|
||||
|
||||
## 主な利点
|
||||
|
||||
### 段階的開示コンテキスト
|
||||
|
||||
- **階層的メモリ取得**は人間のメモリパターンを反映
|
||||
- **レイヤー1(インデックス)**: セッション開始時にどの観察結果が存在するかをトークンコストとともに確認
|
||||
- **レイヤー2(詳細)**: MCP検索を介してオンデマンドで完全なナラティブを取得
|
||||
- **レイヤー3(完全な想起)**: ソースコードと元のトランスクリプトにアクセス
|
||||
- **スマートな意思決定**: トークン数により、Claudeが詳細を取得するかコードを読むかを選択できる
|
||||
- **タイプインジケーター**: 視覚的な手がかり(🔴 重要、🟤 決定、🔵 情報)が観察結果の重要性を強調
|
||||
|
||||
### 自動メモリ
|
||||
|
||||
- Claudeが起動すると自動的にコンテキストが注入されます
|
||||
- 手動コマンドや設定は不要
|
||||
- バックグラウンドで透過的に動作
|
||||
|
||||
### 完全な履歴検索
|
||||
|
||||
- すべてのセッションと観察結果を検索
|
||||
- 高速クエリのためのFTS5全文検索
|
||||
- 引用が特定の観察結果にリンクバック
|
||||
|
||||
### 構造化された観察結果
|
||||
|
||||
- AI駆動の学習内容抽出
|
||||
- タイプ別に分類(decision、bugfix、featureなど)
|
||||
- コンセプトとファイル参照でタグ付け
|
||||
|
||||
### マルチプロンプトセッション
|
||||
|
||||
- セッションは複数のユーザープロンプトにまたがる
|
||||
- `/clear`コマンド間でコンテキストが保持される
|
||||
- 会話スレッド全体を追跡
|
||||
|
||||
---
|
||||
|
||||
## 設定
|
||||
|
||||
設定は`~/.claude-mem/settings.json`で管理されます。ファイルは初回実行時にデフォルト値で自動作成されます。
|
||||
|
||||
**利用可能な設定:**
|
||||
|
||||
| 設定 | デフォルト | 説明 |
|
||||
|---------|---------|-------------|
|
||||
| `CLAUDE_MEM_MODEL` | `claude-haiku-4-5` | 観察結果用のAIモデル |
|
||||
| `CLAUDE_MEM_WORKER_PORT` | `37777` | Workerサービスポート |
|
||||
| `CLAUDE_MEM_DATA_DIR` | `~/.claude-mem` | データディレクトリの場所 |
|
||||
| `CLAUDE_MEM_LOG_LEVEL` | `INFO` | ログの詳細度(DEBUG、INFO、WARN、ERROR、SILENT) |
|
||||
| `CLAUDE_MEM_PYTHON_VERSION` | `3.13` | chroma-mcp用のPythonバージョン |
|
||||
| `CLAUDE_CODE_PATH` | _(自動検出)_ | Claude実行ファイルへのパス |
|
||||
| `CLAUDE_MEM_CONTEXT_OBSERVATIONS` | `50` | SessionStartで注入する観察結果の数 |
|
||||
|
||||
**設定管理:**
|
||||
|
||||
```bash
|
||||
# CLIヘルパーで設定を編集
|
||||
./claude-mem-settings.sh
|
||||
|
||||
# または直接編集
|
||||
nano ~/.claude-mem/settings.json
|
||||
|
||||
# 現在の設定を表示
|
||||
curl http://localhost:37777/api/settings
|
||||
```
|
||||
|
||||
**設定ファイル形式:**
|
||||
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_MODEL": "claude-haiku-4-5",
|
||||
"CLAUDE_MEM_WORKER_PORT": "37777",
|
||||
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "50"
|
||||
}
|
||||
```
|
||||
|
||||
詳細は[設定ガイド](https://docs.claude-mem.ai/configuration)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## 開発
|
||||
|
||||
```bash
|
||||
# クローンとビルド
|
||||
git clone https://github.com/thedotmack/claude-mem.git
|
||||
cd claude-mem
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# テストを実行
|
||||
npm test
|
||||
|
||||
# Workerを起動
|
||||
npm run worker:start
|
||||
|
||||
# ログを表示
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
詳細な手順は[開発ガイド](https://docs.claude-mem.ai/development)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## トラブルシューティング
|
||||
|
||||
**クイック診断:**
|
||||
|
||||
問題が発生した場合は、Claudeに問題を説明してください。トラブルシュートスキルが自動的に起動して診断と修正を提供します。
|
||||
|
||||
**よくある問題:**
|
||||
|
||||
- Workerが起動しない → `npm run worker:restart`
|
||||
- コンテキストが表示されない → `npm run test:context`
|
||||
- データベースの問題 → `sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"`
|
||||
- 検索が機能しない → FTS5テーブルが存在するか確認
|
||||
|
||||
完全な解決策については[トラブルシューティングガイド](https://docs.claude-mem.ai/troubleshooting)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## コントリビュート
|
||||
|
||||
コントリビュートを歓迎します! 以下の手順に従ってください:
|
||||
|
||||
1. リポジトリをフォーク
|
||||
2. 機能ブランチを作成
|
||||
3. テスト付きで変更を行う
|
||||
4. ドキュメントを更新
|
||||
5. プルリクエストを提出
|
||||
|
||||
コントリビュートワークフローについては[開発ガイド](https://docs.claude-mem.ai/development)を参照してください。
|
||||
|
||||
---
|
||||
|
||||
## ライセンス
|
||||
|
||||
このプロジェクトは**GNU Affero General Public License v3.0**(AGPL-3.0)の下でライセンスされています。
|
||||
|
||||
Copyright (C) 2025 Alex Newman (@thedotmack). All rights reserved.
|
||||
|
||||
詳細は[LICENSE](LICENSE)ファイルを参照してください。
|
||||
|
||||
**これが意味すること:**
|
||||
|
||||
- このソフトウェアを自由に使用、変更、配布できます
|
||||
- ネットワークサーバーで変更してデプロイする場合は、ソースコードを公開する必要があります
|
||||
- 派生作品もAGPL-3.0の下でライセンスされる必要があります
|
||||
- このソフトウェアには保証がありません
|
||||
|
||||
---
|
||||
|
||||
## サポート
|
||||
|
||||
- **ドキュメント**: [docs/](docs/)
|
||||
- **Issue**: [GitHub Issues](https://github.com/thedotmack/claude-mem/issues)
|
||||
- **リポジトリ**: [github.com/thedotmack/claude-mem](https://github.com/thedotmack/claude-mem)
|
||||
- **作者**: Alex Newman ([@thedotmack](https://github.com/thedotmack))
|
||||
|
||||
---
|
||||
|
||||
**Claude Agent SDKで構築** | **Claude Codeで駆動** | **TypeScriptで作成**
|
||||
|
||||
---
|
||||
```
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
---
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-dark-mode.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp">
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp" alt="Claude-Mem" width="400">
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
<h4 align="center"><a href="https://claude.com/claude-code" target="_blank">Claude Code</a>를 위해 구축된 지속적 메모리 압축 시스템.</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-AGPL%203.0-blue.svg" alt="License">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/version-6.5.0-green.svg" alt="Version">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg" alt="Node">
|
||||
</a>
|
||||
<a href="https://github.com/thedotmack/awesome-claude-code">
|
||||
<img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Claude Code">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/cm-preview.gif" alt="Claude-Mem Preview" width="800">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#빠른-시작">빠른 시작</a> •
|
||||
<a href="#작동-방식">작동 방식</a> •
|
||||
<a href="#mcp-검색-도구">검색 도구</a> •
|
||||
<a href="#문서">문서</a> •
|
||||
<a href="#설정">설정</a> •
|
||||
<a href="#문제-해결">문제 해결</a> •
|
||||
<a href="#라이선스">라이선스</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Claude-Mem은 도구 사용 관찰 내용을 자동으로 캡처하고 의미론적 요약을 생성하여 향후 세션에서 사용할 수 있도록 함으로써 세션 간 컨텍스트를 원활하게 보존합니다. 이를 통해 Claude는 세션이 종료되거나 재연결된 후에도 프로젝트에 대한 지식의 연속성을 유지할 수 있습니다.
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 빠른 시작
|
||||
|
||||
터미널에서 새로운 Claude Code 세션을 시작하고 다음 명령을 입력하세요:
|
||||
|
||||
```
|
||||
> /plugin marketplace add thedotmack/claude-mem
|
||||
|
||||
> /plugin install claude-mem
|
||||
```
|
||||
|
||||
Claude Code를 재시작하세요. 이전 세션의 컨텍스트가 자동으로 새 세션에 나타납니다.
|
||||
|
||||
**주요 기능:**
|
||||
|
||||
- 🧠 **지속적 메모리** - 세션 간 컨텍스트 유지
|
||||
- 📊 **점진적 공개** - 토큰 비용 가시성을 갖춘 계층화된 메모리 검색
|
||||
- 🔍 **스킬 기반 검색** - mem-search 스킬로 프로젝트 기록 쿼리 (~2,250 토큰 절약)
|
||||
- 🖥️ **웹 뷰어 UI** - http://localhost:37777에서 실시간 메모리 스트림
|
||||
- 💻 **Claude Desktop 스킬** - Claude Desktop 대화에서 메모리 검색
|
||||
- 🔒 **프라이버시 제어** - `<private>` 태그를 사용하여 민감한 콘텐츠를 저장소에서 제외
|
||||
- ⚙️ **컨텍스트 설정** - 주입되는 컨텍스트에 대한 세밀한 제어
|
||||
- 🤖 **자동 작동** - 수동 개입 불필요
|
||||
- 🔗 **인용** - `claude-mem://` URI로 과거 결정 참조
|
||||
- 🧪 **베타 채널** - 버전 전환을 통해 Endless Mode와 같은 실험적 기능 시도
|
||||
|
||||
---
|
||||
|
||||
## 문서
|
||||
|
||||
📚 **[전체 문서 보기](docs/)** - GitHub에서 마크다운 문서 탐색
|
||||
|
||||
💻 **로컬 미리보기**: Mintlify 문서를 로컬에서 실행:
|
||||
|
||||
```bash
|
||||
cd docs
|
||||
npx mintlify dev
|
||||
```
|
||||
|
||||
### 시작하기
|
||||
|
||||
- **[설치 가이드](https://docs.claude-mem.ai/installation)** - 빠른 시작 및 고급 설치
|
||||
- **[사용 가이드](https://docs.claude-mem.ai/usage/getting-started)** - Claude-Mem이 자동으로 작동하는 방법
|
||||
- **[검색 도구](https://docs.claude-mem.ai/usage/search-tools)** - 자연어로 프로젝트 기록 쿼리
|
||||
- **[베타 기능](https://docs.claude-mem.ai/beta-features)** - Endless Mode와 같은 실험적 기능 시도
|
||||
|
||||
### 모범 사례
|
||||
|
||||
- **[컨텍스트 엔지니어링](https://docs.claude-mem.ai/context-engineering)** - AI 에이전트 컨텍스트 최적화 원칙
|
||||
- **[점진적 공개](https://docs.claude-mem.ai/progressive-disclosure)** - Claude-Mem의 컨텍스트 프라이밍 전략 철학
|
||||
|
||||
### 아키텍처
|
||||
|
||||
- **[개요](https://docs.claude-mem.ai/architecture/overview)** - 시스템 구성 요소 및 데이터 흐름
|
||||
- **[아키텍처 진화](https://docs.claude-mem.ai/architecture-evolution)** - v3에서 v5로의 여정
|
||||
- **[훅 아키텍처](https://docs.claude-mem.ai/hooks-architecture)** - Claude-Mem이 라이프사이클 훅을 사용하는 방법
|
||||
- **[훅 참조](https://docs.claude-mem.ai/architecture/hooks)** - 7개 훅 스크립트 설명
|
||||
- **[워커 서비스](https://docs.claude-mem.ai/architecture/worker-service)** - HTTP API 및 PM2 관리
|
||||
- **[데이터베이스](https://docs.claude-mem.ai/architecture/database)** - SQLite 스키마 및 FTS5 검색
|
||||
- **[검색 아키텍처](https://docs.claude-mem.ai/architecture/search-architecture)** - Chroma 벡터 데이터베이스를 사용한 하이브리드 검색
|
||||
|
||||
### 설정 및 개발
|
||||
|
||||
- **[설정](https://docs.claude-mem.ai/configuration)** - 환경 변수 및 설정
|
||||
- **[개발](https://docs.claude-mem.ai/development)** - 빌드, 테스트, 기여
|
||||
- **[문제 해결](https://docs.claude-mem.ai/troubleshooting)** - 일반적인 문제 및 솔루션
|
||||
|
||||
---
|
||||
|
||||
## 작동 방식
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 세션 시작 → 최근 관찰 내용을 컨텍스트로 주입 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 사용자 프롬프트 → 세션 생성, 사용자 프롬프트 저장 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 도구 실행 → 관찰 내용 캡처 (Read, Write 등) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 워커 프로세스 → Claude Agent SDK를 통한 학습 내용 추출 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 세션 종료 → 요약 생성, 다음 세션 준비 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**핵심 구성 요소:**
|
||||
|
||||
1. **5개 라이프사이클 훅** - SessionStart, UserPromptSubmit, PostToolUse, Stop, SessionEnd (6개 훅 스크립트)
|
||||
2. **스마트 설치** - 캐시된 종속성 검사기 (사전 훅 스크립트, 라이프사이클 훅 아님)
|
||||
3. **워커 서비스** - 웹 뷰어 UI와 10개 검색 엔드포인트를 갖춘 포트 37777의 HTTP API, PM2로 관리
|
||||
4. **SQLite 데이터베이스** - FTS5 전문 검색을 갖춘 세션, 관찰 내용, 요약 저장
|
||||
5. **mem-search 스킬** - 점진적 공개를 통한 자연어 쿼리 (~2,250 토큰 절약 vs MCP)
|
||||
6. **Chroma 벡터 데이터베이스** - 지능형 컨텍스트 검색을 위한 하이브리드 의미론적 + 키워드 검색
|
||||
|
||||
자세한 내용은 [아키텍처 개요](https://docs.claude-mem.ai/architecture/overview)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## mem-search 스킬
|
||||
|
||||
Claude-Mem은 과거 작업에 대해 질문할 때 자동으로 호출되는 mem-search 스킬을 통해 지능형 검색을 제공합니다:
|
||||
|
||||
**작동 방식:**
|
||||
- 자연스럽게 질문하세요: *"지난 세션에서 무엇을 했나요?"* 또는 *"이 버그를 이전에 수정했나요?"*
|
||||
- Claude가 자동으로 mem-search 스킬을 호출하여 관련 컨텍스트를 찾습니다
|
||||
- MCP 방식 대비 세션 시작당 ~2,250 토큰 절약
|
||||
|
||||
**사용 가능한 검색 작업:**
|
||||
|
||||
1. **관찰 내용 검색** - 관찰 내용 전체에 대한 전문 검색
|
||||
2. **세션 검색** - 세션 요약 전체에 대한 전문 검색
|
||||
3. **프롬프트 검색** - 원시 사용자 요청 검색
|
||||
4. **개념별** - 개념 태그로 찾기 (discovery, problem-solution, pattern 등)
|
||||
5. **파일별** - 특정 파일을 참조하는 관찰 내용 찾기
|
||||
6. **유형별** - 유형별 찾기 (decision, bugfix, feature, refactor, discovery, change)
|
||||
7. **최근 컨텍스트** - 프로젝트의 최근 세션 컨텍스트 가져오기
|
||||
8. **타임라인** - 특정 시점 주변의 통합 컨텍스트 타임라인 가져오기
|
||||
9. **쿼리별 타임라인** - 관찰 내용을 검색하고 최적 일치 항목 주변의 타임라인 컨텍스트 가져오기
|
||||
10. **API 도움말** - 검색 API 문서 가져오기
|
||||
|
||||
**자연어 쿼리 예시:**
|
||||
|
||||
```
|
||||
"지난 세션에서 어떤 버그를 수정했나요?"
|
||||
"인증을 어떻게 구현했나요?"
|
||||
"worker-service.ts에 어떤 변경 사항이 적용되었나요?"
|
||||
"이 프로젝트의 최근 작업을 보여주세요"
|
||||
"뷰어 UI를 추가할 때 무슨 일이 있었나요?"
|
||||
```
|
||||
|
||||
자세한 예시는 [검색 도구 가이드](https://docs.claude-mem.ai/usage/search-tools)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## 베타 기능 및 Endless Mode
|
||||
|
||||
Claude-Mem은 실험적 기능이 포함된 **베타 채널**을 제공합니다. 웹 뷰어 UI에서 직접 안정 버전과 베타 버전을 전환할 수 있습니다.
|
||||
|
||||
### 베타 시도 방법
|
||||
|
||||
1. http://localhost:37777 열기
|
||||
2. 설정 클릭 (톱니바퀴 아이콘)
|
||||
3. **Version Channel**에서 "Try Beta (Endless Mode)" 클릭
|
||||
4. 워커가 재시작될 때까지 대기
|
||||
|
||||
버전을 전환해도 메모리 데이터는 보존됩니다.
|
||||
|
||||
### Endless Mode (베타)
|
||||
|
||||
대표적인 베타 기능은 **Endless Mode**입니다 - 세션 길이를 극적으로 연장하는 생체모방 메모리 아키텍처:
|
||||
|
||||
**문제점**: 표준 Claude Code 세션은 약 50번의 도구 사용 후 컨텍스트 한계에 도달합니다. 각 도구는 1-10k+ 토큰을 추가하며, Claude는 모든 응답마다 이전의 모든 출력을 재합성합니다 (O(N²) 복잡도).
|
||||
|
||||
**솔루션**: Endless Mode는 도구 출력을 약 500토큰 관찰 내용으로 압축하고 실시간으로 트랜스크립트를 변환합니다:
|
||||
|
||||
```
|
||||
작업 메모리 (컨텍스트): 압축된 관찰 내용 (각 ~500 토큰)
|
||||
아카이브 메모리 (디스크): 회상을 위해 보존된 전체 도구 출력
|
||||
```
|
||||
|
||||
**예상 결과**:
|
||||
- 컨텍스트 창에서 ~95% 토큰 감소
|
||||
- 컨텍스트 소진 전까지 약 20배 더 많은 도구 사용
|
||||
- 이차 O(N²) 대신 선형 O(N) 확장
|
||||
- 완벽한 회상을 위해 전체 트랜스크립트 보존
|
||||
|
||||
**주의사항**: 지연 시간 추가 (관찰 생성당 60-90초), 여전히 실험 단계.
|
||||
|
||||
자세한 내용은 [베타 기능 문서](https://docs.claude-mem.ai/beta-features)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## 새로운 기능
|
||||
|
||||
**v6.4.9 - 컨텍스트 설정:**
|
||||
- 컨텍스트 주입에 대한 세밀한 제어를 위한 11개의 새로운 설정
|
||||
- 토큰 경제성 표시, 유형/개념별 관찰 내용 필터링 구성
|
||||
- 관찰 내용 수 및 표시할 필드 제어
|
||||
|
||||
**v6.4.0 - 이중 태그 프라이버시 시스템:**
|
||||
- 사용자 제어 프라이버시를 위한 `<private>` 태그 - 민감한 콘텐츠를 래핑하여 저장소에서 제외
|
||||
- 시스템 레벨 `<claude-mem-context>` 태그는 재귀적 관찰 저장 방지
|
||||
- 엣지 처리로 프라이빗 콘텐츠가 데이터베이스에 도달하지 않도록 보장
|
||||
|
||||
**v6.3.0 - 버전 채널:**
|
||||
- 웹 뷰어 UI에서 안정 버전과 베타 버전 전환
|
||||
- 수동 git 작업 없이 Endless Mode와 같은 실험적 기능 시도
|
||||
|
||||
**이전 하이라이트:**
|
||||
- **v6.0.0**: 주요 세션 관리 및 트랜스크립트 처리 개선
|
||||
- **v5.5.0**: 100% 효과율을 갖춘 mem-search 스킬 향상
|
||||
- **v5.4.0**: 스킬 기반 검색 아키텍처 (세션당 ~2,250 토큰 절약)
|
||||
- **v5.1.0**: 실시간 업데이트를 갖춘 웹 기반 뷰어 UI
|
||||
- **v5.0.0**: Chroma 벡터 데이터베이스를 사용한 하이브리드 검색
|
||||
|
||||
전체 버전 기록은 [CHANGELOG.md](CHANGELOG.md)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## 시스템 요구사항
|
||||
|
||||
- **Node.js**: 18.0.0 이상
|
||||
- **Claude Code**: 플러그인 지원이 포함된 최신 버전
|
||||
- **PM2**: 프로세스 매니저 (번들 포함 - 전역 설치 불필요)
|
||||
- **SQLite 3**: 지속적 저장을 위해 (번들 포함)
|
||||
|
||||
---
|
||||
|
||||
## 주요 이점
|
||||
|
||||
### 점진적 공개 컨텍스트
|
||||
|
||||
- **계층화된 메모리 검색**은 인간의 기억 패턴을 반영
|
||||
- **레이어 1 (인덱스)**: 세션 시작 시 토큰 비용과 함께 존재하는 관찰 내용 확인
|
||||
- **레이어 2 (세부사항)**: MCP 검색을 통해 필요에 따라 전체 내러티브 가져오기
|
||||
- **레이어 3 (완벽한 회상)**: 소스 코드 및 원본 트랜스크립트 액세스
|
||||
- **스마트 의사결정**: 토큰 수는 Claude가 세부 정보 가져오기 또는 코드 읽기 중에서 선택하는 데 도움
|
||||
- **유형 표시기**: 시각적 단서 (🔴 중요, 🟤 결정, 🔵 정보) 관찰 내용의 중요도 강조
|
||||
|
||||
### 자동 메모리
|
||||
|
||||
- Claude 시작 시 자동으로 컨텍스트 주입
|
||||
- 수동 명령이나 구성 불필요
|
||||
- 백그라운드에서 투명하게 작동
|
||||
|
||||
### 전체 기록 검색
|
||||
|
||||
- 모든 세션 및 관찰 내용에 걸쳐 검색
|
||||
- 빠른 쿼리를 위한 FTS5 전문 검색
|
||||
- 인용은 특정 관찰 내용으로 다시 연결
|
||||
|
||||
### 구조화된 관찰 내용
|
||||
|
||||
- AI 기반 학습 내용 추출
|
||||
- 유형별 분류 (decision, bugfix, feature 등)
|
||||
- 개념 및 파일 참조로 태그 지정
|
||||
|
||||
### 다중 프롬프트 세션
|
||||
|
||||
- 세션은 여러 사용자 프롬프트에 걸쳐 진행
|
||||
- `/clear` 명령 간 컨텍스트 보존
|
||||
- 전체 대화 스레드 추적
|
||||
|
||||
---
|
||||
|
||||
## 설정
|
||||
|
||||
설정은 `~/.claude-mem/settings.json`에서 관리됩니다. 파일은 첫 실행 시 기본값으로 자동 생성됩니다.
|
||||
|
||||
**사용 가능한 설정:**
|
||||
|
||||
| 설정 | 기본값 | 설명 |
|
||||
|---------|---------|-------------|
|
||||
| `CLAUDE_MEM_MODEL` | `claude-haiku-4-5` | 관찰 내용용 AI 모델 |
|
||||
| `CLAUDE_MEM_WORKER_PORT` | `37777` | 워커 서비스 포트 |
|
||||
| `CLAUDE_MEM_DATA_DIR` | `~/.claude-mem` | 데이터 디렉토리 위치 |
|
||||
| `CLAUDE_MEM_LOG_LEVEL` | `INFO` | 로그 상세 수준 (DEBUG, INFO, WARN, ERROR, SILENT) |
|
||||
| `CLAUDE_MEM_PYTHON_VERSION` | `3.13` | chroma-mcp용 Python 버전 |
|
||||
| `CLAUDE_CODE_PATH` | _(자동 감지)_ | Claude 실행 파일 경로 |
|
||||
| `CLAUDE_MEM_CONTEXT_OBSERVATIONS` | `50` | SessionStart 시 주입할 관찰 내용 수 |
|
||||
|
||||
**설정 관리:**
|
||||
|
||||
```bash
|
||||
# CLI 헬퍼를 통한 설정 편집
|
||||
./claude-mem-settings.sh
|
||||
|
||||
# 또는 직접 편집
|
||||
nano ~/.claude-mem/settings.json
|
||||
|
||||
# 현재 설정 보기
|
||||
curl http://localhost:37777/api/settings
|
||||
```
|
||||
|
||||
**설정 파일 형식:**
|
||||
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_MODEL": "claude-haiku-4-5",
|
||||
"CLAUDE_MEM_WORKER_PORT": "37777",
|
||||
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "50"
|
||||
}
|
||||
```
|
||||
|
||||
자세한 내용은 [설정 가이드](https://docs.claude-mem.ai/configuration)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## 개발
|
||||
|
||||
```bash
|
||||
# 복제 및 빌드
|
||||
git clone https://github.com/thedotmack/claude-mem.git
|
||||
cd claude-mem
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# 테스트 실행
|
||||
npm test
|
||||
|
||||
# 워커 시작
|
||||
npm run worker:start
|
||||
|
||||
# 로그 보기
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
자세한 지침은 [개발 가이드](https://docs.claude-mem.ai/development)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## 문제 해결
|
||||
|
||||
**빠른 진단:**
|
||||
|
||||
문제가 발생하면 Claude에게 문제를 설명하면 troubleshoot 스킬이 자동으로 활성화되어 진단하고 수정 방법을 제공합니다.
|
||||
|
||||
**일반적인 문제:**
|
||||
|
||||
- 워커가 시작되지 않음 → `npm run worker:restart`
|
||||
- 컨텍스트가 나타나지 않음 → `npm run test:context`
|
||||
- 데이터베이스 문제 → `sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"`
|
||||
- 검색이 작동하지 않음 → FTS5 테이블 존재 확인
|
||||
|
||||
전체 솔루션은 [문제 해결 가이드](https://docs.claude-mem.ai/troubleshooting)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## 기여
|
||||
|
||||
기여를 환영합니다! 다음을 수행해 주세요:
|
||||
|
||||
1. 저장소 포크
|
||||
2. 기능 브랜치 생성
|
||||
3. 테스트와 함께 변경 사항 작성
|
||||
4. 문서 업데이트
|
||||
5. Pull Request 제출
|
||||
|
||||
기여 워크플로는 [개발 가이드](https://docs.claude-mem.ai/development)를 참조하세요.
|
||||
|
||||
---
|
||||
|
||||
## 라이선스
|
||||
|
||||
이 프로젝트는 **GNU Affero General Public License v3.0** (AGPL-3.0)에 따라 라이선스가 부여됩니다.
|
||||
|
||||
Copyright (C) 2025 Alex Newman (@thedotmack). All rights reserved.
|
||||
|
||||
전체 세부 정보는 [LICENSE](LICENSE) 파일을 참조하세요.
|
||||
|
||||
**의미:**
|
||||
|
||||
- 이 소프트웨어를 자유롭게 사용, 수정 및 배포할 수 있습니다
|
||||
- 수정하여 네트워크 서버에 배포하는 경우 소스 코드를 제공해야 합니다
|
||||
- 파생 저작물도 AGPL-3.0에 따라 라이선스가 부여되어야 합니다
|
||||
- 이 소프트웨어에 대한 보증은 없습니다
|
||||
|
||||
---
|
||||
|
||||
## 지원
|
||||
|
||||
- **문서**: [docs/](docs/)
|
||||
- **이슈**: [GitHub Issues](https://github.com/thedotmack/claude-mem/issues)
|
||||
- **저장소**: [github.com/thedotmack/claude-mem](https://github.com/thedotmack/claude-mem)
|
||||
- **제작자**: Alex Newman ([@thedotmack](https://github.com/thedotmack))
|
||||
|
||||
---
|
||||
|
||||
**Claude Agent SDK로 제작** | **Claude Code 기반** | **TypeScript로 제작**
|
||||
|
||||
---
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-dark-mode.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp">
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp" alt="Claude-Mem" width="400">
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
<h4 align="center">为 <a href="https://claude.com/claude-code" target="_blank">Claude Code</a> 构建的持久化内存压缩系统。</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-AGPL%203.0-blue.svg" alt="License">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/version-6.5.0-green.svg" alt="Version">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg" alt="Node">
|
||||
</a>
|
||||
<a href="https://github.com/thedotmack/awesome-claude-code">
|
||||
<img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Claude Code">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/cm-preview.gif" alt="Claude-Mem Preview" width="800">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#快速开始">快速开始</a> •
|
||||
<a href="#工作原理">工作原理</a> •
|
||||
<a href="#mcp-搜索工具">搜索工具</a> •
|
||||
<a href="#文档">文档</a> •
|
||||
<a href="#配置">配置</a> •
|
||||
<a href="#故障排除">故障排除</a> •
|
||||
<a href="#许可证">许可证</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Claude-Mem 通过自动捕获工具使用观察、生成语义摘要并将其提供给未来会话,无缝地跨会话保留上下文。这使 Claude 能够在会话结束或重新连接后保持对项目知识的连续性。
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
在终端中启动新的 Claude Code 会话并输入以下命令:
|
||||
|
||||
```
|
||||
> /plugin marketplace add thedotmack/claude-mem
|
||||
|
||||
> /plugin install claude-mem
|
||||
```
|
||||
|
||||
重启 Claude Code。之前会话的上下文将自动出现在新会话中。
|
||||
|
||||
**核心功能:**
|
||||
|
||||
- 🧠 **持久化内存** - 上下文在会话间保持
|
||||
- 📊 **渐进式披露** - 分层内存检索,可见令牌成本
|
||||
- 🔍 **基于技能的搜索** - 使用 mem-search 技能查询项目历史(节省约 2,250 个令牌)
|
||||
- 🖥️ **Web 查看器界面** - 在 http://localhost:37777 实时查看内存流
|
||||
- 💻 **Claude Desktop 技能** - 从 Claude Desktop 对话中搜索内存
|
||||
- 🔒 **隐私控制** - 使用 `<private>` 标签排除敏感内容存储
|
||||
- ⚙️ **上下文配置** - 精细控制注入的上下文内容
|
||||
- 🤖 **自动运行** - 无需手动干预
|
||||
- 🔗 **引用** - 使用 `claude-mem://` URI 引用过去的决策
|
||||
- 🧪 **Beta 频道** - 通过版本切换尝试实验性功能,如无尽模式
|
||||
|
||||
---
|
||||
|
||||
## 文档
|
||||
|
||||
📚 **[查看完整文档](docs/)** - 在 GitHub 上浏览 markdown 文档
|
||||
|
||||
💻 **本地预览**: 在本地运行 Mintlify 文档:
|
||||
|
||||
```bash
|
||||
cd docs
|
||||
npx mintlify dev
|
||||
```
|
||||
|
||||
### 入门指南
|
||||
|
||||
- **[安装指南](https://docs.claude-mem.ai/installation)** - 快速开始与高级安装
|
||||
- **[使用指南](https://docs.claude-mem.ai/usage/getting-started)** - Claude-Mem 如何自动工作
|
||||
- **[搜索工具](https://docs.claude-mem.ai/usage/search-tools)** - 使用自然语言查询项目历史
|
||||
- **[Beta 功能](https://docs.claude-mem.ai/beta-features)** - 尝试实验性功能,如无尽模式
|
||||
|
||||
### 最佳实践
|
||||
|
||||
- **[上下文工程](https://docs.claude-mem.ai/context-engineering)** - AI 代理上下文优化原则
|
||||
- **[渐进式披露](https://docs.claude-mem.ai/progressive-disclosure)** - Claude-Mem 上下文预备策略背后的哲学
|
||||
|
||||
### 架构
|
||||
|
||||
- **[概述](https://docs.claude-mem.ai/architecture/overview)** - 系统组件与数据流
|
||||
- **[架构演进](https://docs.claude-mem.ai/architecture-evolution)** - 从 v3 到 v5 的发展历程
|
||||
- **[钩子架构](https://docs.claude-mem.ai/hooks-architecture)** - Claude-Mem 如何使用生命周期钩子
|
||||
- **[钩子参考](https://docs.claude-mem.ai/architecture/hooks)** - 7 个钩子脚本详解
|
||||
- **[Worker 服务](https://docs.claude-mem.ai/architecture/worker-service)** - HTTP API 与 PM2 管理
|
||||
- **[数据库](https://docs.claude-mem.ai/architecture/database)** - SQLite 架构与 FTS5 搜索
|
||||
- **[搜索架构](https://docs.claude-mem.ai/architecture/search-architecture)** - 使用 Chroma 向量数据库的混合搜索
|
||||
|
||||
### 配置与开发
|
||||
|
||||
- **[配置](https://docs.claude-mem.ai/configuration)** - 环境变量与设置
|
||||
- **[开发](https://docs.claude-mem.ai/development)** - 构建、测试、贡献
|
||||
- **[故障排除](https://docs.claude-mem.ai/troubleshooting)** - 常见问题与解决方案
|
||||
|
||||
---
|
||||
|
||||
## 工作原理
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 会话开始 → 注入最近的观察作为上下文 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 用户提示 → 创建会话,保存用户提示 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 工具执行 → 捕获观察(Read、Write 等) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Worker 处理 → 通过 Claude Agent SDK 提取学习内容 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 会话结束 → 生成摘要,为下一个会话做好准备 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**核心组件:**
|
||||
|
||||
1. **5 个生命周期钩子** - SessionStart、UserPromptSubmit、PostToolUse、Stop、SessionEnd(6 个钩子脚本)
|
||||
2. **智能安装** - 缓存依赖检查器(预钩子脚本,非生命周期钩子)
|
||||
3. **Worker 服务** - 端口 37777 上的 HTTP API,带有 Web 查看器界面和 10 个搜索端点,由 PM2 管理
|
||||
4. **SQLite 数据库** - 存储会话、观察、摘要,支持 FTS5 全文搜索
|
||||
5. **mem-search 技能** - 自然语言查询,支持渐进式披露(相比 MCP 节省约 2,250 个令牌)
|
||||
6. **Chroma 向量数据库** - 混合语义 + 关键词搜索,实现智能上下文检索
|
||||
|
||||
详见[架构概述](https://docs.claude-mem.ai/architecture/overview)。
|
||||
|
||||
---
|
||||
|
||||
## mem-search 技能
|
||||
|
||||
Claude-Mem 通过 mem-search 技能提供智能搜索,当您询问过去的工作时会自动调用:
|
||||
|
||||
**工作原理:**
|
||||
- 只需自然提问:*"上个会话我们做了什么?"* 或 *"我们之前修复过这个 bug 吗?"*
|
||||
- Claude 自动调用 mem-search 技能查找相关上下文
|
||||
- 相比 MCP 方法,每次会话开始节省约 2,250 个令牌
|
||||
|
||||
**可用搜索操作:**
|
||||
|
||||
1. **搜索观察** - 跨观察的全文搜索
|
||||
2. **搜索会话** - 跨会话摘要的全文搜索
|
||||
3. **搜索提示** - 搜索原始用户请求
|
||||
4. **按概念搜索** - 按概念标签查找(discovery、problem-solution、pattern 等)
|
||||
5. **按文件搜索** - 查找引用特定文件的观察
|
||||
6. **按类型搜索** - 按类型查找(decision、bugfix、feature、refactor、discovery、change)
|
||||
7. **最近上下文** - 获取项目的最近会话上下文
|
||||
8. **时间线** - 获取特定时间点周围的统一上下文时间线
|
||||
9. **按查询的时间线** - 搜索观察并获取最佳匹配周围的时间线上下文
|
||||
10. **API 帮助** - 获取搜索 API 文档
|
||||
|
||||
**自然语言查询示例:**
|
||||
|
||||
```
|
||||
"上个会话我们修复了哪些 bug?"
|
||||
"我们是如何实现身份验证的?"
|
||||
"对 worker-service.ts 做了哪些更改?"
|
||||
"显示这个项目的最近工作"
|
||||
"添加查看器界面时发生了什么?"
|
||||
```
|
||||
|
||||
详见[搜索工具指南](https://docs.claude-mem.ai/usage/search-tools)获取详细示例。
|
||||
|
||||
---
|
||||
|
||||
## Beta 功能与无尽模式
|
||||
|
||||
Claude-Mem 提供带有实验性功能的 **beta 频道**。直接从 Web 查看器界面在稳定版和 beta 版之间切换。
|
||||
|
||||
### 如何尝试 Beta
|
||||
|
||||
1. 打开 http://localhost:37777
|
||||
2. 点击设置(齿轮图标)
|
||||
3. 在 **版本频道** 中,点击 "Try Beta (Endless Mode)"
|
||||
4. 等待 worker 重启
|
||||
|
||||
切换版本时您的内存数据会被保留。
|
||||
|
||||
### 无尽模式(Beta)
|
||||
|
||||
旗舰 beta 功能是 **无尽模式** - 一种仿生内存架构,可显著延长会话时长:
|
||||
|
||||
**问题**: 标准 Claude Code 会话在约 50 次工具使用后达到上下文限制。每个工具添加 1-10k+ 令牌,Claude 在每次响应时都会重新合成所有先前的输出(O(N²) 复杂度)。
|
||||
|
||||
**解决方案**: 无尽模式将工具输出压缩为约 500 令牌的观察,并实时转换记录:
|
||||
|
||||
```
|
||||
工作内存(上下文): 压缩的观察(每个约 500 令牌)
|
||||
归档内存(磁盘): 保留完整工具输出供调用
|
||||
```
|
||||
|
||||
**预期结果**:
|
||||
- 上下文窗口中约 95% 的令牌减少
|
||||
- 在上下文耗尽前约 20 倍的工具使用次数
|
||||
- 线性 O(N) 扩展而非二次 O(N²)
|
||||
- 保留完整记录以实现完美回忆
|
||||
|
||||
**注意事项**: 增加延迟(每个工具 60-90 秒用于生成观察),仍处于实验阶段。
|
||||
|
||||
详见[Beta 功能文档](https://docs.claude-mem.ai/beta-features)。
|
||||
|
||||
---
|
||||
|
||||
## 新功能
|
||||
|
||||
**v6.4.9 - 上下文配置设置:**
|
||||
- 11 个新设置,用于精细控制上下文注入
|
||||
- 配置令牌经济性显示、按类型/概念过滤观察
|
||||
- 控制观察数量和要显示的字段
|
||||
|
||||
**v6.4.0 - 双标签隐私系统:**
|
||||
- `<private>` 标签用于用户控制的隐私 - 包裹敏感内容以排除存储
|
||||
- 系统级 `<claude-mem-context>` 标签防止递归观察存储
|
||||
- 边缘处理确保私密内容永不到达数据库
|
||||
|
||||
**v6.3.0 - 版本频道:**
|
||||
- 从 Web 查看器界面在稳定版和 beta 版之间切换
|
||||
- 无需手动 git 操作即可尝试实验性功能,如无尽模式
|
||||
|
||||
**先前亮点:**
|
||||
- **v6.0.0**: 重大会话管理与记录处理改进
|
||||
- **v5.5.0**: mem-search 技能增强,100% 有效率
|
||||
- **v5.4.0**: 基于技能的搜索架构(每次会话节省约 2,250 令牌)
|
||||
- **v5.1.0**: 基于 Web 的查看器界面,实时更新
|
||||
- **v5.0.0**: 使用 Chroma 向量数据库的混合搜索
|
||||
|
||||
完整版本历史见 [CHANGELOG.md](CHANGELOG.md)。
|
||||
|
||||
---
|
||||
|
||||
## 系统要求
|
||||
|
||||
- **Node.js**: 18.0.0 或更高版本
|
||||
- **Claude Code**: 支持插件的最新版本
|
||||
- **PM2**: 进程管理器(已捆绑 - 无需全局安装)
|
||||
- **SQLite 3**: 用于持久化存储(已捆绑)
|
||||
|
||||
---
|
||||
|
||||
## 核心优势
|
||||
|
||||
### 渐进式披露上下文
|
||||
|
||||
- **分层内存检索**镜像人类内存模式
|
||||
- **第 1 层(索引)**: 在会话开始时查看存在哪些观察及其令牌成本
|
||||
- **第 2 层(详情)**: 通过 MCP 搜索按需获取完整叙述
|
||||
- **第 3 层(完美回忆)**: 访问源代码和原始记录
|
||||
- **智能决策**: 令牌计数帮助 Claude 在获取详情或读取代码之间做出选择
|
||||
- **类型指示器**: 视觉提示(🔴 关键、🟤 决策、🔵 信息)突出显示观察重要性
|
||||
|
||||
### 自动内存
|
||||
|
||||
- Claude 启动时自动注入上下文
|
||||
- 无需手动命令或配置
|
||||
- 在后台透明工作
|
||||
|
||||
### 完整历史搜索
|
||||
|
||||
- 跨所有会话和观察搜索
|
||||
- FTS5 全文搜索实现快速查询
|
||||
- 引用链接回特定观察
|
||||
|
||||
### 结构化观察
|
||||
|
||||
- AI 驱动的学习内容提取
|
||||
- 按类型分类(decision、bugfix、feature 等)
|
||||
- 标记概念和文件引用
|
||||
|
||||
### 多提示会话
|
||||
|
||||
- 会话跨越多个用户提示
|
||||
- 上下文在 `/clear` 命令间保留
|
||||
- 跟踪整个对话线程
|
||||
|
||||
---
|
||||
|
||||
## 配置
|
||||
|
||||
设置在 `~/.claude-mem/settings.json` 中管理。文件在首次运行时自动创建,包含默认值。
|
||||
|
||||
**可用设置:**
|
||||
|
||||
| 设置 | 默认值 | 描述 |
|
||||
|---------|---------|-------------|
|
||||
| `CLAUDE_MEM_MODEL` | `claude-haiku-4-5` | 用于观察的 AI 模型 |
|
||||
| `CLAUDE_MEM_WORKER_PORT` | `37777` | Worker 服务端口 |
|
||||
| `CLAUDE_MEM_DATA_DIR` | `~/.claude-mem` | 数据目录位置 |
|
||||
| `CLAUDE_MEM_LOG_LEVEL` | `INFO` | 日志详细程度(DEBUG、INFO、WARN、ERROR、SILENT) |
|
||||
| `CLAUDE_MEM_PYTHON_VERSION` | `3.13` | chroma-mcp 的 Python 版本 |
|
||||
| `CLAUDE_CODE_PATH` | _(自动检测)_ | Claude 可执行文件路径 |
|
||||
| `CLAUDE_MEM_CONTEXT_OBSERVATIONS` | `50` | SessionStart 时注入的观察数量 |
|
||||
|
||||
**设置管理:**
|
||||
|
||||
```bash
|
||||
# 通过 CLI 助手编辑设置
|
||||
./claude-mem-settings.sh
|
||||
|
||||
# 或直接编辑
|
||||
nano ~/.claude-mem/settings.json
|
||||
|
||||
# 查看当前设置
|
||||
curl http://localhost:37777/api/settings
|
||||
```
|
||||
|
||||
**设置文件格式:**
|
||||
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_MODEL": "claude-haiku-4-5",
|
||||
"CLAUDE_MEM_WORKER_PORT": "37777",
|
||||
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "50"
|
||||
}
|
||||
```
|
||||
|
||||
详见[配置指南](https://docs.claude-mem.ai/configuration)。
|
||||
|
||||
---
|
||||
|
||||
## 开发
|
||||
|
||||
```bash
|
||||
# 克隆并构建
|
||||
git clone https://github.com/thedotmack/claude-mem.git
|
||||
cd claude-mem
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# 运行测试
|
||||
npm test
|
||||
|
||||
# 启动 worker
|
||||
npm run worker:start
|
||||
|
||||
# 查看日志
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
详细说明见[开发指南](https://docs.claude-mem.ai/development)。
|
||||
|
||||
---
|
||||
|
||||
## 故障排除
|
||||
|
||||
**快速诊断:**
|
||||
|
||||
如果您遇到问题,向 Claude 描述问题,troubleshoot 技能将自动激活以诊断并提供修复方案。
|
||||
|
||||
**常见问题:**
|
||||
|
||||
- Worker 无法启动 → `npm run worker:restart`
|
||||
- 没有上下文出现 → `npm run test:context`
|
||||
- 数据库问题 → `sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"`
|
||||
- 搜索不工作 → 检查 FTS5 表是否存在
|
||||
|
||||
完整解决方案见[故障排除指南](https://docs.claude-mem.ai/troubleshooting)。
|
||||
|
||||
---
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎贡献!请:
|
||||
|
||||
1. Fork 仓库
|
||||
2. 创建功能分支
|
||||
3. 进行更改并添加测试
|
||||
4. 更新文档
|
||||
5. 提交 Pull Request
|
||||
|
||||
贡献工作流程见[开发指南](https://docs.claude-mem.ai/development)。
|
||||
|
||||
---
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目采用 **GNU Affero 通用公共许可证 v3.0** (AGPL-3.0) 授权。
|
||||
|
||||
Copyright (C) 2025 Alex Newman (@thedotmack). 保留所有权利。
|
||||
|
||||
完整详情见 [LICENSE](LICENSE) 文件。
|
||||
|
||||
**这意味着什么:**
|
||||
|
||||
- 您可以自由使用、修改和分发本软件
|
||||
- 如果您修改并部署在网络服务器上,必须提供源代码
|
||||
- 衍生作品也必须采用 AGPL-3.0 许可
|
||||
- 本软件不提供任何担保
|
||||
|
||||
---
|
||||
|
||||
## 支持
|
||||
|
||||
- **文档**: [docs/](docs/)
|
||||
- **问题**: [GitHub Issues](https://github.com/thedotmack/claude-mem/issues)
|
||||
- **仓库**: [github.com/thedotmack/claude-mem](https://github.com/thedotmack/claude-mem)
|
||||
- **作者**: Alex Newman ([@thedotmack](https://github.com/thedotmack))
|
||||
|
||||
---
|
||||
|
||||
**使用 Claude Agent SDK 构建** | **由 Claude Code 驱动** | **使用 TypeScript 制作**
|
||||
|
||||
---
|
||||
Generated
+8
-2052
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -46,10 +46,11 @@
|
||||
"worker:logs": "tail -f ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log",
|
||||
"changelog:generate": "node scripts/generate-changelog.js",
|
||||
"usage:analyze": "node scripts/analyze-usage.js",
|
||||
"usage:today": "node scripts/analyze-usage.js $(date +%Y-%m-%d)"
|
||||
"usage:today": "node scripts/analyze-usage.js $(date +%Y-%m-%d)",
|
||||
"translate-readme": "npx tsx scripts/translate-readme/cli.ts -v README.md zh ko ja"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.1.62",
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.1.67",
|
||||
"@modelcontextprotocol/sdk": "^1.20.1",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"express": "^4.18.2",
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
# README Translator
|
||||
|
||||
Translate README.md files to multiple languages using the Claude Agent SDK. Perfect for build scripts and CI/CD pipelines.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install readme-translator
|
||||
# or
|
||||
npm install -g readme-translator # for CLI usage
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18+
|
||||
- **Authentication** (one of the following):
|
||||
- Claude Code installed and authenticated (Pro/Max subscription) - **no API key needed**
|
||||
- `ANTHROPIC_API_KEY` environment variable set (for API-based usage)
|
||||
- AWS Bedrock (`CLAUDE_CODE_USE_BEDROCK=1` + AWS credentials)
|
||||
- Google Vertex AI (`CLAUDE_CODE_USE_VERTEX=1` + GCP credentials)
|
||||
|
||||
If you have Claude Code installed and logged in with your Pro/Max subscription, the SDK will automatically use that authentication.
|
||||
|
||||
## CLI Usage
|
||||
|
||||
```bash
|
||||
# Basic usage
|
||||
translate-readme README.md es fr de
|
||||
|
||||
# With options
|
||||
translate-readme -v -o ./i18n --pattern docs.{lang}.md README.md es fr de ja zh
|
||||
|
||||
# List supported languages
|
||||
translate-readme --list-languages
|
||||
```
|
||||
|
||||
### CLI Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `-o, --output <dir>` | Output directory (default: same as source) |
|
||||
| `-p, --pattern <pat>` | Output filename pattern (default: `README.{lang}.md`) |
|
||||
| `--no-preserve-code` | Translate code blocks too (not recommended) |
|
||||
| `-m, --model <model>` | Claude model to use (default: `sonnet`) |
|
||||
| `--max-budget <usd>` | Maximum budget in USD |
|
||||
| `-v, --verbose` | Show detailed progress |
|
||||
| `-h, --help` | Show help message |
|
||||
| `--list-languages` | List all supported language codes |
|
||||
|
||||
## Programmatic Usage
|
||||
|
||||
```typescript
|
||||
import { translateReadme } from "readme-translator";
|
||||
|
||||
const result = await translateReadme({
|
||||
source: "./README.md",
|
||||
languages: ["es", "fr", "de", "ja", "zh"],
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
console.log(`Translated ${result.successful} files`);
|
||||
console.log(`Total cost: $${result.totalCostUsd.toFixed(4)}`);
|
||||
```
|
||||
|
||||
### API Options
|
||||
|
||||
```typescript
|
||||
interface TranslationOptions {
|
||||
/** Source README file path */
|
||||
source: string;
|
||||
|
||||
/** Target language codes */
|
||||
languages: string[];
|
||||
|
||||
/** Output directory (defaults to same directory as source) */
|
||||
outputDir?: string;
|
||||
|
||||
/** Output filename pattern (use {lang} placeholder) */
|
||||
pattern?: string; // default: "README.{lang}.md"
|
||||
|
||||
/** Preserve code blocks without translation */
|
||||
preserveCode?: boolean; // default: true
|
||||
|
||||
/** Claude model to use */
|
||||
model?: string; // default: "sonnet"
|
||||
|
||||
/** Maximum budget in USD */
|
||||
maxBudgetUsd?: number;
|
||||
|
||||
/** Verbose output */
|
||||
verbose?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Return Value
|
||||
|
||||
```typescript
|
||||
interface TranslationJobResult {
|
||||
results: TranslationResult[];
|
||||
totalCostUsd: number;
|
||||
successful: number;
|
||||
failed: number;
|
||||
}
|
||||
|
||||
interface TranslationResult {
|
||||
language: string;
|
||||
outputPath: string;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
costUsd?: number;
|
||||
}
|
||||
```
|
||||
|
||||
## Build Script Integration
|
||||
|
||||
### package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"translate": "translate-readme README.md es fr de ja zh",
|
||||
"translate:all": "translate-readme -v -o ./i18n README.md es fr de it pt ja ko zh ru ar",
|
||||
"prebuild": "npm run translate"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
Note: CI/CD environments require an API key since Claude Code won't be authenticated there.
|
||||
|
||||
```yaml
|
||||
name: Translate README
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths: [README.md]
|
||||
|
||||
jobs:
|
||||
translate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- run: npm install -g readme-translator
|
||||
|
||||
- name: Translate README
|
||||
env:
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
run: |
|
||||
translate-readme -v -o ./i18n README.md es fr de ja zh
|
||||
|
||||
- name: Commit translations
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add i18n/
|
||||
git diff --staged --quiet || git commit -m "chore: update README translations"
|
||||
git push
|
||||
```
|
||||
|
||||
### Programmatic Build Script
|
||||
|
||||
```typescript
|
||||
// scripts/translate.ts
|
||||
import { translateReadme } from "readme-translator";
|
||||
|
||||
async function main() {
|
||||
const result = await translateReadme({
|
||||
source: "./README.md",
|
||||
languages: (process.env.TRANSLATE_LANGS || "es,fr,de").split(","),
|
||||
outputDir: "./docs/i18n",
|
||||
maxBudgetUsd: 5.0,
|
||||
verbose: !process.env.CI,
|
||||
});
|
||||
|
||||
if (result.failed > 0) {
|
||||
console.error("Some translations failed");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Code | Language | Code | Language |
|
||||
|------|----------|------|----------|
|
||||
| `ar` | Arabic | `ko` | Korean |
|
||||
| `bg` | Bulgarian | `lt` | Lithuanian |
|
||||
| `cs` | Czech | `lv` | Latvian |
|
||||
| `da` | Danish | `nl` | Dutch |
|
||||
| `de` | German | `no` | Norwegian |
|
||||
| `el` | Greek | `pl` | Polish |
|
||||
| `es` | Spanish | `pt` | Portuguese |
|
||||
| `et` | Estonian | `pt-br` | Brazilian Portuguese |
|
||||
| `fi` | Finnish | `ro` | Romanian |
|
||||
| `fr` | French | `ru` | Russian |
|
||||
| `he` | Hebrew | `sk` | Slovak |
|
||||
| `hi` | Hindi | `sl` | Slovenian |
|
||||
| `hu` | Hungarian | `sv` | Swedish |
|
||||
| `id` | Indonesian | `th` | Thai |
|
||||
| `it` | Italian | `tr` | Turkish |
|
||||
| `ja` | Japanese | `uk` | Ukrainian |
|
||||
| | | `vi` | Vietnamese |
|
||||
| | | `zh` | Chinese (Simplified) |
|
||||
| | | `zh-tw` | Chinese (Traditional) |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Preserve Code Blocks**: Keep `preserveCode: true` (default) to avoid breaking code examples
|
||||
|
||||
2. **Set Budget Limits**: Use `maxBudgetUsd` to prevent runaway costs
|
||||
|
||||
3. **Run on Releases Only**: In CI/CD, trigger translations only on main branch or releases
|
||||
|
||||
4. **Review Translations**: Automated translations are good but not perfect - consider human review for critical docs
|
||||
|
||||
5. **Cache Results**: Don't re-translate unchanged content - check if README changed before running
|
||||
|
||||
## Cost Estimation
|
||||
|
||||
Typical costs per language (varies by README length):
|
||||
- Short README (~500 words): ~$0.01-0.02
|
||||
- Medium README (~2000 words): ~$0.05-0.10
|
||||
- Long README (~5000 words): ~$0.15-0.25
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env npx tsx
|
||||
|
||||
import { translateReadme, SUPPORTED_LANGUAGES } from "./index.ts";
|
||||
|
||||
interface CliArgs {
|
||||
source: string;
|
||||
languages: string[];
|
||||
outputDir?: string;
|
||||
pattern?: string;
|
||||
preserveCode: boolean;
|
||||
model?: string;
|
||||
maxBudget?: number;
|
||||
verbose: boolean;
|
||||
help: boolean;
|
||||
listLanguages: boolean;
|
||||
}
|
||||
|
||||
function printHelp(): void {
|
||||
console.log(`
|
||||
readme-translator - Translate README.md files using Claude Agent SDK
|
||||
|
||||
AUTHENTICATION:
|
||||
If Claude Code is installed and authenticated (Pro/Max subscription),
|
||||
no API key is needed. Otherwise, set ANTHROPIC_API_KEY environment variable.
|
||||
|
||||
USAGE:
|
||||
translate-readme [options] <source> <languages...>
|
||||
translate-readme --help
|
||||
translate-readme --list-languages
|
||||
|
||||
ARGUMENTS:
|
||||
source Path to the source README.md file
|
||||
languages Target language codes (e.g., es fr de ja zh)
|
||||
|
||||
OPTIONS:
|
||||
-o, --output <dir> Output directory (default: same as source)
|
||||
-p, --pattern <pat> Output filename pattern (default: README.{lang}.md)
|
||||
--no-preserve-code Translate code blocks too (not recommended)
|
||||
-m, --model <model> Claude model to use (default: sonnet)
|
||||
--max-budget <usd> Maximum budget in USD
|
||||
-v, --verbose Show detailed progress
|
||||
-h, --help Show this help message
|
||||
--list-languages List all supported language codes
|
||||
|
||||
EXAMPLES:
|
||||
# Translate to Spanish and French
|
||||
translate-readme README.md es fr
|
||||
|
||||
# Translate to multiple languages with custom output
|
||||
translate-readme -v -o ./i18n --pattern docs.{lang}.md README.md de ja ko zh
|
||||
|
||||
# Use in npm scripts
|
||||
# package.json: "translate": "translate-readme README.md es fr de"
|
||||
|
||||
SUPPORTED LANGUAGES:
|
||||
Run with --list-languages to see all supported language codes
|
||||
`);
|
||||
}
|
||||
|
||||
function printLanguages(): void {
|
||||
const LANGUAGE_NAMES: Record<string, string> = {
|
||||
ar: "Arabic",
|
||||
bg: "Bulgarian",
|
||||
cs: "Czech",
|
||||
da: "Danish",
|
||||
de: "German",
|
||||
el: "Greek",
|
||||
es: "Spanish",
|
||||
et: "Estonian",
|
||||
fi: "Finnish",
|
||||
fr: "French",
|
||||
he: "Hebrew",
|
||||
hi: "Hindi",
|
||||
hu: "Hungarian",
|
||||
id: "Indonesian",
|
||||
it: "Italian",
|
||||
ja: "Japanese",
|
||||
ko: "Korean",
|
||||
lt: "Lithuanian",
|
||||
lv: "Latvian",
|
||||
nl: "Dutch",
|
||||
no: "Norwegian",
|
||||
pl: "Polish",
|
||||
pt: "Portuguese",
|
||||
"pt-br": "Brazilian Portuguese",
|
||||
ro: "Romanian",
|
||||
ru: "Russian",
|
||||
sk: "Slovak",
|
||||
sl: "Slovenian",
|
||||
sv: "Swedish",
|
||||
th: "Thai",
|
||||
tr: "Turkish",
|
||||
uk: "Ukrainian",
|
||||
vi: "Vietnamese",
|
||||
zh: "Chinese (Simplified)",
|
||||
"zh-tw": "Chinese (Traditional)",
|
||||
};
|
||||
|
||||
console.log("\nSupported Language Codes:\n");
|
||||
const sorted = Object.entries(LANGUAGE_NAMES).sort((a, b) =>
|
||||
a[1].localeCompare(b[1])
|
||||
);
|
||||
for (const [code, name] of sorted) {
|
||||
console.log(` ${code.padEnd(8)} ${name}`);
|
||||
}
|
||||
console.log("");
|
||||
}
|
||||
|
||||
function parseArgs(argv: string[]): CliArgs {
|
||||
const args: CliArgs = {
|
||||
source: "",
|
||||
languages: [],
|
||||
preserveCode: true,
|
||||
verbose: false,
|
||||
help: false,
|
||||
listLanguages: false,
|
||||
};
|
||||
|
||||
const positional: string[] = [];
|
||||
let i = 2; // Skip node and script path
|
||||
|
||||
while (i < argv.length) {
|
||||
const arg = argv[i];
|
||||
|
||||
switch (arg) {
|
||||
case "-h":
|
||||
case "--help":
|
||||
args.help = true;
|
||||
break;
|
||||
case "--list-languages":
|
||||
args.listLanguages = true;
|
||||
break;
|
||||
case "-v":
|
||||
case "--verbose":
|
||||
args.verbose = true;
|
||||
break;
|
||||
case "--no-preserve-code":
|
||||
args.preserveCode = false;
|
||||
break;
|
||||
case "-o":
|
||||
case "--output":
|
||||
args.outputDir = argv[++i];
|
||||
break;
|
||||
case "-p":
|
||||
case "--pattern":
|
||||
args.pattern = argv[++i];
|
||||
break;
|
||||
case "-m":
|
||||
case "--model":
|
||||
args.model = argv[++i];
|
||||
break;
|
||||
case "--max-budget":
|
||||
args.maxBudget = parseFloat(argv[++i]);
|
||||
break;
|
||||
default:
|
||||
if (arg.startsWith("-")) {
|
||||
console.error(`Unknown option: ${arg}`);
|
||||
process.exit(1);
|
||||
}
|
||||
positional.push(arg);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (positional.length > 0) {
|
||||
args.source = positional[0];
|
||||
args.languages = positional.slice(1);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const args = parseArgs(process.argv);
|
||||
|
||||
if (args.help) {
|
||||
printHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (args.listLanguages) {
|
||||
printLanguages();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!args.source) {
|
||||
console.error("Error: No source file specified");
|
||||
console.error("Run with --help for usage information");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (args.languages.length === 0) {
|
||||
console.error("Error: No target languages specified");
|
||||
console.error("Run with --help for usage information");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Validate language codes
|
||||
const invalidLangs = args.languages.filter(
|
||||
(lang) => !SUPPORTED_LANGUAGES.includes(lang.toLowerCase())
|
||||
);
|
||||
if (invalidLangs.length > 0) {
|
||||
console.error(`Error: Unknown language codes: ${invalidLangs.join(", ")}`);
|
||||
console.error("Run with --list-languages to see supported codes");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await translateReadme({
|
||||
source: args.source,
|
||||
languages: args.languages,
|
||||
outputDir: args.outputDir,
|
||||
pattern: args.pattern,
|
||||
preserveCode: args.preserveCode,
|
||||
model: args.model,
|
||||
maxBudgetUsd: args.maxBudget,
|
||||
verbose: args.verbose,
|
||||
});
|
||||
|
||||
// Exit with error code if any translations failed
|
||||
if (result.failed > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Translation failed:",
|
||||
error instanceof Error ? error.message : error
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Example: Using readme-translator in build scripts
|
||||
*
|
||||
* These examples show how to integrate the translator into your build pipeline.
|
||||
*/
|
||||
|
||||
import { translateReadme, TranslationJobResult, SUPPORTED_LANGUAGES } from "./index.js";
|
||||
|
||||
// Example 1: Simple usage - translate to a few common languages
|
||||
async function translateToCommonLanguages(): Promise<void> {
|
||||
const result = await translateReadme({
|
||||
source: "./README.md",
|
||||
languages: ["es", "fr", "de", "ja", "zh"],
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
console.log(`Translated to ${result.successful} languages`);
|
||||
}
|
||||
|
||||
// Example 2: Full i18n setup with custom output directory
|
||||
async function fullI18nSetup(): Promise<void> {
|
||||
const result = await translateReadme({
|
||||
source: "./README.md",
|
||||
languages: ["es", "fr", "de", "it", "pt", "ja", "ko", "zh", "ru", "ar"],
|
||||
outputDir: "./docs/i18n",
|
||||
pattern: "README.{lang}.md",
|
||||
preserveCode: true,
|
||||
model: "sonnet",
|
||||
maxBudgetUsd: 5.0, // Cap spending at $5
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Handle results programmatically
|
||||
for (const r of result.results) {
|
||||
if (!r.success) {
|
||||
console.error(`Failed to translate to ${r.language}: ${r.error}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Example 3: Build script integration with error handling
|
||||
// Note: If Claude Code is authenticated, no API key needed locally.
|
||||
// CI/CD environments will need ANTHROPIC_API_KEY set.
|
||||
async function buildScriptIntegration(): Promise<number> {
|
||||
try {
|
||||
const result = await translateReadme({
|
||||
source: process.env.README_PATH || "./README.md",
|
||||
languages: (process.env.TRANSLATE_LANGS || "es,fr,de").split(","),
|
||||
outputDir: process.env.I18N_OUTPUT || "./i18n",
|
||||
verbose: process.env.CI !== "true", // Quiet in CI
|
||||
});
|
||||
|
||||
// Return exit code for build scripts
|
||||
return result.failed > 0 ? 1 : 0;
|
||||
} catch (error) {
|
||||
console.error("Translation failed:", error);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Example 4: Batch translation of multiple READMEs
|
||||
async function batchTranslation(): Promise<void> {
|
||||
const readmes = [
|
||||
"./README.md",
|
||||
"./packages/core/README.md",
|
||||
"./packages/cli/README.md",
|
||||
];
|
||||
|
||||
const languages = ["es", "fr", "de"];
|
||||
|
||||
for (const readme of readmes) {
|
||||
console.log(`\nProcessing: ${readme}`);
|
||||
await translateReadme({
|
||||
source: readme,
|
||||
languages,
|
||||
verbose: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Example 5: Custom output pattern for docs sites
|
||||
async function docsiteSetup(): Promise<void> {
|
||||
// For docusaurus/vitepress style: docs/README.es.md
|
||||
await translateReadme({
|
||||
source: "./README.md",
|
||||
languages: ["es", "fr", "de", "ja", "zh"],
|
||||
outputDir: "./docs",
|
||||
pattern: "README.{lang}.md",
|
||||
verbose: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Example 6: Conditional translation in CI/CD
|
||||
async function cicdTranslation(): Promise<void> {
|
||||
// Only translate on main branch releases
|
||||
const isRelease = process.env.GITHUB_REF === "refs/heads/main";
|
||||
const isManualTrigger = process.env.GITHUB_EVENT_NAME === "workflow_dispatch";
|
||||
|
||||
if (!isRelease && !isManualTrigger) {
|
||||
console.log("Skipping translation - not a release build");
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await translateReadme({
|
||||
source: "./README.md",
|
||||
languages: ["es", "fr", "de", "ja", "ko", "zh", "pt-br"],
|
||||
outputDir: "./dist/i18n",
|
||||
maxBudgetUsd: 10.0,
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Write summary for GitHub Actions
|
||||
if (process.env.GITHUB_STEP_SUMMARY) {
|
||||
const summary = `
|
||||
## Translation Summary
|
||||
- ✅ Successful: ${result.successful}
|
||||
- ❌ Failed: ${result.failed}
|
||||
- 💰 Cost: $${result.totalCostUsd.toFixed(4)}
|
||||
`;
|
||||
// In real usage, write to GITHUB_STEP_SUMMARY
|
||||
console.log(summary);
|
||||
}
|
||||
}
|
||||
|
||||
// Run an example
|
||||
const example = process.argv[2];
|
||||
|
||||
switch (example) {
|
||||
case "simple":
|
||||
translateToCommonLanguages();
|
||||
break;
|
||||
case "full":
|
||||
fullI18nSetup();
|
||||
break;
|
||||
case "batch":
|
||||
batchTranslation();
|
||||
break;
|
||||
case "docs":
|
||||
docsiteSetup();
|
||||
break;
|
||||
case "ci":
|
||||
cicdTranslation();
|
||||
break;
|
||||
default:
|
||||
console.log("Available examples: simple, full, batch, docs, ci");
|
||||
console.log("\nSupported languages:", SUPPORTED_LANGUAGES.join(", "));
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
import { query, type SDKMessage, type SDKResultMessage } from "@anthropic-ai/claude-agent-sdk";
|
||||
import * as fs from "fs/promises";
|
||||
import * as path from "path";
|
||||
|
||||
export interface TranslationOptions {
|
||||
/** Source README file path */
|
||||
source: string;
|
||||
/** Target languages (e.g., ['es', 'fr', 'de', 'ja', 'zh']) */
|
||||
languages: string[];
|
||||
/** Output directory (defaults to same directory as source) */
|
||||
outputDir?: string;
|
||||
/** Output filename pattern (use {lang} placeholder, defaults to 'README.{lang}.md') */
|
||||
pattern?: string;
|
||||
/** Preserve code blocks without translation */
|
||||
preserveCode?: boolean;
|
||||
/** Model to use (defaults to 'sonnet') */
|
||||
model?: string;
|
||||
/** Maximum budget in USD for the entire translation job */
|
||||
maxBudgetUsd?: number;
|
||||
/** Verbose output */
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
export interface TranslationResult {
|
||||
language: string;
|
||||
outputPath: string;
|
||||
success: boolean;
|
||||
error?: string;
|
||||
costUsd?: number;
|
||||
}
|
||||
|
||||
export interface TranslationJobResult {
|
||||
results: TranslationResult[];
|
||||
totalCostUsd: number;
|
||||
successful: number;
|
||||
failed: number;
|
||||
}
|
||||
|
||||
const LANGUAGE_NAMES: Record<string, string> = {
|
||||
ar: "Arabic",
|
||||
bg: "Bulgarian",
|
||||
cs: "Czech",
|
||||
da: "Danish",
|
||||
de: "German",
|
||||
el: "Greek",
|
||||
es: "Spanish",
|
||||
et: "Estonian",
|
||||
fi: "Finnish",
|
||||
fr: "French",
|
||||
he: "Hebrew",
|
||||
hi: "Hindi",
|
||||
hu: "Hungarian",
|
||||
id: "Indonesian",
|
||||
it: "Italian",
|
||||
ja: "Japanese",
|
||||
ko: "Korean",
|
||||
lt: "Lithuanian",
|
||||
lv: "Latvian",
|
||||
nl: "Dutch",
|
||||
no: "Norwegian",
|
||||
pl: "Polish",
|
||||
pt: "Portuguese",
|
||||
"pt-br": "Brazilian Portuguese",
|
||||
ro: "Romanian",
|
||||
ru: "Russian",
|
||||
sk: "Slovak",
|
||||
sl: "Slovenian",
|
||||
sv: "Swedish",
|
||||
th: "Thai",
|
||||
tr: "Turkish",
|
||||
uk: "Ukrainian",
|
||||
vi: "Vietnamese",
|
||||
zh: "Chinese (Simplified)",
|
||||
"zh-tw": "Chinese (Traditional)",
|
||||
};
|
||||
|
||||
function getLanguageName(code: string): string {
|
||||
return LANGUAGE_NAMES[code.toLowerCase()] || code;
|
||||
}
|
||||
|
||||
async function translateToLanguage(
|
||||
content: string,
|
||||
targetLang: string,
|
||||
options: Pick<TranslationOptions, "preserveCode" | "model" | "verbose">
|
||||
): Promise<{ translation: string; costUsd: number }> {
|
||||
const languageName = getLanguageName(targetLang);
|
||||
|
||||
const preserveCodeInstructions = options.preserveCode
|
||||
? `
|
||||
IMPORTANT: Preserve all code blocks exactly as they are. Do NOT translate:
|
||||
- Code inside \`\`\` blocks
|
||||
- Inline code inside \` backticks
|
||||
- Command examples
|
||||
- File paths
|
||||
- Variable names, function names, and technical identifiers
|
||||
- URLs and links
|
||||
`
|
||||
: "";
|
||||
|
||||
const prompt = `Translate the following README.md content from English to ${languageName} (${targetLang}).
|
||||
|
||||
${preserveCodeInstructions}
|
||||
Guidelines:
|
||||
- Maintain all Markdown formatting (headers, lists, links, etc.)
|
||||
- Keep the same document structure
|
||||
- Translate headings, descriptions, and explanatory text naturally
|
||||
- Preserve technical accuracy
|
||||
- Use appropriate technical terminology for ${languageName}
|
||||
- Keep proper nouns (product names, company names) unchanged unless they have official translations
|
||||
|
||||
Here is the README content to translate:
|
||||
|
||||
---
|
||||
${content}
|
||||
---
|
||||
|
||||
Output ONLY the translated README content, nothing else. Do not include any preamble or explanation.`;
|
||||
|
||||
let translation = "";
|
||||
let costUsd = 0;
|
||||
let charCount = 0;
|
||||
const startTime = Date.now();
|
||||
|
||||
const stream = query({
|
||||
prompt,
|
||||
options: {
|
||||
model: options.model || "sonnet",
|
||||
systemPrompt: `You are an expert technical translator specializing in software documentation.
|
||||
You translate README files while preserving Markdown formatting and technical accuracy.
|
||||
Always output only the translated content without any surrounding explanation.`,
|
||||
permissionMode: "bypassPermissions",
|
||||
allowDangerouslySkipPermissions: true,
|
||||
includePartialMessages: true, // Enable streaming events
|
||||
},
|
||||
});
|
||||
|
||||
// Progress spinner frames
|
||||
const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||
let spinnerIdx = 0;
|
||||
|
||||
for await (const message of stream) {
|
||||
// Handle streaming text deltas
|
||||
if (message.type === "stream_event") {
|
||||
const event = message.event as { type: string; delta?: { type: string; text?: string } };
|
||||
if (event.type === "content_block_delta" && event.delta?.type === "text_delta" && event.delta.text) {
|
||||
translation += event.delta.text;
|
||||
charCount += event.delta.text.length;
|
||||
|
||||
if (options.verbose) {
|
||||
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
||||
const spinner = spinnerFrames[spinnerIdx++ % spinnerFrames.length];
|
||||
process.stdout.write(`\r ${spinner} Translating... ${charCount} chars (${elapsed}s)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle full assistant messages (fallback)
|
||||
if (message.type === "assistant") {
|
||||
for (const block of message.message.content) {
|
||||
if (block.type === "text" && !translation) {
|
||||
translation = block.text;
|
||||
charCount = translation.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.type === "result") {
|
||||
const result = message as SDKResultMessage;
|
||||
if (result.subtype === "success") {
|
||||
costUsd = result.total_cost_usd;
|
||||
// Use the result text if we didn't get it from streaming
|
||||
if (!translation && result.result) {
|
||||
translation = result.result;
|
||||
charCount = translation.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the progress line
|
||||
if (options.verbose) {
|
||||
process.stdout.write("\r" + " ".repeat(60) + "\r");
|
||||
}
|
||||
|
||||
return { translation: translation.trim(), costUsd };
|
||||
}
|
||||
|
||||
export async function translateReadme(
|
||||
options: TranslationOptions
|
||||
): Promise<TranslationJobResult> {
|
||||
const {
|
||||
source,
|
||||
languages,
|
||||
outputDir,
|
||||
pattern = "README.{lang}.md",
|
||||
preserveCode = true,
|
||||
model,
|
||||
maxBudgetUsd,
|
||||
verbose = false,
|
||||
} = options;
|
||||
|
||||
// Read source file
|
||||
const sourcePath = path.resolve(source);
|
||||
const content = await fs.readFile(sourcePath, "utf-8");
|
||||
|
||||
// Determine output directory
|
||||
const outDir = outputDir ? path.resolve(outputDir) : path.dirname(sourcePath);
|
||||
await fs.mkdir(outDir, { recursive: true });
|
||||
|
||||
const results: TranslationResult[] = [];
|
||||
let totalCostUsd = 0;
|
||||
|
||||
if (verbose) {
|
||||
console.log(`📖 Source: ${sourcePath}`);
|
||||
console.log(`📂 Output: ${outDir}`);
|
||||
console.log(`🌍 Languages: ${languages.join(", ")}`);
|
||||
console.log("");
|
||||
}
|
||||
|
||||
for (const lang of languages) {
|
||||
// Check budget
|
||||
if (maxBudgetUsd && totalCostUsd >= maxBudgetUsd) {
|
||||
results.push({
|
||||
language: lang,
|
||||
outputPath: "",
|
||||
success: false,
|
||||
error: "Budget exceeded",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const outputFilename = pattern.replace("{lang}", lang);
|
||||
const outputPath = path.join(outDir, outputFilename);
|
||||
|
||||
if (verbose) {
|
||||
console.log(`🔄 Translating to ${getLanguageName(lang)} (${lang})...`);
|
||||
}
|
||||
|
||||
try {
|
||||
const { translation, costUsd } = await translateToLanguage(content, lang, {
|
||||
preserveCode,
|
||||
model,
|
||||
verbose,
|
||||
});
|
||||
|
||||
await fs.writeFile(outputPath, translation, "utf-8");
|
||||
totalCostUsd += costUsd;
|
||||
|
||||
results.push({
|
||||
language: lang,
|
||||
outputPath,
|
||||
success: true,
|
||||
costUsd,
|
||||
});
|
||||
|
||||
if (verbose) {
|
||||
console.log(` ✅ Saved to ${outputFilename} ($${costUsd.toFixed(4)})`);
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
results.push({
|
||||
language: lang,
|
||||
outputPath,
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
});
|
||||
|
||||
if (verbose) {
|
||||
console.log(` ❌ Failed: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const successful = results.filter((r) => r.success).length;
|
||||
const failed = results.filter((r) => !r.success).length;
|
||||
|
||||
if (verbose) {
|
||||
console.log("");
|
||||
console.log(`📊 Summary: ${successful} succeeded, ${failed} failed`);
|
||||
console.log(`💰 Total cost: $${totalCostUsd.toFixed(4)}`);
|
||||
}
|
||||
|
||||
return {
|
||||
results,
|
||||
totalCostUsd,
|
||||
successful,
|
||||
failed,
|
||||
};
|
||||
}
|
||||
|
||||
// Export language codes for convenience
|
||||
export const SUPPORTED_LANGUAGES = Object.keys(LANGUAGE_NAMES);
|
||||
Reference in New Issue
Block a user