clawt 3.0.0 → 3.1.0

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.
@@ -440,6 +440,42 @@ var INIT_MESSAGES = {
440
440
  PROJECT_CONFIG_MISSING_BRANCH: "\u9879\u76EE\u914D\u7F6E\u7F3A\u5C11\u4E3B\u5DE5\u4F5C\u5206\u652F\u4FE1\u606F\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C clawt init \u8BBE\u7F6E\u4E3B\u5DE5\u4F5C\u5206\u652F"
441
441
  };
442
442
 
443
+ // src/constants/messages/interactive-panel.ts
444
+ import chalk from "chalk";
445
+
446
+ // src/constants/interactive-panel.ts
447
+ var PANEL_SHORTCUT_KEYS = {
448
+ /** 验证 */
449
+ VALIDATE: "v",
450
+ /** 合并 */
451
+ MERGE: "m",
452
+ /** 删除 */
453
+ DELETE: "d",
454
+ /** 恢复 */
455
+ RESUME: "r",
456
+ /** 同步 */
457
+ SYNC: "s",
458
+ /** 手动刷新 */
459
+ REFRESH: "f",
460
+ /** 退出 */
461
+ QUIT: "q"
462
+ };
463
+
464
+ // src/constants/messages/interactive-panel.ts
465
+ var SHORTCUT_LABELS = {
466
+ VALIDATE: "\u9A8C\u8BC1",
467
+ MERGE: "\u5408\u5E76",
468
+ DELETE: "\u5220\u9664",
469
+ RESUME: "\u6062\u590D",
470
+ SYNC: "\u540C\u6B65",
471
+ REFRESH: "\u5237\u65B0",
472
+ QUIT: "\u9000\u51FA"
473
+ };
474
+ var PANEL_FOOTER_SHORTCUTS = Object.entries(SHORTCUT_LABELS).map(([key, label]) => `[${chalk.cyan(PANEL_SHORTCUT_KEYS[key])}]${label}`).join(" ");
475
+ var PANEL_OVERFLOW_DOWN_HINT = chalk.gray("\u2193 \u66F4\u591A worktree...");
476
+ var PANEL_OVERFLOW_UP_HINT = chalk.gray("\u2191 \u66F4\u591A worktree...");
477
+ var PANEL_PRESS_ENTER_TO_RETURN = chalk.gray("\n\u6309 Enter \u8FD4\u56DE\u9762\u677F...");
478
+
443
479
  // src/constants/messages/index.ts
444
480
  var MESSAGES = {
445
481
  ...COMMON_MESSAGES,
@@ -517,8 +553,8 @@ var CONFIG_DESCRIPTIONS = deriveConfigDescriptions(CONFIG_DEFINITIONS);
517
553
  var UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
518
554
 
519
555
  // src/constants/prompt.ts
520
- import chalk from "chalk";
521
- var UNKNOWN_DATE_SEPARATOR_LABEL = `\u2550\u2550\u2550\u2550 ${chalk.bold.hex("#FF8C00")("\u672A\u77E5\u65E5\u671F")} \u2550\u2550\u2550\u2550`;
556
+ import chalk2 from "chalk";
557
+ var UNKNOWN_DATE_SEPARATOR_LABEL = `\u2550\u2550\u2550\u2550 ${chalk2.bold.hex("#FF8C00")("\u672A\u77E5\u65E5\u671F")} \u2550\u2550\u2550\u2550`;
522
558
 
523
559
  // scripts/postinstall.ts
524
560
  function ensureDirectory(dirPath) {
package/docs/spec.md CHANGED
@@ -278,7 +278,7 @@ export const PROJECTS_CONFIG_DIR = join(CLAWT_HOME, 'projects');
278
278
  | `clawt resume` | 在已有 worktree 中恢复 Claude Code 会话(支持多选批量恢复) | 5.11 |
279
279
  | `clawt sync` | 将主分支最新代码同步到目标 worktree(含验证分支重建) | 5.12 |
280
280
  | `clawt reset` | 重置主 worktree 工作区和暂存区 | 5.13 |
281
- | `clawt status` | 显示项目全局状态总览(支持 `--json` 格式输出) | 5.14 |
281
+ | `clawt status` | 显示项目全局状态总览(支持 `--json` 格式输出和 `-i` 交互式面板模式)| 5.14 |
282
282
  | `clawt alias` | 管理命令别名(列出 / 设置 / 移除) | 5.15 |
283
283
  | `clawt completion` | 为终端提供 shell 自动补全功能(bash/zsh) | 5.16 |
284
284
  | `clawt projects` | 展示所有项目的 worktree 概览,或查看指定项目的 worktree 详情 | 5.17 |
package/docs/status.md CHANGED
@@ -3,19 +3,22 @@
3
3
  **命令:**
4
4
 
5
5
  ```bash
6
- clawt status [--json]
6
+ clawt status [--json] [-i | --interactive]
7
7
  ```
8
8
 
9
9
  **参数:**
10
10
 
11
- | 参数 | 必填 | 说明 |
12
- | -------- | ---- | ---------------------------------------- |
13
- | `--json` | 否 | 以 JSON 格式输出完整状态数据 |
11
+ | 参数 | 必填 | 说明 |
12
+ | --------------------- | ---- | ---------------------------------------- |
13
+ | `--json` | 否 | 以 JSON 格式输出完整状态数据 |
14
+ | `-i, --interactive` | 否 | 启动交互式面板模式(TUI 实时刷新面板) |
14
15
 
15
16
  **使用场景:**
16
17
 
17
18
  在管理多个 worktree 时,快速了解项目全局状态:主 worktree 当前分支及干净状态、所有 worktree 的变更情况和与主分支的同步状态、validate 快照摘要。
18
19
 
20
+ 交互式面板模式适用于需要持续监控项目状态并快速执行操作的场景,无需反复输入命令。
21
+
19
22
  **运行流程:**
20
23
 
21
24
  1. **主 worktree 校验** (2.1)
@@ -36,6 +39,7 @@ clawt status [--json]
36
39
  - 统计快照总数和孤立快照数(对应 worktree 已不存在的快照)
37
40
  5. **输出状态信息**:
38
41
  - 指定 `--json` → 以 JSON 格式输出完整状态数据(`JSON.stringify`)
42
+ - 指定 `-i` / `--interactive` → 启动交互式面板模式(见下方「交互式面板模式」章节)
39
43
  - 未指定 → 以文本格式输出
40
44
 
41
45
  **文本输出格式(默认):**
@@ -152,4 +156,143 @@ clawt status [--json]
152
156
  - `getCommitCountBehind()` 是新增的工具函数(在 `src/utils/git.ts`),通过 `git rev-list --count <branch>..HEAD` 计算落后提交数
153
157
  - `getProjectSnapshotBranches()` 是新增的工具函数(在 `src/utils/validate-snapshot.ts`),通过扫描快照目录下的 `.tree` 文件提取分支名列表
154
158
 
159
+ **交互式面板模式(`-i` / `--interactive`):**
160
+
161
+ 通过 `-i` 选项启动一个实时刷新的 TUI(Text User Interface)面板,在终端中提供键盘导航和快捷键操作功能。面板基于备选屏幕(alternate screen)渲染,退出后终端恢复原状。
162
+
163
+ **前置条件:**
164
+
165
+ - 需要 TTY 终端环境。非 TTY 时(如管道、重定向场景)会输出降级提示并退出。
166
+
167
+ **面板布局:**
168
+
169
+ ```
170
+ 项目状态总览: my-project
171
+ 快照: 3 个(1 个孤立)
172
+ ──────── ↑ 更多 worktree... ────────
173
+ ════ 2026-03-01(2 天前) ════
174
+
175
+ ▶ feature-login [已提交]
176
+ +120 -30
177
+ 3 个本地提交
178
+ 与主分支同步
179
+ 创建于 3 天前
180
+ 上次验证: 2 小时前
181
+
182
+ feature-signup [未提交修改]
183
+ +45 -10
184
+ 1 个本地提交
185
+ 落后主分支 2 个提交
186
+ 创建于 1 天前
187
+ ✗ 未验证
188
+
189
+ ════ 2026-02-28(3 天前) ════
190
+
191
+ fix-bug [无变更]
192
+ 与主分支同步
193
+ 创建于 5 天前
194
+ ✗ 未验证
195
+
196
+ ──────── ↓ 更多 worktree... ────────
197
+ [v]验证 [m]合并 [d]删除 [r]恢复 [s]同步 [f]刷新 [q]退出 (3s 后刷新)
198
+ ```
199
+
200
+ 面板从上到下分为以下区域:
201
+
202
+ 1. **标题行**:显示项目名(`项目状态总览: <projectName>`)
203
+ 2. **快照摘要行**:显示快照总数和孤立快照数
204
+ 3. **顶部分隔线**:当存在向上溢出时,分隔线中间嵌入 `↑ 更多 worktree...` 提示
205
+ 4. **Worktree 滚动区域**:按日期分组显示 worktree 列表,支持上下滚动
206
+ 5. **底部分隔线**:当存在向下溢出时,分隔线中间嵌入 `↓ 更多 worktree...` 提示
207
+ 6. **底栏**:快捷键提示 + 自动刷新倒计时
208
+
209
+ **Worktree 日期分组显示:**
210
+
211
+ Worktree 按创建日期分组(复用 `groupWorktreesByDate()`),每组前显示日期分隔线,格式为 `════ YYYY-MM-DD(相对日期) ════`,相对日期如"今天"、"昨天"、"3 天前"等(通过 `formatRelativeDate()` 格式化)。
212
+
213
+ 每个 worktree 条目的渲染内容与文本输出模式一致(分支名 + 变更状态标签、行数差异、本地提交数、同步状态、创建时间、验证状态),选中项前显示 `▶` 指示器(青色),未选中项前显示等宽空格占位。
214
+
215
+ **键盘操作:**
216
+
217
+ | 按键 | 操作 |
218
+ | ------- | ---------------------------------------- |
219
+ | `↑` | 向上导航,选中上一个 worktree |
220
+ | `↓` | 向下导航,选中下一个 worktree |
221
+ | `v` | 对选中 worktree 执行 `clawt validate` |
222
+ | `m` | 对选中 worktree 执行 `clawt merge` |
223
+ | `d` | 对选中 worktree 执行 `clawt remove` |
224
+ | `r` | 对选中 worktree 执行 `clawt resume` |
225
+ | `s` | 对选中 worktree 执行 `clawt sync` |
226
+ | `f` | 手动刷新数据 |
227
+ | `q` | 退出面板 |
228
+ | `Ctrl+C`| 退出面板 |
229
+
230
+ **操作执行流程:**
231
+
232
+ 当用户按下操作快捷键(v/m/d/r/s)时,面板会:
233
+
234
+ 1. 暂停定时器和键盘监听
235
+ 2. 退出备选屏幕,恢复终端状态
236
+ 3. 以继承 stdio 的方式执行对应的 clawt 子命令(如 `clawt validate -b <branch>`)
237
+ 4. 命令完成后,输出 `按 Enter 返回面板...` 提示
238
+ 5. 等待用户按 Enter 键
239
+ 6. 重新进入备选屏幕,刷新数据,恢复面板
240
+
241
+ 执行操作期间设置操作锁(`isOperating`),阻止其他按键响应。
242
+
243
+ **自动刷新机制:**
244
+
245
+ - 数据刷新间隔:每 5 秒自动调用 `collectStatus()` 重新收集数据(常量 `PANEL_REFRESH_INTERVAL_MS`)
246
+ - 倒计时更新:每 1 秒更新底栏的倒计时显示(常量 `PANEL_COUNTDOWN_INTERVAL_MS`)
247
+ - 刷新后保持选中位置:通过记录刷新前选中的分支名,在新数据中查找匹配的分支恢复选中位置;若分支已被删除则调整到安全范围
248
+
249
+ **滚动机制:**
250
+
251
+ - 滚动区域高度 = 终端行数 - 固定行数(标题 + 快照摘要 + 顶部分隔线 + 底部分隔线 + 底栏 = `PANEL_FIXED_ROWS + 1`),最小 3 行
252
+ - 导航时自动调整滚动偏移(`scrollOffset`),确保选中项及其所属日期分组标题在可见区域内
253
+ - 溢出提示嵌入分隔线中间,不额外占用行数
254
+ - 终端 resize 时自动触发重绘
255
+
256
+ **渲染机制:**
257
+
258
+ - 使用备选屏幕(`ALT_SCREEN_ENTER` / `ALT_SCREEN_LEAVE`)避免污染原始终端内容
259
+ - 使用同步输出序列(`SYNC_OUTPUT_START` / `SYNC_OUTPUT_END`)防止闪烁
260
+ - 隐藏光标、禁用行换行,确保渲染效果整洁
261
+ - 注册 `exit` 事件兜底处理器,确保异常退出时终端状态被恢复
262
+ - 每行通过 `truncateToTerminalWidth()` 截断以适配终端宽度
263
+
264
+ **实现要点:**
265
+
266
+ - `InteractivePanel` 类定义在 `src/utils/interactive-panel.ts`,参照 `ProgressRenderer` 的生命周期模式实现
267
+ - 渲染函数集定义在 `src/utils/interactive-panel-render.ts`,导出以下函数:
268
+ - `buildPanelFrame()`:构建完整帧内容
269
+ - `buildGroupedWorktreeLines()`:按日期分组构建 worktree 行列表,返回 `PanelLine[]`
270
+ - `buildDisplayOrder()`:构建显示顺序到原始索引的映射
271
+ - `renderDateSeparator()`:渲染日期分隔线
272
+ - `renderWorktreeBlock()`:渲染单个 worktree 的多行块
273
+ - `renderSnapshotSummary()`:渲染快照摘要行
274
+ - `renderFooter()`:渲染底栏
275
+ - `calculateVisibleRows()`:计算滚动区域可用行数
276
+ - 面板常量定义在 `src/constants/interactive-panel.ts`:
277
+ - `PANEL_REFRESH_INTERVAL_MS`(5000)、`PANEL_COUNTDOWN_INTERVAL_MS`(1000)
278
+ - `SELECTED_INDICATOR`(`▶`)、`UNSELECTED_INDICATOR`(等宽空格)
279
+ - `KEY_ARROW_UP`、`KEY_ARROW_DOWN`、`KEY_CTRL_C`
280
+ - `PANEL_SHORTCUT_KEYS`(快捷键映射对象)
281
+ - `PANEL_DATE_SEPARATOR_PREFIX`(`════`)
282
+ - `PANEL_FIXED_ROWS`(4,固定占用行数)
283
+ - 面板消息常量定义在 `src/constants/messages/interactive-panel.ts`:
284
+ - `PANEL_FOOTER_SHORTCUTS`:底栏快捷键提示(从 `PANEL_SHORTCUT_KEYS` 自动生成)
285
+ - `PANEL_FOOTER_COUNTDOWN(seconds)`:底栏倒计时文本
286
+ - `PANEL_OVERFLOW_DOWN_HINT` / `PANEL_OVERFLOW_UP_HINT`:溢出提示
287
+ - `PANEL_SNAPSHOT_SUMMARY(total, orphaned)`:快照摘要文本
288
+ - `PANEL_NO_WORKTREES`:无 worktree 提示
289
+ - `PANEL_PRESS_ENTER_TO_RETURN`:操作后返回提示
290
+ - `PANEL_NOT_TTY`:非 TTY 降级提示
291
+ - `PANEL_TITLE(projectName)`:面板标题
292
+ - `PanelLine` 接口(`src/utils/interactive-panel-render.ts`):面板行类型定义,包含 `type`(`'separator'` | `'worktree-content'`)、`text`、可选 `worktreeIndex`
293
+ - `collectStatus()` 函数已改为导出(`export`),以便 `InteractivePanel` 作为数据收集函数引用
294
+ - `handleStatus()` 改为 `async` 函数,返回 `Promise<void>`
295
+ - `StatusOptions` 类型新增 `interactive?: boolean` 字段
296
+ - 从 `src/utils/worktree-matcher.ts` 新导出 `formatRelativeDate()` 和 `getWorktreeCreatedDate()`,供面板渲染使用
297
+
155
298
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawt",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "本地并行执行多个Claude Code Agent任务,融合 Git Worktree 与 Claude Code CLI 的命令行工具",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,6 +21,7 @@ import {
21
21
  printInfo,
22
22
  printDoubleSeparator,
23
23
  printSeparator,
24
+ InteractivePanel,
24
25
  } from '../utils/index.js';
25
26
 
26
27
  /**
@@ -32,8 +33,9 @@ export function registerStatusCommand(program: Command): void {
32
33
  .command('status')
33
34
  .description('显示项目全局状态总览(支持 --json 格式输出)')
34
35
  .option('--json', '以 JSON 格式输出')
35
- .action((options: StatusOptions) => {
36
- handleStatus(options);
36
+ .option('-i, --interactive', '交互式面板模式')
37
+ .action(async (options: StatusOptions) => {
38
+ await handleStatus(options);
37
39
  });
38
40
  }
39
41
 
@@ -41,9 +43,16 @@ export function registerStatusCommand(program: Command): void {
41
43
  * 执行 status 命令的核心逻辑
42
44
  * @param {StatusOptions} options - 命令选项
43
45
  */
44
- function handleStatus(options: StatusOptions): void {
46
+ async function handleStatus(options: StatusOptions): Promise<void> {
45
47
  validateMainWorktree();
46
48
 
49
+ // 交互式面板模式
50
+ if (options.interactive) {
51
+ const panel = new InteractivePanel(collectStatus);
52
+ await panel.start();
53
+ return;
54
+ }
55
+
47
56
  const statusResult = collectStatus();
48
57
 
49
58
  logger.info(`status 命令执行,项目: ${statusResult.main.projectName},共 ${statusResult.totalWorktrees} 个 worktree`);
@@ -60,7 +69,7 @@ function handleStatus(options: StatusOptions): void {
60
69
  * 收集项目全局状态信息
61
70
  * @returns {StatusResult} 完整的状态数据
62
71
  */
63
- function collectStatus(): StatusResult {
72
+ export function collectStatus(): StatusResult {
64
73
  const projectName = getProjectName();
65
74
  const currentBranch = getCurrentBranch();
66
75
  const isClean = isWorkingDirClean();
@@ -30,3 +30,15 @@ export {
30
30
  CURSOR_HOME,
31
31
  } from './progress.js';
32
32
  export { SELECT_ALL_NAME, SELECT_ALL_LABEL, GROUP_SELECT_ALL_PREFIX, GROUP_SELECT_ALL_LABEL, GROUP_SEPARATOR_LABEL, UNKNOWN_DATE_GROUP, UNKNOWN_DATE_SEPARATOR_LABEL } from './prompt.js';
33
+ export {
34
+ PANEL_REFRESH_INTERVAL_MS,
35
+ PANEL_COUNTDOWN_INTERVAL_MS,
36
+ SELECTED_INDICATOR,
37
+ UNSELECTED_INDICATOR,
38
+ KEY_ARROW_UP,
39
+ KEY_ARROW_DOWN,
40
+ KEY_CTRL_C,
41
+ PANEL_SHORTCUT_KEYS,
42
+ PANEL_DATE_SEPARATOR_PREFIX,
43
+ PANEL_FIXED_ROWS,
44
+ } from './interactive-panel.js';
@@ -0,0 +1,44 @@
1
+ /** 自动刷新间隔(毫秒) */
2
+ export const PANEL_REFRESH_INTERVAL_MS = 5000;
3
+
4
+ /** 倒计时更新间隔(毫秒) */
5
+ export const PANEL_COUNTDOWN_INTERVAL_MS = 1000;
6
+
7
+ /** 选中指示器 */
8
+ export const SELECTED_INDICATOR = '▶';
9
+
10
+ /** 未选中占位(与选中指示器等宽) */
11
+ export const UNSELECTED_INDICATOR = ' ';
12
+
13
+ /** 方向键上的字节序列 */
14
+ export const KEY_ARROW_UP = '\x1b[A';
15
+
16
+ /** 方向键下的字节序列 */
17
+ export const KEY_ARROW_DOWN = '\x1b[B';
18
+
19
+ /** Ctrl+C 的字节值 */
20
+ export const KEY_CTRL_C = 0x03;
21
+
22
+ /** 面板快捷键映射 */
23
+ export const PANEL_SHORTCUT_KEYS = {
24
+ /** 验证 */
25
+ VALIDATE: 'v',
26
+ /** 合并 */
27
+ MERGE: 'm',
28
+ /** 删除 */
29
+ DELETE: 'd',
30
+ /** 恢复 */
31
+ RESUME: 'r',
32
+ /** 同步 */
33
+ SYNC: 's',
34
+ /** 手动刷新 */
35
+ REFRESH: 'f',
36
+ /** 退出 */
37
+ QUIT: 'q',
38
+ } as const;
39
+
40
+ /** 日期分隔线前缀 */
41
+ export const PANEL_DATE_SEPARATOR_PREFIX = '════';
42
+
43
+ /** 固定占用行数(顶部分隔线 + 快照摘要 + 底部分隔线 + 底栏) */
44
+ export const PANEL_FIXED_ROWS = 4;
@@ -14,9 +14,11 @@ import { PROJECTS_MESSAGES } from './projects.js';
14
14
  import { COMPLETION_MESSAGES } from './completion.js';
15
15
  import { UPDATE_MESSAGES, UPDATE_COMMANDS } from './update.js';
16
16
  import { INIT_MESSAGES } from './init.js';
17
+ import { PANEL_FOOTER_SHORTCUTS, PANEL_FOOTER_COUNTDOWN, PANEL_OVERFLOW_DOWN_HINT, PANEL_OVERFLOW_UP_HINT, PANEL_SNAPSHOT_SUMMARY, PANEL_NO_WORKTREES as PANEL_NO_WORKTREES_MSG, PANEL_PRESS_ENTER_TO_RETURN, PANEL_NOT_TTY, PANEL_TITLE } from './interactive-panel.js';
17
18
 
18
19
  export { CONFIG_ALIAS_DISABLED_HINT };
19
20
  export { UPDATE_MESSAGES, UPDATE_COMMANDS };
21
+ export { PANEL_FOOTER_SHORTCUTS, PANEL_FOOTER_COUNTDOWN, PANEL_OVERFLOW_DOWN_HINT, PANEL_OVERFLOW_UP_HINT, PANEL_SNAPSHOT_SUMMARY, PANEL_NO_WORKTREES_MSG, PANEL_PRESS_ENTER_TO_RETURN, PANEL_NOT_TTY, PANEL_TITLE };
20
22
 
21
23
  /**
22
24
  * 提示消息模板
@@ -0,0 +1,61 @@
1
+ import chalk from 'chalk';
2
+ import { PANEL_SHORTCUT_KEYS } from '../interactive-panel.js';
3
+
4
+ /** 快捷键标签映射(键名 → 中文标签) */
5
+ const SHORTCUT_LABELS: Record<keyof typeof PANEL_SHORTCUT_KEYS, string> = {
6
+ VALIDATE: '验证',
7
+ MERGE: '合并',
8
+ DELETE: '删除',
9
+ RESUME: '恢复',
10
+ SYNC: '同步',
11
+ REFRESH: '刷新',
12
+ QUIT: '退出',
13
+ };
14
+
15
+ /** 底栏快捷键提示文本(从 PANEL_SHORTCUT_KEYS 自动生成) */
16
+ export const PANEL_FOOTER_SHORTCUTS = Object.entries(SHORTCUT_LABELS)
17
+ .map(([key, label]) => `[${chalk.cyan(PANEL_SHORTCUT_KEYS[key as keyof typeof PANEL_SHORTCUT_KEYS])}]${label}`)
18
+ .join(' ');
19
+
20
+ /**
21
+ * 底栏倒计时文本
22
+ * @param {number} seconds - 剩余秒数
23
+ * @returns {string} 格式化的倒计时文本
24
+ */
25
+ export const PANEL_FOOTER_COUNTDOWN = (seconds: number): string => chalk.gray(`(${seconds}s 后刷新)`);
26
+
27
+ /** 向下溢出提示 */
28
+ export const PANEL_OVERFLOW_DOWN_HINT = chalk.gray('↓ 更多 worktree...');
29
+
30
+ /** 向上溢出提示 */
31
+ export const PANEL_OVERFLOW_UP_HINT = chalk.gray('↑ 更多 worktree...');
32
+
33
+ /**
34
+ * 快照摘要文本
35
+ * @param {number} total - 快照总数
36
+ * @param {number} orphaned - 孤立快照数
37
+ * @returns {string} 格式化的快照摘要
38
+ */
39
+ export const PANEL_SNAPSHOT_SUMMARY = (total: number, orphaned: number): string => {
40
+ const base = `快照: ${total} 个`;
41
+ if (orphaned > 0) {
42
+ return `${base}(${chalk.yellow(`${orphaned} 个孤立`)})`;
43
+ }
44
+ return base;
45
+ };
46
+
47
+ /** 无 worktree 提示 */
48
+ export const PANEL_NO_WORKTREES = '(无活跃 worktree)';
49
+
50
+ /** 操作后返回提示 */
51
+ export const PANEL_PRESS_ENTER_TO_RETURN = chalk.gray('\n按 Enter 返回面板...');
52
+
53
+ /** 非 TTY 降级提示 */
54
+ export const PANEL_NOT_TTY = '交互式面板需要 TTY 终端环境,请直接在终端中运行 clawt status -i';
55
+
56
+ /**
57
+ * 面板标题
58
+ * @param {string} projectName - 项目名
59
+ * @returns {string} 格式化的标题
60
+ */
61
+ export const PANEL_TITLE = (projectName: string): string => chalk.bold.cyan(`项目状态总览: ${projectName}`);
@@ -68,6 +68,8 @@ export interface ListOptions {
68
68
  export interface StatusOptions {
69
69
  /** 以 JSON 格式输出 */
70
70
  json?: boolean;
71
+ /** 交互式面板模式 */
72
+ interactive?: boolean;
71
73
  }
72
74
 
73
75
  /** projects 命令选项 */
@@ -58,7 +58,7 @@ export { ensureDir, removeEmptyDir, calculateDirSize } from './fs.js';
58
58
  export { multilineInput } from './prompt.js';
59
59
  export { launchInteractiveClaude, hasClaudeSessionHistory, launchInteractiveClaudeInNewTerminal } from './claude.js';
60
60
  export { getSnapshotPath, hasSnapshot, getSnapshotModifiedTime, readSnapshotTreeHash, readSnapshot, writeSnapshot, removeSnapshot, removeProjectSnapshots, getProjectSnapshotBranches } from './validate-snapshot.js';
61
- export { findExactMatch, findFuzzyMatches, promptSelectBranch, promptMultiSelectBranches, promptGroupedMultiSelectBranches, resolveTargetWorktree, resolveTargetWorktrees, groupWorktreesByDate, buildGroupedChoices, buildGroupMembershipMap } from './worktree-matcher.js';
61
+ export { findExactMatch, findFuzzyMatches, promptSelectBranch, promptMultiSelectBranches, promptGroupedMultiSelectBranches, resolveTargetWorktree, resolveTargetWorktrees, groupWorktreesByDate, buildGroupedChoices, buildGroupMembershipMap, formatRelativeDate, getWorktreeCreatedDate } from './worktree-matcher.js';
62
62
  export type { WorktreeResolveMessages, WorktreeMultiResolveMessages } from './worktree-matcher.js';
63
63
  export { ProgressRenderer } from './progress.js';
64
64
  export { parseTaskFile, loadTaskFile, parseTasksFromOptions } from './task-file.js';
@@ -73,4 +73,7 @@ export { checkForUpdates } from './update-checker.js';
73
73
  export { getProjectConfigPath, loadProjectConfig, saveProjectConfig, requireProjectConfig, getMainWorkBranch } from './project-config.js';
74
74
  export { getValidateBranchName, createValidateBranch, deleteValidateBranch, rebuildValidateBranch, ensureOnMainWorkBranch, handleDirtyWorkingDir } from './validate-branch.js';
75
75
  export { safeStringify } from './json.js';
76
+ export { InteractivePanel } from './interactive-panel.js';
77
+ export { buildPanelFrame, buildGroupedWorktreeLines, buildDisplayOrder, renderDateSeparator, renderWorktreeBlock, renderSnapshotSummary, renderFooter, calculateVisibleRows } from './interactive-panel-render.js';
78
+ export type { PanelLine } from './interactive-panel-render.js';
76
79