claude-chats-sync 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 tubo70
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # claude-chats-sync
2
+
3
+ [![npm version](https://badge.fury.io/js/claude-chats-sync.svg)](https://www.npmjs.com/package/claude-chats-sync)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node](https://img.shields.io/node/v/claude-chats-sync.svg)](https://nodejs.org)
6
+
7
+ > Cross-platform CLI tool to sync Claude Code chat sessions to your project directory
8
+
9
+ [中文文档](README.zh-CN.md) | English
10
+
11
+ ## ✨ Features
12
+
13
+ - 🔄 **Auto-sync** - Creates symlinks from Claude Code local storage to your project folder
14
+ - 📁 **Project-local history** - Chat sessions stored in your project, not user home directory
15
+ - 🔒 **Sensitive data protection** - Cleans API keys from session files
16
+ - 🎯 **Simple to use** - Initialize sync with a single command
17
+ - 📊 **Status tracking** - Check sync status and session count
18
+ - 🌳 **Git-friendly** - Configure Git filters for safe version control
19
+ - 🔧 **Cross-platform** - Works on Windows, macOS, and Linux
20
+
21
+ ## 📦 Installation
22
+
23
+ ### Install globally (recommended)
24
+
25
+ ```bash
26
+ npm install -g claude-chats-sync
27
+ ```
28
+
29
+ This allows you to use `claude-chats-sync` command from anywhere.
30
+
31
+ ### Install locally
32
+
33
+ ```bash
34
+ npm install -D claude-chats-sync
35
+ ```
36
+
37
+ Then use it via `npx`:
38
+ ```bash
39
+ npx claude-chats-sync init
40
+ ```
41
+
42
+ ## 🚀 Quick Start
43
+
44
+ ### Initialize sync
45
+
46
+ ```bash
47
+ # In your project directory
48
+ claude-chats-sync init
49
+ ```
50
+
51
+ This will:
52
+ - Create a `.claudeCodeSessions/` folder in your project
53
+ - Create a symlink in `~/.claude/projects/`
54
+ - Configure Git filter for automatic sensitive data cleaning
55
+ - Add `.claudeCodeSessions/` to `.gitignore` (commented by default)
56
+
57
+ ### Check status
58
+
59
+ ```bash
60
+ claude-chats-sync status
61
+ ```
62
+
63
+ ### Open history folder
64
+
65
+ ```bash
66
+ claude-chats-sync open
67
+ ```
68
+
69
+ ## 📖 Commands
70
+
71
+ | Command | Description |
72
+ |---------|-------------|
73
+ | `init` | Initialize sync for current project |
74
+ | `status` | Check sync status and session count |
75
+ | `open` | Open history folder in file manager |
76
+ | `clean` | Clean sensitive data from session files |
77
+ | `setup-git-filter` | Setup Git filter for automatic cleaning |
78
+ | `help` | Show help message |
79
+
80
+ ## 🔧 Usage Examples
81
+
82
+ ### Basic usage
83
+
84
+ ```bash
85
+ # Initialize sync
86
+ claude-chats-sync init
87
+
88
+ # Check status
89
+ claude-chats-sync status
90
+
91
+ # Open sessions folder
92
+ claude-chats-sync open
93
+ ```
94
+
95
+ ### Advanced options
96
+
97
+ ```bash
98
+ # Custom folder name
99
+ claude-chats-sync init --folder-name .sessions
100
+
101
+ # Force migrate existing sessions
102
+ claude-chats-sync init --force
103
+
104
+ # Specify project path
105
+ claude-chats-sync init --project-path /path/to/project
106
+ ```
107
+
108
+ ### Cleaning sensitive data
109
+
110
+ ```bash
111
+ # Manual cleanup
112
+ claude-chats-sync clean
113
+
114
+ # Setup Git auto-filter
115
+ claude-chats-sync setup-git-filter
116
+ ```
117
+
118
+ ## ⚙️ Environment Variables (Recommended)
119
+
120
+ Configure API keys via environment variables to prevent them from appearing in session files:
121
+
122
+ **Linux/macOS** - Add to `~/.bashrc` or `~/.zshrc`:
123
+ ```bash
124
+ export ANTHROPIC_AUTH_TOKEN="sk-ant-..."
125
+ export ANTHROPIC_BASE_URL="https://api.example.com" # Optional: for third-party API
126
+ ```
127
+
128
+ **Windows PowerShell**:
129
+ ```powershell
130
+ $env:ANTHROPIC_AUTH_TOKEN="sk-ant-..."
131
+ $env:ANTHROPIC_BASE_URL="https://api.example.com"
132
+ ```
133
+
134
+ **Windows CMD (permanent)**:
135
+ ```cmd
136
+ setx ANTHROPIC_AUTH_TOKEN "sk-ant-..."
137
+ setx ANTHROPIC_BASE_URL "https://api.example.com"
138
+ ```
139
+
140
+ ## 🔒 Security & Version Control
141
+
142
+ ### ⚠️ Security Warning
143
+
144
+ Session files may contain sensitive information:
145
+ - API keys and authentication tokens
146
+ - Proprietary code and business logic
147
+ - Private conversations and internal discussions
148
+ - System paths and environment details
149
+
150
+ While this tool provides API key cleaning, **no automated cleaning is 100% complete**. Only commit these files if you fully understand and accept the security risks.
151
+
152
+ ### Options for securing API keys
153
+
154
+ **Option 1: Use environment variables (Recommended)**
155
+
156
+ Configure Claude Code to use API keys from environment variables. This prevents them from appearing in session files entirely.
157
+
158
+ **Option 2: Use Git filter**
159
+
160
+ If you store API keys in config files, the Git filter automatically cleans them on commit.
161
+
162
+ ### Git filter usage
163
+
164
+ After initialization, commit normally:
165
+
166
+ ```bash
167
+ git add .claudeCodeSessions/
168
+ git commit -m "Add conversation history"
169
+
170
+ # API keys are automatically replaced with [REDACTED]
171
+ # Your local files remain unchanged
172
+ ```
173
+
174
+ ### Complete Git ignore (safest)
175
+
176
+ **RECOMMENDED**: Ignore session files entirely. Uncomment in `.gitignore`:
177
+
178
+ ```gitignore
179
+ .claudeCodeSessions/
180
+ ```
181
+
182
+ This prevents accidentally committing sensitive data to your repository.
183
+
184
+ ## 🌐 How It Works
185
+
186
+ Claude Code stores chat sessions in `~/.claude/projects/{normalized-project-path}/`.
187
+
188
+ This CLI creates a symbolic link to a folder in your project (default: `.claudeCodeSessions/`), making the chat history part of your project.
189
+
190
+ ### Example structure
191
+
192
+ ```
193
+ Your Project/
194
+ ├── src/
195
+ ├── .claudeCodeSessions/ # Chat sessions (synced with ~/.claude)
196
+ │ ├── session-abc123.jsonl
197
+ │ └── session-def456.jsonl
198
+ ├── .gitignore # Auto-updated
199
+ ├── .gitattributes # Git filter configuration
200
+ └── package.json
201
+ ```
202
+
203
+ ## 🔄 Syncing Across Machines
204
+
205
+ If you choose to sync session files:
206
+
207
+ 1. Commit the `.claudeCodeSessions/` folder
208
+ 2. Push to GitHub
209
+ 3. Pull on another machine
210
+ 4. Run `claude-chats-sync init` to create the symlink
211
+
212
+ ## 🔧 Platform-specific Notes
213
+
214
+ ### Windows
215
+ - Uses junction points (no admin privileges required)
216
+ - Supports PowerShell and CMD
217
+ - Run PowerShell scripts may require: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
218
+
219
+ ### macOS
220
+ - Requires execute permissions: `chmod +x $(which claude-chats-sync)`
221
+ - Uses standard symbolic links
222
+
223
+ ### Linux
224
+ - Requires execute permissions: `chmod +x $(which claude-chats-sync)`
225
+ - Uses standard symbolic links
226
+
227
+ ## 🐛 Troubleshooting
228
+
229
+ ### Symlink creation fails (Windows)
230
+
231
+ The tool uses junction points which work without admin privileges. If issues persist:
232
+ - Ensure Node.js is in your PATH
233
+ - Try running as administrator
234
+ - Check that your project path doesn't contain special characters
235
+
236
+ ### History not syncing
237
+
238
+ 1. Check if symlink exists:
239
+ - Windows: `dir %USERPROFILE%\.claude\projects`
240
+ - macOS/Linux: `ls -la ~/.claude/projects`
241
+
242
+ 2. Verify symlink points to your project's `.claudeCodeSessions/` folder
243
+
244
+ ### Reinitialize
245
+
246
+ Delete existing symlink:
247
+
248
+ ```bash
249
+ # Windows
250
+ rmdir "%USERPROFILE%\.claude\projects\{project-name}"
251
+
252
+ # macOS/Linux
253
+ rm ~/.claude/projects/{project-name}
254
+ ```
255
+
256
+ Then run `claude-chats-sync init` again.
257
+
258
+ ## 📚 Related Projects
259
+
260
+ - [VSCode Extension](https://marketplace.visualstudio.com/items?itemName=tubo.claude-code-chats-sync) - Full-featured VSCode extension with the same functionality
261
+
262
+ ## 💰 Token Usage & Cost Considerations
263
+
264
+ > ⚠️ **IMPORTANT**: When sharing session files, each team member uses their own API key and incurs their own API costs.
265
+
266
+ ### Key points
267
+
268
+ 1. **Each member pays for their own usage**
269
+ - Every team member must configure their own API key
270
+ - When you continue a shared conversation, **you pay for all new tokens** generated
271
+ - The original creator's API key is **never** used
272
+
273
+ 2. **Context window considerations**
274
+ - Long shared conversations consume more tokens as context
275
+ - A shared conversation with 50,000 tokens will consume ~50,000 input tokens each time a new member continues it
276
+
277
+ 3. **Cost-saving best practices**
278
+ - Generate conversation summaries before sharing
279
+ - Start new conversations when possible
280
+ - Archive old sessions
281
+ - Monitor your API usage
282
+
283
+ For detailed cost considerations, see [Token Usage Guide](TOKEN_USAGE.md).
284
+
285
+ ## 📝 License
286
+
287
+ MIT - see [LICENSE](LICENSE) file for details
288
+
289
+ ## 🤝 Contributing
290
+
291
+ Contributions are welcome! Please open an issue or submit a pull request.
292
+
293
+ ## 📞 Support
294
+
295
+ - 📧 [Issues](https://github.com/tubo70/claude-chats-sync/issues)
296
+ - 📖 [Documentation](https://github.com/tubo70/claude-chats-sync/wiki)
297
+ - 💬 [Discussions](https://github.com/tubo70/claude-chats-sync/discussions)
298
+
299
+ ## 🔗 Links
300
+
301
+ - [npm](https://www.npmjs.com/package/claude-chats-sync)
302
+ - [GitHub](https://github.com/tubo70/claude-chats-sync)
303
+ - [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=tubo.claude-code-chats-sync)
304
+
305
+ ---
306
+
307
+ Made with ❤️ by [tubo70](https://github.com/tubo70)
@@ -0,0 +1,305 @@
1
+ # claude-chats-sync
2
+
3
+ [![npm version](https://badge.fury.io/js/claude-chats-sync.svg)](https://www.npmjs.com/package/claude-chats-sync)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node](https://img.shields.io/node/v/claude-chats-sync.svg)](https://nodejs.org)
6
+
7
+ > 跨平台命令行工具,将 Claude Code 聊天会话同步到项目目录
8
+
9
+ 中文文档 | [English](README.md)
10
+
11
+ ## ✨ 功能特性
12
+
13
+ - 🔄 **自动同步** - 创建符号链接将 Claude Code 会话同步到项目文件夹
14
+ - 📁 **项目本地历史** - 聊天会话存储在项目中,而不是用户主目录
15
+ - 🔒 **敏感数据保护** - 清理会话文件中的 API keys
16
+ - 🎯 **简单易用** - 单个命令即可初始化同步
17
+ - 📊 **状态跟踪** - 检查同步状态和会话数量
18
+ - 🌳 **Git 友好** - 配置 Git 过滤器以安全地进行版本控制
19
+ - 🔧 **跨平台** - 支持 Windows、macOS 和 Linux
20
+
21
+ ## 📦 安装
22
+
23
+ ### 全局安装(推荐)
24
+
25
+ ```bash
26
+ npm install -g claude-chats-sync
27
+ ```
28
+
29
+ 安装后可以在任何地方使用 `claude-chats-sync` 命令。
30
+
31
+ ### 本地安装
32
+
33
+ ```bash
34
+ npm install -D claude-chats-sync
35
+ ```
36
+
37
+ 然后通过 `npx` 使用:
38
+ ```bash
39
+ npx claude-chats-sync init
40
+ ```
41
+
42
+ ## 🚀 快速开始
43
+
44
+ ### 初始化同步
45
+
46
+ ```bash
47
+ # 在项目目录中
48
+ claude-chats-sync init
49
+ ```
50
+
51
+ 这将:
52
+ - 在项目中创建 `.claudeCodeSessions/` 文件夹
53
+ - 在 `~/.claude/projects/` 中创建符号链接
54
+ - 配置 Git 过滤器以自动清理敏感数据
55
+ - 将 `.claudeCodeSessions/` 添加到 `.gitignore`(默认被注释)
56
+
57
+ ### 查看状态
58
+
59
+ ```bash
60
+ claude-chats-sync status
61
+ ```
62
+
63
+ ### 打开历史文件夹
64
+
65
+ ```bash
66
+ claude-chats-sync open
67
+ ```
68
+
69
+ ## 📖 命令
70
+
71
+ | 命令 | 说明 |
72
+ |------|------|
73
+ | `init` | 初始化当前项目的同步 |
74
+ | `status` | 检查同步状态和会话数量 |
75
+ | `open` | 在文件管理器中打开历史文件夹 |
76
+ | `clean` | 清理会话文件中的敏感数据 |
77
+ | `setup-git-filter` | 设置 Git 自动清理过滤器 |
78
+ | `help` | 显示帮助信息 |
79
+
80
+ ## 🔧 使用示例
81
+
82
+ ### 基本用法
83
+
84
+ ```bash
85
+ # 初始化同步
86
+ claude-chats-sync init
87
+
88
+ # 查看状态
89
+ claude-chats-sync status
90
+
91
+ # 打开会话文件夹
92
+ claude-chats-sync open
93
+ ```
94
+
95
+ ### 高级选项
96
+
97
+ ```bash
98
+ # 自定义文件夹名称
99
+ claude-chats-sync init --folder-name .sessions
100
+
101
+ # 强制迁移现有会话
102
+ claude-chats-sync init --force
103
+
104
+ # 指定项目路径
105
+ claude-chats-sync init --project-path /path/to/project
106
+ ```
107
+
108
+ ### 清理敏感数据
109
+
110
+ ```bash
111
+ # 手动清理
112
+ claude-chats-sync clean
113
+
114
+ # 设置 Git 自动过滤器
115
+ claude-chats-sync setup-git-filter
116
+ ```
117
+
118
+ ## ⚙️ 环境变量配置(推荐)
119
+
120
+ 通过环境变量配置 API keys,防止它们出现在会话文件中:
121
+
122
+ **Linux/macOS** - 添加到 `~/.bashrc` 或 `~/.zshrc`:
123
+ ```bash
124
+ export ANTHROPIC_AUTH_TOKEN="sk-ant-..."
125
+ export ANTHROPIC_BASE_URL="https://api.example.com" # 可选:第三方 API
126
+ ```
127
+
128
+ **Windows PowerShell**:
129
+ ```powershell
130
+ $env:ANTHROPIC_AUTH_TOKEN="sk-ant-..."
131
+ $env:ANTHROPIC_BASE_URL="https://api.example.com"
132
+ ```
133
+
134
+ **Windows CMD(永久设置)**:
135
+ ```cmd
136
+ setx ANTHROPIC_AUTH_TOKEN "sk-ant-..."
137
+ setx ANTHROPIC_BASE_URL="https://api.example.com"
138
+ ```
139
+
140
+ ## 🔒 安全与版本控制
141
+
142
+ ### ⚠️ 安全警告
143
+
144
+ 会话文件可能包含敏感信息:
145
+ - API keys 和认证令牌
146
+ - 专有代码和业务逻辑
147
+ - 私人对话和内部讨论
148
+ - 系统路径和环境详情
149
+
150
+ 虽然本工具提供了 API key 清理功能,**但没有任何自动清理是 100% 完整的**。只有在你完全理解并接受安全风险时才提交这些文件。
151
+
152
+ ### API Key 配置选项
153
+
154
+ **选项 1:使用环境变量(推荐)**
155
+
156
+ 配置 Claude Code 从环境变量使用 API keys,防止它们出现在会话文件中。这是最安全的方法。
157
+
158
+ **选项 2:使用 Git 过滤器**
159
+
160
+ 如果你在配置文件中存储 API keys,Git 过滤器会在提交时自动清理它们。
161
+
162
+ ### Git 过滤器使用
163
+
164
+ 初始化后,正常提交即可:
165
+
166
+ ```bash
167
+ git add .claudeCodeSessions/
168
+ git commit -m "添加对话历史"
169
+
170
+ # API keys 自动替换为 [REDACTED]
171
+ # 你的本地文件保持不变
172
+ ```
173
+
174
+ ### 完全 Git 忽略(最安全)
175
+
176
+ **推荐**:完全忽略会话文件。在 `.gitignore` 中取消注释:
177
+
178
+ ```gitignore
179
+ .claudeCodeSessions/
180
+ ```
181
+
182
+ 这可以防止意外将敏感数据提交到仓库。
183
+
184
+ ## 🌐 工作原理
185
+
186
+ Claude Code 将聊天会话存储在 `~/.claude/projects/{normalized-project-path}/` 中。
187
+
188
+ 本 CLI 创建一个指向项目文件夹的符号链接(默认:`.claudeCodeSessions/`),使聊天历史成为项目的一部分。
189
+
190
+ ### 示例结构
191
+
192
+ ```
193
+ Your Project/
194
+ ├── src/
195
+ ├── .claudeCodeSessions/ # 聊天会话(与 ~/.claude 同步)
196
+ │ ├── session-abc123.jsonl
197
+ │ └── session-def456.jsonl
198
+ ├── .gitignore # 自动更新
199
+ ├── .gitattributes # Git 过滤器配置
200
+ └── package.json
201
+ ```
202
+
203
+ ## 🔄 跨机器同步
204
+
205
+ 如果你选择同步会话文件:
206
+
207
+ 1. 提交 `.claudeCodeSessions/` 文件夹
208
+ 2. 推送到 GitHub
209
+ 3. 在另一台机器上拉取
210
+ 4. 运行 `claude-chats-sync init` 创建符号链接
211
+
212
+ ## 🔧 平台特定说明
213
+
214
+ ### Windows
215
+ - 使用 junction 点(不需要管理员权限)
216
+ - 支持 PowerShell 和 CMD
217
+ - 运行 PowerShell 脚本可能需要:`Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
218
+
219
+ ### macOS
220
+ - 需要执行权限:`chmod +x $(which claude-chats-sync)`
221
+ - 使用标准符号链接
222
+
223
+ ### Linux
224
+ - 需要执行权限:`chmod +x $(which claude-chats-sync)`
225
+ - 使用标准符号链接
226
+
227
+ ## 🐛 故障排除
228
+
229
+ ### 符号链接创建失败(Windows)
230
+
231
+ 本工具使用 junction 点,无需管理员权限。如果仍有问题:
232
+ - 确保 Node.js 在 PATH 中
233
+ - 尝试以管理员身份运行
234
+ - 检查项目路径不包含特殊字符
235
+
236
+ ### 历史记录未同步
237
+
238
+ 1. 检查符号链接是否存在:
239
+ - Windows: `dir %USERPROFILE%\.claude\projects`
240
+ - macOS/Linux: `ls -la ~/.claude/projects`
241
+
242
+ 2. 验证符号链接是否指向项目的 `.claudeCodeSessions/` 文件夹
243
+
244
+ ### 重新初始化
245
+
246
+ 删除现有符号链接:
247
+
248
+ ```bash
249
+ # Windows
250
+ rmdir "%USERPROFILE%\.claude\projects\{project-name}"
251
+
252
+ # macOS/Linux
253
+ rm ~/.claude/projects/{project-name}
254
+ ```
255
+
256
+ 然后再次运行 `claude-chats-sync init`。
257
+
258
+ ## 📚 相关项目
259
+
260
+ - [VSCode 扩展](https://marketplace.visualstudio.com/items?itemName=tubo.claude-code-chats-sync) - 功能完整的 VSCode 扩展
261
+
262
+ ## 💰 Token 使用与成本考虑
263
+
264
+ > ⚠️ **重要提示**:在团队成员间共享会话文件时,每个成员使用自己的 API key 并承担自己的 API 成本。
265
+
266
+ ### 关键要点
267
+
268
+ 1. **每个成员支付自己的使用费用**
269
+ - 每个团队成员必须配置自己的 API key
270
+ - 当你继续共享的对话时,**你需要为所有新生成的 tokens 付费**
271
+ - 原始创建者的 API key **不会被使用**
272
+
273
+ 2. **上下文窗口考虑**
274
+ - 较长的共享对话会消耗更多 tokens 作为上下文
275
+ - 一个包含 50,000 tokens 的共享对话,每次新成员继续时都会消耗约 50,000 个输入 tokens
276
+
277
+ 3. **节省成本的最佳实践**
278
+ - 共享前生成对话摘要
279
+ - 尽可能开始新对话
280
+ - 归档旧会话
281
+ - 监控 API 使用情况
282
+
283
+ ## 📝 许可证
284
+
285
+ MIT - 详见 [LICENSE](LICENSE) 文件
286
+
287
+ ## 🤝 贡献
288
+
289
+ 欢迎贡献!请提交 issue 或拉取请求。
290
+
291
+ ## 📞 支持
292
+
293
+ - 📧 [问题反馈](https://github.com/tubo70/claude-chats-sync/issues)
294
+ - 📖 [文档](https://github.com/tubo70/claude-chats-sync/wiki)
295
+ - 💬 [讨论](https://github.com/tubo70/claude-chats-sync/discussions)
296
+
297
+ ## 🔗 链接
298
+
299
+ - [npm](https://www.npmjs.com/package/claude-chats-sync)
300
+ - [GitHub](https://github.com/tubo70/claude-chats-sync)
301
+ - [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=tubo.claude-code-chats-sync)
302
+
303
+ ---
304
+
305
+ 由 [tubo70](https://github.com/tubo70) 用 ❤️ 制作
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Claude Code Sync CLI - Bash wrapper
4
+ # This script allows you to run the CLI with just "claude-sync" command
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ node "$SCRIPT_DIR/claude-sync.js" "$@"
@@ -0,0 +1,5 @@
1
+ @echo off
2
+ REM Claude Code Sync CLI - Windows batch wrapper
3
+
4
+ set SCRIPT_DIR=%~dp0
5
+ node "%SCRIPT_DIR%claude-sync.js" %*
@@ -0,0 +1,620 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Claude Code Sync CLI
5
+ *
6
+ * 跨平台命令行工具,用于同步 Claude Code 聊天会话到项目目录
7
+ * Cross-platform CLI tool to sync Claude Code chat sessions to project directory
8
+ *
9
+ * Usage:
10
+ * node claude-sync-cli.js init # Initialize sync
11
+ * node claude-sync-cli.js status # Check sync status
12
+ * node claude-sync-cli.js open # Open history folder
13
+ * node claude-sync-cli.js clean # Clean sensitive data from session files
14
+ * node claude-sync-cli.js setup-git-filter # Setup Git filter for auto-cleaning
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const os = require('os');
20
+ const { execSync } = require('child_process');
21
+
22
+ // ANSI 颜色代码 / ANSI color codes
23
+ const colors = {
24
+ reset: '\x1b[0m',
25
+ red: '\x1b[31m',
26
+ green: '\x1b[32m',
27
+ yellow: '\x1b[33m',
28
+ blue: '\x1b[34m',
29
+ cyan: '\x1b[36m'
30
+ };
31
+
32
+ // 工具函数 / Utility functions
33
+ function log(message, color = 'reset') {
34
+ console.log(`${colors[color]}${message}${colors.reset}`);
35
+ }
36
+
37
+ function error(message) {
38
+ log(`❌ Error: ${message}`, 'red');
39
+ }
40
+
41
+ function success(message) {
42
+ log(`✅ ${message}`, 'green');
43
+ }
44
+
45
+ function info(message) {
46
+ log(`ℹ️ ${message}`, 'cyan');
47
+ }
48
+
49
+ function warn(message) {
50
+ log(`⚠️ ${message}`, 'yellow');
51
+ }
52
+
53
+ /**
54
+ * 规范化项目路径为 Claude Code 格式
55
+ * Normalize project path to Claude Code format
56
+ *
57
+ * Windows: D:\Projects\MyProject -> d--Projects-MyProject
58
+ * Linux/Mac: /home/user/projects/my-project -> home-user-projects-my-project
59
+ */
60
+ function normalizeProjectPath(projectPath) {
61
+ if (process.platform === 'win32') {
62
+ // Windows: Replace backslashes and colons with dashes, preserve case
63
+ return projectPath
64
+ .replace(/\\/g, '-')
65
+ .replace(/:/g, '-');
66
+ } else {
67
+ // Linux/Mac: Replace forward slashes with dashes, preserve case
68
+ return projectPath
69
+ .replace(/^\//, '') // Remove leading slash
70
+ .replace(/\//g, '-'); // Replace remaining slashes with dashes
71
+ }
72
+ }
73
+
74
+ /**
75
+ * 获取 Claude Code 项目目录
76
+ * Get Claude Code projects directory
77
+ */
78
+ function getClaudeProjectsDir() {
79
+ return path.join(os.homedir(), '.claude', 'projects');
80
+ }
81
+
82
+ /**
83
+ * 获取项目中的历史文件夹路径
84
+ * Get history folder path in the project
85
+ */
86
+ function getHistoryFolderPath(projectPath, folderName = '.claudeCodeSessions') {
87
+ return path.join(projectPath, folderName);
88
+ }
89
+
90
+ /**
91
+ * 创建符号链接 (跨平台)
92
+ * Create symbolic link (cross-platform)
93
+ */
94
+ function createSymlink(target, linkPath) {
95
+ if (process.platform === 'win32') {
96
+ // Windows: 使用 junction (不需要管理员权限)
97
+ // Windows: Use junction (no admin privileges required)
98
+ fs.symlinkSync(target, linkPath, 'junction');
99
+ } else {
100
+ // Unix: 使用符号链接
101
+ // Unix: Use symbolic link
102
+ fs.symlinkSync(target, linkPath);
103
+ }
104
+ }
105
+
106
+ /**
107
+ * 检查是否为符号链接
108
+ * Check if path is a symbolic link
109
+ */
110
+ function isSymlink(symlinkPath) {
111
+ try {
112
+ const stats = fs.lstatSync(symlinkPath);
113
+ return stats.isSymbolicLink() || (process.platform === 'win32' && stats.isDirectory());
114
+ } catch {
115
+ return false;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * 移动目录 (递归)
121
+ * Move directory (recursive)
122
+ */
123
+ function moveDirectory(src, dest) {
124
+ // 创建目标目录
125
+ fs.mkdirSync(dest, { recursive: true });
126
+
127
+ // 递归复制所有文件和子目录
128
+ const entries = fs.readdirSync(src, { withFileTypes: true });
129
+
130
+ for (const entry of entries) {
131
+ const srcPath = path.join(src, entry.name);
132
+ const destPath = path.join(dest, entry.name);
133
+
134
+ if (entry.isDirectory()) {
135
+ moveDirectory(srcPath, destPath);
136
+ } else {
137
+ fs.copyFileSync(srcPath, destPath);
138
+ }
139
+ }
140
+
141
+ // 删除源目录
142
+ fs.rmSync(src, { recursive: true, force: true });
143
+ }
144
+
145
+ /**
146
+ * 清理会话文件内容中的敏感信息
147
+ * Clean sensitive information from session file content
148
+ */
149
+ function cleanSensitiveData(content) {
150
+ // Pattern for Anthropic API keys (normal format)
151
+ const apiKeyPattern = /"primaryApiKey"\s*:\s*"sk-ant-[^"]*"/g;
152
+
153
+ // Pattern for API keys within escaped JSON strings
154
+ const apiKeyPatternEscaped = /\\"primaryApiKey\\":\s*\\"sk-ant-[^"]*\\"/g;
155
+
156
+ // Pattern for ANTHROPIC_AUTH_TOKEN (escaped format)
157
+ const authTokenPatternEscaped = /\\"ANTHROPIC_AUTH_TOKEN\\"\\s*:\\s*\\"[^"]*\\"/g;
158
+
159
+ // Pattern for other API keys
160
+ const genericApiKeyPattern = /"(apiKey|api_key|authorization|token|bearer)"\s*:\s*"[^"]*"/gi;
161
+
162
+ // Clean API keys
163
+ let cleaned = content.replace(apiKeyPattern, '"primaryApiKey": "[REDACTED]"');
164
+ cleaned = cleaned.replace(apiKeyPatternEscaped, '\\"primaryApiKey\\": \\"[REDACTED]\\"');
165
+ cleaned = cleaned.replace(authTokenPatternEscaped, '\\"ANTHROPIC_AUTH_TOKEN\\": \\"[REDACTED]\\"');
166
+ cleaned = cleaned.replace(genericApiKeyPattern, '"$1": "[REDACTED]"');
167
+
168
+ return cleaned;
169
+ }
170
+
171
+ /**
172
+ * 初始化同步
173
+ * Initialize sync
174
+ */
175
+ function init(projectPath, options = {}) {
176
+ const { folderName = '.claudeCodeSessions', force = false } = options;
177
+
178
+ const historyFolder = getHistoryFolderPath(projectPath, folderName);
179
+ const claudeProjectsDir = getClaudeProjectsDir();
180
+ const normalizedPath = normalizeProjectPath(projectPath);
181
+ const symlinkPath = path.join(claudeProjectsDir, normalizedPath);
182
+
183
+ try {
184
+ // 检查符号链接是否已存在
185
+ // Check if symlink already exists
186
+ if (fs.existsSync(symlinkPath)) {
187
+ if (isSymlink(symlinkPath)) {
188
+ success('Claude Code Chats Sync already initialized');
189
+ info(`History folder: ${historyFolder}`);
190
+ info(`Linked to: ${symlinkPath}`);
191
+ return;
192
+ } else if (fs.lstatSync(symlinkPath).isDirectory()) {
193
+ // 现有真实目录 - 用户之前使用过 Claude Code
194
+ // Existing real directory - user has used Claude Code before
195
+ const files = fs.readdirSync(symlinkPath);
196
+ const sessionFiles = files.filter(f => f.endsWith('.jsonl'));
197
+
198
+ if (sessionFiles.length > 0 && !force) {
199
+ warn(`Found ${sessionFiles.length} existing Claude Code session(s) in Claude's storage.`);
200
+ info('Use --force to move them to your project folder');
201
+ return;
202
+ }
203
+
204
+ if (sessionFiles.length > 0 && force) {
205
+ // 移动现有目录到项目文件夹
206
+ // Move existing directory to project folder
207
+ moveDirectory(symlinkPath, historyFolder);
208
+ success(`Moved ${sessionFiles.length} session(s) to project folder!`);
209
+ } else {
210
+ // 空目录,直接删除
211
+ // Empty directory, just remove it
212
+ fs.rmSync(symlinkPath, { recursive: true, force: true });
213
+ }
214
+ } else {
215
+ error(`A file exists at Claude Code location: ${symlinkPath}`);
216
+ return;
217
+ }
218
+ }
219
+
220
+ // 创建历史文件夹 (如果不存在)
221
+ // Create history folder if it doesn't exist
222
+ if (!fs.existsSync(historyFolder)) {
223
+ fs.mkdirSync(historyFolder, { recursive: true });
224
+ success(`Created folder: ${historyFolder}`);
225
+ }
226
+
227
+ // 确保 .claude/projects 目录存在
228
+ // Ensure .claude/projects directory exists
229
+ if (!fs.existsSync(claudeProjectsDir)) {
230
+ fs.mkdirSync(claudeProjectsDir, { recursive: true });
231
+ }
232
+
233
+ // 创建符号链接
234
+ // Create symbolic link
235
+ createSymlink(historyFolder, symlinkPath);
236
+
237
+ success('Claude Code Chats Sync initialized!');
238
+ info(`History folder: ${historyFolder}`);
239
+ info(`Linked to: ${symlinkPath}`);
240
+
241
+ // 添加到 .gitignore
242
+ // Add to .gitignore
243
+ addToGitIgnore(projectPath, folderName);
244
+
245
+ // 设置 Git 过滤器
246
+ // Setup Git filter
247
+ setupGitFilter(projectPath, folderName, false);
248
+
249
+ } catch (err) {
250
+ error(`Failed to initialize: ${err.message}`);
251
+ }
252
+ }
253
+
254
+ /**
255
+ * 检查同步状态
256
+ * Check sync status
257
+ */
258
+ function status(projectPath, options = {}) {
259
+ const { folderName = '.claudeCodeSessions' } = options;
260
+
261
+ const historyFolder = getHistoryFolderPath(projectPath, folderName);
262
+ const claudeProjectsDir = getClaudeProjectsDir();
263
+ const normalizedPath = normalizeProjectPath(projectPath);
264
+ const symlinkPath = path.join(claudeProjectsDir, normalizedPath);
265
+
266
+ log('\n📊 Claude Code Chats Sync Status\n', 'blue');
267
+
268
+ // 检查历史文件夹
269
+ // Check history folder
270
+ if (fs.existsSync(historyFolder)) {
271
+ const files = fs.readdirSync(historyFolder).filter(f => f.endsWith('.jsonl'));
272
+ success('History folder exists');
273
+ info(` Path: ${historyFolder}`);
274
+ info(` Sessions: ${files.length}`);
275
+ } else {
276
+ error('History folder not found');
277
+ }
278
+
279
+ // 检查符号链接
280
+ // Check symlink
281
+ if (fs.existsSync(symlinkPath)) {
282
+ success('Symlink created');
283
+ info(` Path: ${symlinkPath}`);
284
+ } else {
285
+ error('Symlink not created');
286
+ }
287
+
288
+ console.log('');
289
+ }
290
+
291
+ /**
292
+ * 添加到 .gitignore
293
+ * Add to .gitignore
294
+ */
295
+ function addToGitIgnore(projectPath, folderName = '.claudeCodeSessions') {
296
+ const gitignorePath = path.join(projectPath, '.gitignore');
297
+
298
+ try {
299
+ let content = '';
300
+ if (fs.existsSync(gitignorePath)) {
301
+ content = fs.readFileSync(gitignorePath, 'utf-8');
302
+ }
303
+
304
+ const ignoreEntry = `# Claude Code conversation history
305
+ # Uncomment the line below to ignore session files, OR configure Git filter for safe sharing
306
+ # ${folderName}/`;
307
+
308
+ // 仅在不存在时添加
309
+ // Only add if not already present
310
+ if (!content.includes(`# ${folderName}/`) && !content.includes(`${folderName}/`)) {
311
+ if (content && !content.endsWith('\n')) {
312
+ content += '\n';
313
+ }
314
+ content += `\n${ignoreEntry}\n`;
315
+ fs.writeFileSync(gitignorePath, content, 'utf-8');
316
+ success('Added .gitignore entry (commented by default)');
317
+ }
318
+ } catch (err) {
319
+ warn('Could not update .gitignore (not a Git repository?)');
320
+ }
321
+ }
322
+
323
+ /**
324
+ * 设置 Git 过滤器
325
+ * Setup Git filter
326
+ */
327
+ function setupGitFilter(projectPath, folderName = '.claudeCodeSessions', showMessage = true) {
328
+ try {
329
+ // 检查是否为 Git 仓库
330
+ // Check if we're in a Git repository
331
+ const gitDir = path.join(projectPath, '.git');
332
+ if (!fs.existsSync(gitDir)) {
333
+ warn('Not a Git repository. Git filter will not be configured.');
334
+ return;
335
+ }
336
+
337
+ // 创建清理过滤器脚本
338
+ // Create clean filter script
339
+ const filterScriptPath = path.join(projectPath, '.gitfilters', 'clean-sessions.js');
340
+ const filterDir = path.dirname(filterScriptPath);
341
+
342
+ if (!fs.existsSync(filterDir)) {
343
+ fs.mkdirSync(filterDir, { recursive: true });
344
+ }
345
+
346
+ const filterScript = `#!/usr/bin/env node
347
+ const fs = require('fs');
348
+
349
+ // Pattern for Anthropic API keys (normal format)
350
+ const apiKeyPattern = /"primaryApiKey"\\\\s*:\\\\s*"sk-ant-[^"]*"/g;
351
+
352
+ // Pattern for API keys within escaped JSON strings
353
+ const apiKeyPatternEscaped = /\\\\\\\\"primaryApiKey\\\\\\\\"\\\\s*:\\\\\\\\s*\\\\\\"sk-ant-[^"]*\\\\\\"/g;
354
+
355
+ // Pattern for ANTHROPIC_AUTH_TOKEN (escaped format)
356
+ const authTokenPatternEscaped = /\\\\"ANTHROPIC_AUTH_TOKEN\\\\"\\\\s*:\\\\\\s*\\\\"[^"]*\\\\"/g;
357
+
358
+ // Pattern for other API keys
359
+ const genericApiKeyPattern = /"(apiKey|api_key|authorization|token|bearer)"\\\\s*:\\\\s*"[^"]*"/gi;
360
+
361
+ let data = '';
362
+ process.stdin.setEncoding('utf8');
363
+
364
+ process.stdin.on('data', (chunk) => {
365
+ data += chunk;
366
+ });
367
+
368
+ process.stdin.on('end', () => {
369
+ let cleaned = data.replace(apiKeyPattern, '"primaryApiKey": "[REDACTED]"');
370
+ cleaned = cleaned.replace(apiKeyPatternEscaped, '\\\\\\\\"primaryApiKey\\\\\\\\": \\\\"[REDACTED]\\\\"');
371
+ cleaned = cleaned.replace(authTokenPatternEscaped, '\\\\\\\\"ANTHROPIC_AUTH_TOKEN\\\\\\\\": \\\\"[REDACTED]\\\\"');
372
+ cleaned = cleaned.replace(genericApiKeyPattern, '"$1": "[REDACTED]"');
373
+ process.stdout.write(cleaned);
374
+ });
375
+ `;
376
+
377
+ fs.writeFileSync(filterScriptPath, filterScript, 'utf-8');
378
+
379
+ // 在 Unix-like 系统上设置为可执行
380
+ // Make it executable on Unix-like systems
381
+ if (process.platform !== 'win32') {
382
+ try {
383
+ fs.chmodSync(filterScriptPath, 0o755);
384
+ } catch (e) {
385
+ // Ignore permission errors
386
+ }
387
+ }
388
+
389
+ // 在 .gitconfig 中配置 Git 过滤器
390
+ // Configure Git filter in .gitconfig
391
+ const gitConfigPath = path.join(projectPath, '.gitconfig');
392
+
393
+ let gitConfig = '';
394
+ if (fs.existsSync(gitConfigPath)) {
395
+ gitConfig = fs.readFileSync(gitConfigPath, 'utf-8');
396
+ }
397
+
398
+ if (!gitConfig.includes('[filter "claude-clean"]')) {
399
+ if (gitConfig && !gitConfig.endsWith('\n')) {
400
+ gitConfig += '\n';
401
+ }
402
+ gitConfig += `[filter "claude-clean"]
403
+ clean = node .gitfilters/clean-sessions.js
404
+ `;
405
+ fs.writeFileSync(gitConfigPath, gitConfig, 'utf-8');
406
+ }
407
+
408
+ // 在本地 Git 配置中配置过滤器
409
+ // Configure the filter in local Git config
410
+ try {
411
+ execSync(
412
+ `git config filter.claude-clean.clean "node .gitfilters/clean-sessions.js"`,
413
+ { cwd: projectPath, stdio: 'pipe' }
414
+ );
415
+ } catch (err) {
416
+ warn(`Failed to configure local Git filter: ${err.message}`);
417
+ }
418
+
419
+ // 在 .gitattributes 中配置过滤器
420
+ // Configure the filter in .gitattributes
421
+ const gitAttributesPath = path.join(projectPath, '.gitattributes');
422
+
423
+ let gitAttributes = '';
424
+ if (fs.existsSync(gitAttributesPath)) {
425
+ gitAttributes = fs.readFileSync(gitAttributesPath, 'utf-8');
426
+ }
427
+
428
+ const filterLine = `${folderName}/*.jsonl filter=claude-clean`;
429
+
430
+ if (!gitAttributes.includes(filterLine)) {
431
+ if (gitAttributes && !gitAttributes.endsWith('\n')) {
432
+ gitAttributes += '\n';
433
+ }
434
+ gitAttributes += `\n# Claude Code sessions - clean sensitive data on commit\n${filterLine}\n`;
435
+ fs.writeFileSync(gitAttributesPath, gitAttributes, 'utf-8');
436
+ }
437
+
438
+ if (showMessage) {
439
+ success('Git filter configured');
440
+ info('Session files will be automatically cleaned on commit');
441
+ info('Original files remain unchanged. Only committed versions are cleaned.');
442
+ }
443
+
444
+ } catch (err) {
445
+ error(`Failed to setup Git filter: ${err.message}`);
446
+ }
447
+ }
448
+
449
+ /**
450
+ * 清理会话文件中的敏感数据
451
+ * Clean sensitive data from session files
452
+ */
453
+ function cleanSessions(projectPath, options = {}) {
454
+ const { folderName = '.claudeCodeSessions' } = options;
455
+
456
+ const historyFolder = getHistoryFolderPath(projectPath, folderName);
457
+
458
+ if (!fs.existsSync(historyFolder)) {
459
+ error('History folder does not exist');
460
+ return;
461
+ }
462
+
463
+ const files = fs.readdirSync(historyFolder).filter(f => f.endsWith('.jsonl'));
464
+
465
+ if (files.length === 0) {
466
+ warn('No session files to clean');
467
+ return;
468
+ }
469
+
470
+ info(`Cleaning ${files.length} session file(s)...`);
471
+
472
+ let cleanedCount = 0;
473
+ for (const file of files) {
474
+ const filePath = path.join(historyFolder, file);
475
+ const content = fs.readFileSync(filePath, 'utf-8');
476
+ const cleaned = cleanSensitiveData(content);
477
+
478
+ // 将清理后的内容写回文件
479
+ // Write cleaned content back to file
480
+ fs.writeFileSync(filePath, cleaned, 'utf-8');
481
+ cleanedCount++;
482
+ }
483
+
484
+ success(`Cleaned ${cleanedCount} session file(s)`);
485
+ info('Sensitive data has been redacted');
486
+ }
487
+
488
+ /**
489
+ * 打开历史文件夹
490
+ * Open history folder
491
+ */
492
+ function openFolder(projectPath, options = {}) {
493
+ const { folderName = '.claudeCodeSessions' } = options;
494
+
495
+ const historyFolder = getHistoryFolderPath(projectPath, folderName);
496
+
497
+ if (!fs.existsSync(historyFolder)) {
498
+ error('History folder does not exist. Please initialize first.');
499
+ return;
500
+ }
501
+
502
+ try {
503
+ const { exec } = require('child_process');
504
+
505
+ let command;
506
+ switch (process.platform) {
507
+ case 'darwin':
508
+ command = 'open';
509
+ break;
510
+ case 'win32':
511
+ command = 'explorer';
512
+ break;
513
+ default:
514
+ command = 'xdg-open';
515
+ }
516
+
517
+ exec(`${command} "${historyFolder}"`);
518
+ success(`Opened history folder: ${historyFolder}`);
519
+ } catch (err) {
520
+ error(`Failed to open folder: ${err.message}`);
521
+ }
522
+ }
523
+
524
+ /**
525
+ * 显示帮助信息
526
+ * Show help message
527
+ */
528
+ function showHelp() {
529
+ const help = `
530
+ Claude Code Sync CLI - 跨平台 Claude Code 会话同步工具
531
+ Claude Code Sync CLI - Cross-platform Claude Code session sync tool
532
+
533
+ Usage: node claude-sync-cli.js <command> [options]
534
+
535
+ Commands:
536
+ init Initialize sync for current project
537
+ status Check sync status and session count
538
+ open Open history folder in file manager
539
+ clean Clean sensitive data from session files
540
+ setup-git-filter Setup Git filter for automatic cleaning
541
+ help Show this help message
542
+
543
+ Options:
544
+ --folder-name <name> History folder name (default: .claudeCodeSessions)
545
+ --force Force migration of existing sessions
546
+ --project-path <path> Project path (default: current directory)
547
+
548
+ Examples:
549
+ node claude-sync-cli.js init
550
+ node claude-sync-cli.js init --folder-name .sessions
551
+ node claude-sync-cli.js init --force
552
+ node claude-sync-cli.js status
553
+ node claude-sync-cli.js clean
554
+ node claude-sync-cli.js setup-git-filter
555
+
556
+ Environment Variables:
557
+ ANTHROPIC_AUTH_TOKEN Recommended: Configure API key via env var
558
+ ANTHROPIC_BASE_URL Optional: Third-party API endpoint
559
+
560
+ For more information, visit: https://github.com/tubo70/claude-code-sync-extension
561
+ `;
562
+
563
+ console.log(help);
564
+ }
565
+
566
+ /**
567
+ * 主函数
568
+ * Main function
569
+ */
570
+ function main() {
571
+ const args = process.argv.slice(2);
572
+ const command = args[0];
573
+
574
+ // 解析选项
575
+ // Parse options
576
+ const options = {};
577
+ let projectPath = process.cwd();
578
+
579
+ for (let i = 1; i < args.length; i++) {
580
+ const arg = args[i];
581
+ if (arg === '--folder-name' && args[i + 1]) {
582
+ options.folderName = args[++i];
583
+ } else if (arg === '--project-path' && args[i + 1]) {
584
+ projectPath = args[++i];
585
+ } else if (arg === '--force') {
586
+ options.force = true;
587
+ }
588
+ }
589
+
590
+ if (!command || command === 'help' || command === '--help' || command === '-h') {
591
+ showHelp();
592
+ return;
593
+ }
594
+
595
+ switch (command) {
596
+ case 'init':
597
+ init(projectPath, options);
598
+ break;
599
+ case 'status':
600
+ status(projectPath, options);
601
+ break;
602
+ case 'open':
603
+ openFolder(projectPath, options);
604
+ break;
605
+ case 'clean':
606
+ cleanSessions(projectPath, options);
607
+ break;
608
+ case 'setup-git-filter':
609
+ setupGitFilter(projectPath, options.folderName, true);
610
+ break;
611
+ default:
612
+ error(`Unknown command: ${command}`);
613
+ info('Run "node claude-sync-cli.js help" for usage information');
614
+ process.exit(1);
615
+ }
616
+ }
617
+
618
+ // 运行主函数
619
+ // Run main function
620
+ main();
@@ -0,0 +1,17 @@
1
+ # Claude Code Sync CLI - PowerShell wrapper
2
+
3
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
4
+ $CliScript = Join-Path $ScriptDir "claude-sync.js"
5
+
6
+ # Check if Node.js is installed
7
+ try {
8
+ $null = & node --version 2>&1
9
+ } catch {
10
+ Write-Host "❌ Error: Node.js is not installed or not in PATH" -ForegroundColor Red
11
+ Write-Host "Please install Node.js from https://nodejs.org/" -ForegroundColor Yellow
12
+ exit 1
13
+ }
14
+
15
+ # Run the CLI script
16
+ & node $CliScript $args
17
+ exit $LASTEXITCODE
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "claude-chats-sync",
3
+ "version": "0.0.1",
4
+ "description": "Cross-platform CLI tool to sync Claude Code chat sessions to project directory",
5
+ "main": "bin/claude-chats-sync.js",
6
+ "bin": {
7
+ "claude-chats-sync": "./bin/claude-chats-sync.js"
8
+ },
9
+ "scripts": {
10
+ "init": "node bin/claude-chats-sync.js init",
11
+ "status": "node bin/claude-chats-sync.js status",
12
+ "open": "node bin/claude-chats-sync.js open",
13
+ "clean": "node bin/claude-chats-sync.js clean",
14
+ "setup-git-filter": "node bin/claude-chats-sync.js setup-git-filter",
15
+ "test": "echo \"Error: no test specified\" && exit 1"
16
+ },
17
+ "keywords": [
18
+ "claude",
19
+ "claude-code",
20
+ "claude-ai",
21
+ "sync",
22
+ "chat",
23
+ "sessions",
24
+ "cli",
25
+ "vscode",
26
+ "git",
27
+ "version-control",
28
+ "developer-tools"
29
+ ],
30
+ "author": {
31
+ "name": "tubo70",
32
+ "email": "445527@qq.com"
33
+ },
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/tubo70/claude-chats-sync.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/tubo70/claude-chats-sync/issues"
41
+ },
42
+ "homepage": "https://github.com/tubo70/claude-chats-sync#readme",
43
+ "engines": {
44
+ "node": ">=14.0.0"
45
+ },
46
+ "os": [
47
+ "win32",
48
+ "darwin",
49
+ "linux"
50
+ ],
51
+ "preferGlobal": true,
52
+ "files": [
53
+ "bin/",
54
+ "README.md",
55
+ "LICENSE"
56
+ ]
57
+ }