claude-starter 1.3.4 → 1.3.5

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.
Files changed (3) hide show
  1. package/README.md +113 -113
  2. package/index.js +90 -48
  3. package/package.json +6 -2
package/README.md CHANGED
@@ -11,8 +11,8 @@
11
11
  <h1 align="center">🚀 Claude Starter</h1>
12
12
 
13
13
  <p align="center">
14
- <strong>Claude Code 的主页。</strong>你的所有会话,一目了然。<br/>
15
- <strong>Your homepage for Claude Code.</strong> All your sessions, at a glance.
14
+ <strong>Your homepage for Claude Code.</strong> All your sessions, at a glance.<br/>
15
+ <strong>Claude Code 的主页。</strong>你的所有会话,一目了然。
16
16
  </p>
17
17
 
18
18
  <p align="center">
@@ -25,117 +25,7 @@
25
25
 
26
26
  ---
27
27
 
28
- # 🇨🇳 中文
29
-
30
- ## 痛点
31
-
32
- 用过 Claude Code 的 `/resume` 吗?它给你的是这样一坨东西:
33
-
34
- ```
35
- ? Select a conversation
36
- 3ee0f33a-b882-424f-9ba4-260342e4dd5b - 4/3/2026, 10:53:41 AM
37
- 87570bab-ee92-4681-9591-54abf2fcb486 - 4/3/2026, 10:18:55 AM
38
- ...200 个 UUID...
39
- ```
40
-
41
- 一堆 UUID,没有上下文,无法搜索。**想找到上周帮你调过 bug 的那个 session?祝你好运。**
42
-
43
- ## 解决方案
44
-
45
- **Claude Starter** 是一个精美的终端可视化工具,让你能像浏览网页一样浏览所有 Claude 历史会话。它是你的 **Claude 主页** —— 每次打开终端,`claude-starter` 一敲,所有 session 一目了然。
46
-
47
- ```bash
48
- claude-starter
49
- ```
50
-
51
- 精美的分屏 UI,Tokyo Night 配色。左侧列表一目了然,右侧实时预览对话详情。不是 UUID,是你**真正说过的话**。
52
-
53
- ## 🔍 搜索 — 杀手级功能
54
-
55
- 按 `/` 开始输入,**就这么简单**。无需按回车。
56
-
57
- 跨项目名、Git 分支、对话内容**全文实时搜索**。输入即过滤,`↑↓` 直接导航结果。
58
-
59
- - `auth` → 所有认证相关的对话
60
- - `refactor` → 上周的代码重构
61
- - `web-app fix` → 某个项目的 bug 修复
62
-
63
- **不需要管理模式,不需要确认。输入即搜,方向键即走。**
64
-
65
- ## 核心能力
66
-
67
- | | 功能 | 说明 |
68
- |---|---|---|
69
- | 🎨 | **精美 TUI** | Tokyo Night 配色,分屏布局,终端里的 App |
70
- | ✨ | **一键新建** | 列表顶部直接新建对话 |
71
- | 🔍 | **即时搜索** | `/` 全文搜索,无需回车 |
72
- | 📂 | **项目过滤** | `p` 按项目筛选 |
73
- | ⚡ | **秒级恢复** | 选中 → Enter → 回到对话 |
74
- | 📋 | **对话预览** | 右侧面板展示完整元数据和对话历史 |
75
- | 🔀 | **多种排序** | 时间 / 大小 / 消息数 / 项目 |
76
- | 📎 | **复制 ID** | `c` 一键复制到剪贴板 |
77
- | 🔒 | **权限模式** | `m` 设置权限模式,`d` 一键 danger 模式恢复 |
78
- | ✏️ | **重命名会话** | `r` 直接重命名,支持中文输入 |
79
- | 🗑️ | **删除会话** | `x` 删除不需要的会话 |
80
- | ⌨️ | **Vim 快捷键** | `j`/`k` 上下,`g`/`G` 跳顶/底 |
81
- | 🧠 | **智能 CLI** | 自动检测 `mai-claude` / `claude` |
82
- | 🔐 | **完全本地** | 不联网,不上传,不追踪 |
83
-
84
- ## 安装
85
-
86
- ```bash
87
- npm install -g claude-starter
88
- ```
89
-
90
- 或者从源码安装:
91
-
92
- ```bash
93
- git clone https://github.com/Bojun-Vvibe/claude-starter.git
94
- cd claude-starter
95
- npm install
96
- npm link
97
- ```
98
-
99
- 然后运行 `claude-starter`,就这么简单。
100
-
101
- ## CLI 参数
102
-
103
- ```bash
104
- claude-starter # 启动交互式 TUI
105
- claude-starter --list [N] # 打印最近 N 个会话(默认 30)
106
- claude-starter --version # 显示版本号
107
- claude-starter --update # 检查并更新到最新版本
108
- claude-starter --help # 显示帮助信息
109
- ```
110
-
111
- ## 快捷键
112
-
113
- | 按键 | 功能 |
114
- |:---:|------|
115
- | `↑` `↓` / `j` `k` | 上下导航 |
116
- | `Enter` | 新建 / 恢复对话 |
117
- | `n` | 直接新建 |
118
- | `d` | Danger 模式恢复(bypassPermissions) |
119
- | `m` | 权限模式选择器 |
120
- | `r` | 重命名会话 |
121
- | `/` | 搜索 |
122
- | `Backspace` | 删除搜索字符,删空自动退出 |
123
- | `Esc` | 清空搜索 |
124
- | `p` | 按项目过滤 |
125
- | `s` | 切换排序(时间/大小/消息数/项目) |
126
- | `c` | 复制 Session ID |
127
- | `x` / `Delete` | 删除会话 |
128
- | `g` / `G` | 跳到顶 / 底 |
129
- | `Ctrl-D` / `Ctrl-U` | 翻页 |
130
- | `q` / `Ctrl-C` | 退出 |
131
-
132
- ## 原理
133
-
134
- 读取 `~/.claude/projects/` 下的 JSONL 会话文件,解析元数据和对话内容。200 个 session 加载耗时 ~10ms。**所有数据留在本地,不联网。**
135
-
136
- ---
137
-
138
- # 🇬🇧 English
28
+ # English
139
29
 
140
30
  ## The Problem
141
31
 
@@ -256,6 +146,116 @@ MIT
256
146
 
257
147
  ---
258
148
 
149
+ # 中文
150
+
151
+ ## 痛点
152
+
153
+ 用过 Claude Code 的 `/resume` 吗?它给你的是这样一坨东西:
154
+
155
+ ```
156
+ ? Select a conversation
157
+ 3ee0f33a-b882-424f-9ba4-260342e4dd5b - 4/3/2026, 10:53:41 AM
158
+ 87570bab-ee92-4681-9591-54abf2fcb486 - 4/3/2026, 10:18:55 AM
159
+ ...200 个 UUID...
160
+ ```
161
+
162
+ 一堆 UUID,没有上下文,无法搜索。**想找到上周帮你调过 bug 的那个 session?祝你好运。**
163
+
164
+ ## 解决方案
165
+
166
+ **Claude Starter** 是一个精美的终端可视化工具,让你能像浏览网页一样浏览所有 Claude 历史会话。它是你的 **Claude 主页** —— 每次打开终端,`claude-starter` 一敲,所有 session 一目了然。
167
+
168
+ ```bash
169
+ claude-starter
170
+ ```
171
+
172
+ 精美的分屏 UI,Tokyo Night 配色。左侧列表一目了然,右侧实时预览对话详情。不是 UUID,是你**真正说过的话**。
173
+
174
+ ## 🔍 搜索 — 杀手级功能
175
+
176
+ 按 `/` 开始输入,**就这么简单**。无需按回车。
177
+
178
+ 跨项目名、Git 分支、对话内容**全文实时搜索**。输入即过滤,`↑↓` 直接导航结果。
179
+
180
+ - `auth` → 所有认证相关的对话
181
+ - `refactor` → 上周的代码重构
182
+ - `web-app fix` → 某个项目的 bug 修复
183
+
184
+ **不需要管理模式,不需要确认。输入即搜,方向键即走。**
185
+
186
+ ## 核心能力
187
+
188
+ | | 功能 | 说明 |
189
+ |---|---|---|
190
+ | 🎨 | **精美 TUI** | Tokyo Night 配色,分屏布局,终端里的 App |
191
+ | ✨ | **一键新建** | 列表顶部直接新建对话 |
192
+ | 🔍 | **即时搜索** | `/` 全文搜索,无需回车 |
193
+ | 📂 | **项目过滤** | `p` 按项目筛选 |
194
+ | ⚡ | **秒级恢复** | 选中 → Enter → 回到对话 |
195
+ | 📋 | **对话预览** | 右侧面板展示完整元数据和对话历史 |
196
+ | 🔀 | **多种排序** | 时间 / 大小 / 消息数 / 项目 |
197
+ | 📎 | **复制 ID** | `c` 一键复制到剪贴板 |
198
+ | 🔒 | **权限模式** | `m` 设置权限模式,`d` 一键 danger 模式恢复 |
199
+ | ✏️ | **重命名会话** | `r` 直接重命名,支持中文输入 |
200
+ | 🗑️ | **删除会话** | `x` 删除不需要的会话 |
201
+ | ⌨️ | **Vim 快捷键** | `j`/`k` 上下,`g`/`G` 跳顶/底 |
202
+ | 🧠 | **智能 CLI** | 自动检测 `mai-claude` / `claude` |
203
+ | 🔐 | **完全本地** | 不联网,不上传,不追踪 |
204
+
205
+ ## 安装
206
+
207
+ ```bash
208
+ npm install -g claude-starter
209
+ ```
210
+
211
+ 或者从源码安装:
212
+
213
+ ```bash
214
+ git clone https://github.com/Bojun-Vvibe/claude-starter.git
215
+ cd claude-starter
216
+ npm install
217
+ npm link
218
+ ```
219
+
220
+ 然后运行 `claude-starter`,就这么简单。
221
+
222
+ ## CLI 参数
223
+
224
+ ```bash
225
+ claude-starter # 启动交互式 TUI
226
+ claude-starter --list [N] # 打印最近 N 个会话(默认 30)
227
+ claude-starter --version # 显示版本号
228
+ claude-starter --update # 检查并更新到最新版本
229
+ claude-starter --help # 显示帮助信息
230
+ ```
231
+
232
+ ## 快捷键
233
+
234
+ | 按键 | 功能 |
235
+ |:---:|------|
236
+ | `↑` `↓` / `j` `k` | 上下导航 |
237
+ | `Enter` | 新建 / 恢复对话 |
238
+ | `n` | 直接新建 |
239
+ | `d` | Danger 模式恢复(bypassPermissions) |
240
+ | `m` | 权限模式选择器 |
241
+ | `r` | 重命名会话 |
242
+ | `/` | 搜索 |
243
+ | `Backspace` | 删除搜索字符,删空自动退出 |
244
+ | `Esc` | 清空搜索 |
245
+ | `p` | 按项目过滤 |
246
+ | `s` | 切换排序(时间/大小/消息数/项目) |
247
+ | `c` | 复制 Session ID |
248
+ | `x` / `Delete` | 删除会话 |
249
+ | `g` / `G` | 跳到顶 / 底 |
250
+ | `Ctrl-D` / `Ctrl-U` | 翻页 |
251
+ | `q` / `Ctrl-C` | 退出 |
252
+
253
+ ## 原理
254
+
255
+ 读取 `~/.claude/projects/` 下的 JSONL 会话文件,解析元数据和对话内容。200 个 session 加载耗时 ~10ms。**所有数据留在本地,不联网。**
256
+
257
+ ---
258
+
259
259
  <p align="center">
260
260
  <sub>Built with 💜 by <a href="https://github.com/Bojun-Vvibe">Bojun</a> — powered by Claude Code itself</sub>
261
261
  </p>
package/index.js CHANGED
@@ -1508,58 +1508,99 @@ function createApp() {
1508
1508
  listPanel.focus();
1509
1509
  }
1510
1510
 
1511
+ // ─── Exports for Testing ────────────────────────────────────────────────────
1512
+ // When required as a module (e.g. by tests), export helpers without launching
1513
+ // the CLI / TUI. The entry-point logic only runs when executed directly.
1514
+
1515
+ if (typeof module !== 'undefined') {
1516
+ module.exports = {
1517
+ // Data helpers
1518
+ getProjectDisplayName,
1519
+ extractUserText,
1520
+ loadSessionQuick,
1521
+ loadSessionDetail,
1522
+ loadAllSessions,
1523
+ // Formatting
1524
+ formatTimestamp,
1525
+ formatFileSize,
1526
+ getProjectColor,
1527
+ esc,
1528
+ // Meta
1529
+ loadMeta,
1530
+ saveMeta,
1531
+ getSessionMeta,
1532
+ getEffectivePermissionMode,
1533
+ setSessionPermissionMode,
1534
+ setGlobalPermissionMode,
1535
+ // Constants
1536
+ PERMISSION_MODES,
1537
+ PROJECT_COLORS,
1538
+ CLAUDE_DIR,
1539
+ PROJECTS_DIR,
1540
+ META_FILE,
1541
+ // CLI
1542
+ detectCLI,
1543
+ // List mode (for integration tests)
1544
+ runListMode,
1545
+ // TUI (for interaction tests)
1546
+ createApp,
1547
+ };
1548
+ }
1549
+
1511
1550
  // ─── Entry Point ─────────────────────────────────────────────────────────────
1551
+ // Only run CLI/TUI when executed directly (not when required as a module).
1512
1552
 
1513
- const PKG = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'));
1553
+ if (require.main === module) {
1554
+ const PKG = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'));
1514
1555
 
1515
- const args = process.argv.slice(2);
1556
+ const args = process.argv.slice(2);
1516
1557
 
1517
- if (args.includes('--version') || args.includes('-v') || args.includes('-V')) {
1518
- console.log(`claude-starter v${PKG.version}`);
1519
- process.exit(0);
1520
- }
1521
-
1522
- if (args.includes('--update') || args.includes('-u')) {
1523
- const C = {
1524
- reset: '\x1b[0m', dim: '\x1b[2m', bold: '\x1b[1m',
1525
- cyan: '\x1b[36m', yellow: '\x1b[33m', green: '\x1b[32m',
1526
- red: '\x1b[31m',
1527
- };
1528
- console.log(`\n${C.cyan}🔄 Checking for updates…${C.reset}\n`);
1558
+ if (args.includes('--version') || args.includes('-v') || args.includes('-V')) {
1559
+ console.log(`claude-starter v${PKG.version}`);
1560
+ process.exit(0);
1561
+ }
1529
1562
 
1530
- try {
1531
- const latest = execSync('npm view claude-starter version 2>/dev/null', {
1532
- stdio: ['pipe', 'pipe', 'pipe'],
1533
- timeout: 10000,
1534
- }).toString().trim();
1563
+ if (args.includes('--update') || args.includes('-u')) {
1564
+ const C = {
1565
+ reset: '\x1b[0m', dim: '\x1b[2m', bold: '\x1b[1m',
1566
+ cyan: '\x1b[36m', yellow: '\x1b[33m', green: '\x1b[32m',
1567
+ red: '\x1b[31m',
1568
+ };
1569
+ console.log(`\n${C.cyan}🔄 Checking for updates…${C.reset}\n`);
1535
1570
 
1536
- if (latest === PKG.version) {
1537
- console.log(`${C.green}✓ Already on the latest version (v${PKG.version})${C.reset}\n`);
1538
- process.exit(0);
1539
- }
1571
+ try {
1572
+ const latest = execSync('npm view claude-starter version 2>/dev/null', {
1573
+ stdio: ['pipe', 'pipe', 'pipe'],
1574
+ timeout: 10000,
1575
+ }).toString().trim();
1576
+
1577
+ if (latest === PKG.version) {
1578
+ console.log(`${C.green}✓ Already on the latest version (v${PKG.version})${C.reset}\n`);
1579
+ process.exit(0);
1580
+ }
1540
1581
 
1541
- console.log(`${C.yellow} Current: v${PKG.version}${C.reset}`);
1542
- console.log(`${C.green} Latest: v${latest}${C.reset}\n`);
1543
- console.log(`${C.cyan}📦 Updating…${C.reset}\n`);
1582
+ console.log(`${C.yellow} Current: v${PKG.version}${C.reset}`);
1583
+ console.log(`${C.green} Latest: v${latest}${C.reset}\n`);
1584
+ console.log(`${C.cyan}📦 Updating…${C.reset}\n`);
1544
1585
 
1545
- try {
1546
- execSync('npm install -g claude-starter@latest', { stdio: 'inherit', timeout: 60000 });
1547
- console.log(`\n${C.green}${C.bold}✓ Updated to v${latest}${C.reset}\n`);
1586
+ try {
1587
+ execSync('npm install -g claude-starter@latest', { stdio: 'inherit', timeout: 60000 });
1588
+ console.log(`\n${C.green}${C.bold}✓ Updated to v${latest}${C.reset}\n`);
1589
+ } catch (e) {
1590
+ console.error(`\n${C.red}✗ Update failed. Try manually:${C.reset}`);
1591
+ console.log(`${C.yellow} npm install -g claude-starter@latest${C.reset}\n`);
1592
+ process.exit(1);
1593
+ }
1548
1594
  } catch (e) {
1549
- console.error(`\n${C.red}✗ Update failed. Try manually:${C.reset}`);
1550
- console.log(`${C.yellow} npm install -g claude-starter@latest${C.reset}\n`);
1595
+ console.error(`${C.red}✗ Could not check for updates (network error or npm not found)${C.reset}\n`);
1551
1596
  process.exit(1);
1552
1597
  }
1553
- } catch (e) {
1554
- console.error(`${C.red}✗ Could not check for updates (network error or npm not found)${C.reset}\n`);
1555
- process.exit(1);
1556
- }
1557
1598
 
1558
- process.exit(0);
1559
- }
1599
+ process.exit(0);
1600
+ }
1560
1601
 
1561
- if (args.includes('--help') || args.includes('-h')) {
1562
- console.log(`
1602
+ if (args.includes('--help') || args.includes('-h')) {
1603
+ console.log(`
1563
1604
  \x1b[36m🚀 Claude Starter\x1b[0m \x1b[2mv${PKG.version}\x1b[0m
1564
1605
 
1565
1606
  Usage:
@@ -1585,14 +1626,15 @@ TUI Keyboard Shortcuts:
1585
1626
  Esc Clear filter
1586
1627
  q / Ctrl-C Quit
1587
1628
  `);
1588
- process.exit(0);
1589
- }
1629
+ process.exit(0);
1630
+ }
1590
1631
 
1591
- if (args.includes('--list') || args.includes('-l')) {
1592
- const limitIdx = args.indexOf('--list') !== -1 ? args.indexOf('--list') : args.indexOf('-l');
1593
- const limit = parseInt(args[limitIdx + 1]) || 30;
1594
- runListMode(limit);
1595
- process.exit(0);
1596
- }
1632
+ if (args.includes('--list') || args.includes('-l')) {
1633
+ const limitIdx = args.indexOf('--list') !== -1 ? args.indexOf('--list') : args.indexOf('-l');
1634
+ const limit = parseInt(args[limitIdx + 1]) || 30;
1635
+ runListMode(limit);
1636
+ process.exit(0);
1637
+ }
1597
1638
 
1598
- createApp();
1639
+ createApp();
1640
+ }
package/package.json CHANGED
@@ -1,13 +1,17 @@
1
1
  {
2
2
  "name": "claude-starter",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "A beautiful terminal UI for managing Claude Code sessions — start new or resume past conversations",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "claude-starter": "./index.js"
8
8
  },
9
9
  "scripts": {
10
- "start": "node index.js"
10
+ "start": "node index.js",
11
+ "test": "node --test test.js",
12
+ "test:tui": "node --test --test-force-exit test-tui.js",
13
+ "test:all": "node --test --test-force-exit test.js test-tui.js",
14
+ "prepublishOnly": "npm run test:all"
11
15
  },
12
16
  "keywords": [
13
17
  "claude",