@cacinie/cace-timer 1.0.0 → 1.3.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.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +372 -220
  3. package/dist/commands/delete.d.ts +4 -0
  4. package/dist/commands/delete.js +48 -0
  5. package/dist/commands/export.d.ts +4 -0
  6. package/dist/commands/export.js +104 -0
  7. package/dist/commands/help.d.ts +1 -0
  8. package/dist/commands/help.js +73 -0
  9. package/dist/commands/list.d.ts +5 -0
  10. package/dist/commands/list.js +42 -0
  11. package/dist/commands/mark.d.ts +1 -0
  12. package/dist/commands/mark.js +27 -0
  13. package/dist/commands/pomodoro.d.ts +6 -0
  14. package/dist/commands/pomodoro.js +135 -0
  15. package/dist/commands/resume.d.ts +4 -0
  16. package/dist/commands/resume.js +54 -0
  17. package/dist/commands/search.d.ts +1 -0
  18. package/dist/commands/search.js +36 -0
  19. package/dist/commands/start.d.ts +4 -0
  20. package/dist/commands/start.js +47 -0
  21. package/dist/commands/status.d.ts +1 -0
  22. package/dist/commands/status.js +48 -0
  23. package/dist/commands/stop.d.ts +3 -0
  24. package/dist/commands/stop.js +104 -0
  25. package/dist/commands/summary.d.ts +6 -0
  26. package/dist/commands/summary.js +128 -0
  27. package/dist/commands/sync.d.ts +1 -0
  28. package/dist/commands/sync.js +62 -0
  29. package/dist/data.d.ts +18 -0
  30. package/dist/data.js +161 -0
  31. package/dist/i18n.d.ts +7 -0
  32. package/dist/i18n.js +418 -0
  33. package/dist/index.js +142 -492
  34. package/dist/mascot.d.ts +9 -0
  35. package/dist/mascot.js +200 -0
  36. package/dist/parser.d.ts +6 -0
  37. package/dist/parser.js +45 -0
  38. package/dist/tui/countdown.d.ts +8 -0
  39. package/dist/tui/countdown.js +135 -0
  40. package/dist/tui/dashboard.d.ts +2 -0
  41. package/dist/tui/dashboard.js +135 -0
  42. package/dist/tui/index.d.ts +2 -0
  43. package/dist/tui/index.js +8 -0
  44. package/dist/tui/lifecycle.d.ts +28 -0
  45. package/dist/tui/lifecycle.js +82 -0
  46. package/dist/tui/reflection.d.ts +5 -0
  47. package/dist/tui/reflection.js +71 -0
  48. package/dist/types.d.ts +24 -0
  49. package/dist/types.js +2 -0
  50. package/dist/utils.d.ts +5 -0
  51. package/dist/utils.js +44 -0
  52. package/package.json +39 -6
package/dist/index.js CHANGED
@@ -1,521 +1,171 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
3
  Object.defineProperty(exports, "__esModule", { value: true });
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
- const os = __importStar(require("os"));
40
- // ============ CACE TIMER Animation ============
41
- // 可爱短发小女孩头像
42
- const CACE_FRAMES = [
43
- // Frame 1: 正常
44
- `
45
- ▄▄▄▄▄▄▄▄▄▄▄▄
46
- █░░░░░░░░░░░░█
47
- █░▄▄▄▄▄▄▄▄▄░█
48
- █░│ ● ● │░█
49
- █░│ ▽ │░█
50
- █░│ ─── │░█
51
- ╰────────────╯
52
- `,
53
- // Frame 2: 眨眼
54
- `
55
- ▄▄▄▄▄▄▄▄▄▄▄▄
56
- █░░░░░░░░░░░░█
57
- █░▄▄▄▄▄▄▄▄▄░█
58
- █░│ ─ ─ │░█
59
- █░│ ▽ │░█
60
- █░│ ─── │░█
61
- ╰────────────╯
62
- `,
63
- // Frame 3: 开心
64
- `
65
- ▄▄▄▄▄▄▄▄▄▄▄▄
66
- █░░░░░░░░░░░░█
67
- █░▄▄▄▄▄▄▄▄▄░█
68
- █░│ ★ ★ │░█
69
- █░│ ▽ │░█
70
- █░│ ◡◡◡ │░█
71
- ╰────────────╯
72
- `,
73
- // Frame 4: 超开心
74
- `
75
- ▄▄▄▄▄▄▄▄▄▄▄▄
76
- █░░░░░░░░░░░░█
77
- █░▄▄▄▄▄▄▄▄▄░█
78
- █░│ ◉ ◉ │░█
79
- █░│ ▽ │░█
80
- █░│ ▽△▽ │░█
81
- ╰────────────╯
82
- `,
83
- ];
84
- const CACE_SMALL = `
85
- ▄▄▄▄▄▄▄▄▄▄
86
- █░░░░░░░░░░█
87
- █░▄▄▄▄▄▄▄░█
88
- █│ ● ● │
89
- █│ ▽ │
90
- █│ ─── │
91
- ╰─────────╯`;
92
- const CACE_HAPPY = `
93
- ▄▄▄▄▄▄▄▄▄▄
94
- █░░░░░░░░░░█
95
- █░▄▄▄▄▄▄▄░█
96
- █│ ★ ★ │
97
- █│ ▽ │
98
- █│ ◡◡◡ │
99
- ╰─────────╯`;
100
- const CACE_SLEEPY = `
101
- ▄▄▄▄▄▄▄▄▄▄
102
- █░░░░░░░░░░█
103
- █░▄▄▄▄▄▄▄░█
104
- █│ ─ ─ │
105
- █│ ▽ │
106
- █│ ─── │
107
- ╰─────────╯`;
108
- function getGreeting() {
109
- const hour = new Date().getHours();
110
- if (hour < 6)
111
- return '夜深了';
112
- if (hour < 12)
113
- return '早上好';
114
- if (hour < 18)
115
- return '下午好';
116
- return '晚上好';
117
- }
118
- async function showCaceAnimation(message = '') {
119
- const cyan = '\x1b[36m';
120
- const bold = '\x1b[1m';
121
- const reset = '\x1b[0m';
122
- // Animation loop
123
- for (let i = 0; i < 2; i++) {
124
- for (const frame of CACE_FRAMES) {
125
- console.clear();
126
- console.log(cyan + frame + reset);
127
- console.log();
128
- console.log(cyan + bold + ' ════════════════════════════════' + reset);
129
- console.log(cyan + bold + ' C A C E T I M E R' + reset);
130
- console.log(cyan + bold + ' ════════════════════════════════' + reset);
131
- if (message) {
132
- console.log();
133
- console.log(' ' + message);
134
- }
135
- await sleep(180);
136
- }
137
- }
138
- }
139
- function showCaceSmall(status = '', mood = 'normal') {
140
- const cyan = '\x1b[36m';
141
- const reset = '\x1b[0m';
142
- let face = CACE_SMALL;
143
- if (mood === 'happy')
144
- face = CACE_HAPPY;
145
- else if (mood === 'sleepy')
146
- face = CACE_SLEEPY;
147
- console.log(cyan + face + reset);
148
- if (status) {
149
- console.log(cyan + ' ' + status + reset);
150
- }
151
- }
152
- // ============ Utilities ============
153
- function sleep(ms) {
154
- return new Promise(resolve => setTimeout(resolve, ms));
155
- }
156
- function generateId() {
157
- return Date.now().toString(36) + Math.random().toString(36).substr(2);
158
- }
159
- function formatDuration(ms) {
160
- const seconds = Math.floor(ms / 1000);
161
- const minutes = Math.floor(seconds / 60);
162
- const hours = Math.floor(minutes / 60);
163
- if (hours > 0) {
164
- return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
165
- }
166
- else if (minutes > 0) {
167
- return `${minutes}m ${seconds % 60}s`;
168
- }
169
- else {
170
- return `${seconds}s`;
171
- }
172
- }
173
- function formatTime(isoString) {
174
- const date = new Date(isoString);
175
- return date.toLocaleString('zh-CN', {
176
- month: '2-digit',
177
- day: '2-digit',
178
- hour: '2-digit',
179
- minute: '2-digit'
180
- });
181
- }
182
- function formatDate(isoString) {
183
- const date = new Date(isoString);
184
- return date.toLocaleDateString('zh-CN');
185
- }
186
- // ============ Data Management ============
187
- const DATA_FILE = path.join(os.homedir(), '.cace-timer.json');
188
- function loadData() {
189
- try {
190
- if (fs.existsSync(DATA_FILE)) {
191
- const content = fs.readFileSync(DATA_FILE, 'utf-8');
192
- return JSON.parse(content);
193
- }
194
- }
195
- catch (e) {
196
- // Ignore errors
197
- }
198
- return { current: null, history: [] };
199
- }
200
- function saveData(data) {
201
- fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
202
- // Sync to external path if set
203
- if (data.syncPath && fs.existsSync(path.dirname(data.syncPath))) {
204
- fs.writeFileSync(data.syncPath, JSON.stringify(data, null, 2));
205
- }
206
- }
207
- // ============ Commands ============
208
- async function cmdStart(task, options) {
209
- const data = loadData();
210
- if (data.current) {
211
- console.log('\x1b[33m⚠ 已有进行中的任务,请先使用 tk stop 结束\x1b[0m');
212
- return;
213
- }
214
- const session = {
215
- id: generateId(),
216
- start: new Date().toISOString(),
217
- task: task || '未命名任务',
218
- tags: options.tag ? [options.tag] : [],
219
- marks: [],
220
- estimatedMinutes: options.estimate
221
- };
222
- data.current = session;
223
- saveData(data);
224
- await showCaceAnimation(`${getGreeting()}!开始记录: ${session.task}`);
225
- console.log();
226
- console.log(` 📌 任务: ${session.task}`);
227
- if (session.tags.length > 0) {
228
- console.log(` 🏷 标签: ${session.tags.join(', ')}`);
229
- }
230
- if (session.estimatedMinutes) {
231
- console.log(` ⏱ 预计: ${session.estimatedMinutes} 分钟`);
232
- }
233
- console.log(` 🕐 开始: ${formatTime(session.start)}`);
234
- console.log();
235
- }
236
- async function cmdMark(note) {
237
- const data = loadData();
238
- if (!data.current) {
239
- console.log('\x1b[33m⚠ 没有进行中的任务,请先用 tk start 开始\x1b[0m');
240
- return;
241
- }
242
- const mark = {
243
- time: new Date().toISOString(),
244
- note: note || '标记点'
245
- };
246
- data.current.marks.push(mark);
247
- saveData(data);
248
- const elapsed = Date.now() - new Date(data.current.start).getTime();
249
- console.log();
250
- showCaceSmall('✓ 已标记', 'happy');
251
- console.log();
252
- console.log(` 📍 ${formatTime(mark.time)} - ${mark.note}`);
253
- console.log(` ⏱ 已用时: ${formatDuration(elapsed)}`);
254
- console.log();
255
- }
256
- async function cmdStop() {
257
- const data = loadData();
258
- if (!data.current) {
259
- console.log('\x1b[33m⚠ 没有进行中的任务\x1b[0m');
260
- return;
261
- }
262
- const session = data.current;
263
- session.end = new Date().toISOString();
264
- const duration = new Date(session.end).getTime() - new Date(session.start).getTime();
265
- const durationMinutes = duration / 60000;
266
- // Calculate efficiency score
267
- let efficiency = 100;
268
- if (session.estimatedMinutes && session.estimatedMinutes > 0) {
269
- efficiency = Math.min(100, Math.round((session.estimatedMinutes / durationMinutes) * 100));
270
- }
271
- data.history.unshift(session);
272
- data.current = null;
273
- saveData(data);
274
- console.log();
275
- showCaceSmall('任务完成!', 'happy');
276
- console.log();
277
- console.log(' ┌─────────────────────────────────┐');
278
- console.log(' │ 📊 任务总结 │');
279
- console.log(' └─────────────────────────────────┘');
280
- console.log();
281
- console.log(` 📌 任务: ${session.task}`);
282
- console.log(` 🕐 时长: ${formatDuration(duration)}`);
283
- if (session.tags.length > 0) {
284
- console.log(` 🏷 标签: ${session.tags.join(', ')}`);
285
- }
286
- if (session.marks.length > 0) {
287
- console.log(` 📍 标记: ${session.marks.length} 个`);
288
- }
289
- // Efficiency display
290
- let effEmoji = '⭐';
291
- let effColor = '\x1b[32m';
292
- if (efficiency < 50) {
293
- effEmoji = '💀';
294
- effColor = '\x1b[31m';
295
- }
296
- else if (efficiency < 80) {
297
- effEmoji = '💪';
298
- effColor = '\x1b[33m';
299
- }
300
- else if (efficiency >= 100) {
301
- effEmoji = '🏆';
302
- }
303
- console.log(` ${effEmoji} 效率分: ${effColor}${efficiency}%\x1b[0m`);
304
- console.log();
305
- }
306
- function cmdStatus() {
307
- const data = loadData();
308
- console.log();
309
- showCaceSmall('', data.current ? 'normal' : 'sleepy');
310
- if (!data.current) {
311
- console.log();
312
- console.log(' 😴 当前没有进行中的任务');
313
- console.log(' 使用 tk start "任务名" 开始新任务');
314
- console.log();
315
- return;
316
- }
317
- const elapsed = Date.now() - new Date(data.current.start).getTime();
318
- console.log();
319
- console.log(' 🔥 进行中');
320
- console.log();
321
- console.log(` 📌 任务: ${data.current.task}`);
322
- console.log(` 🕐 开始: ${formatTime(data.current.start)}`);
323
- console.log(` ⏱ 已用: ${formatDuration(elapsed)}`);
324
- if (data.current.tags.length > 0) {
325
- console.log(` 🏷 标签: ${data.current.tags.join(', ')}`);
326
- }
327
- if (data.current.marks.length > 0) {
328
- console.log(` 📍 标记: ${data.current.marks.length} 个`);
329
- data.current.marks.forEach((m, i) => {
330
- console.log(` ${i + 1}. ${formatTime(m.time)} - ${m.note}`);
331
- });
332
- }
333
- console.log();
334
- }
335
- function cmdList(options) {
336
- const data = loadData();
337
- let sessions = data.history;
338
- // Filter by today
339
- if (options.today) {
340
- const today = formatDate(new Date().toISOString());
341
- sessions = sessions.filter(s => formatDate(s.start) === today);
342
- }
343
- // Filter by tag
344
- if (options.tag) {
345
- sessions = sessions.filter(s => s.tags.includes(options.tag));
346
- }
347
- // Limit
348
- const limit = options.limit || 10;
349
- sessions = sessions.slice(0, limit);
350
- console.log();
351
- showCaceSmall('历史记录');
352
- console.log();
353
- if (sessions.length === 0) {
354
- console.log(' 📭 暂无记录');
355
- console.log();
356
- return;
357
- }
358
- sessions.forEach((session, i) => {
359
- const duration = session.end
360
- ? formatDuration(new Date(session.end).getTime() - new Date(session.start).getTime())
361
- : '进行中';
362
- console.log(` ${i + 1}. ${session.task}`);
363
- console.log(` 📅 ${formatTime(session.start)} | ⏱ ${duration}`);
364
- if (session.tags.length > 0) {
365
- console.log(` 🏷 ${session.tags.map(t => '#' + t).join(' ')}`);
366
- }
367
- console.log();
368
- });
369
- }
370
- function cmdSearch(keyword) {
371
- const data = loadData();
372
- const results = data.history.filter(s => s.task.toLowerCase().includes(keyword.toLowerCase()) ||
373
- s.tags.some(t => t.toLowerCase().includes(keyword.toLowerCase())) ||
374
- s.marks.some(m => m.note.toLowerCase().includes(keyword.toLowerCase())));
375
- console.log();
376
- showCaceSmall(`搜索: "${keyword}"`);
377
- console.log();
378
- if (results.length === 0) {
379
- console.log(' 🔍 未找到匹配记录');
380
- console.log();
381
- return;
382
- }
383
- console.log(` 找到 ${results.length} 条记录:\n`);
384
- results.forEach((session, i) => {
385
- const duration = session.end
386
- ? formatDuration(new Date(session.end).getTime() - new Date(session.start).getTime())
387
- : '进行中';
388
- console.log(` ${i + 1}. ${session.task}`);
389
- console.log(` 📅 ${formatTime(session.start)} | ⏱ ${duration}`);
390
- console.log();
391
- });
392
- }
393
- function cmdSync(filePath) {
394
- const data = loadData();
395
- const absPath = path.resolve(filePath);
396
- data.syncPath = absPath;
397
- saveData(data);
398
- console.log();
399
- showCaceSmall('同步已配置');
400
- console.log();
401
- console.log(` 📂 同步路径: ${absPath}`);
402
- console.log(' 💡 提示: 可将文件放在 Dropbox/iCloud/OneDrive 等同步目录');
403
- console.log();
404
- }
405
- function cmdHelp() {
406
- console.log();
407
- showCaceSmall('');
408
- console.log();
409
- console.log(' ╔═══════════════════════════════════════════╗');
410
- console.log(' ║ CACE TIMER - 命令帮助 ║');
411
- console.log(' ╚═══════════════════════════════════════════╝');
412
- console.log();
413
- console.log(' tk start <任务名> [选项]');
414
- console.log(' 开始新任务');
415
- console.log(' --tag <标签> 添加标签');
416
- console.log(' --estimate <分钟> 预估时长');
417
- console.log();
418
- console.log(' tk mark <备注>');
419
- console.log(' 记录时间点');
420
- console.log();
421
- console.log(' tk stop');
422
- console.log(' 结束当前任务(显示效率评分)');
423
- console.log();
424
- console.log(' tk status');
425
- console.log(' 查看当前状态');
426
- console.log();
427
- console.log(' tk list [选项]');
428
- console.log(' 查看历史记录');
429
- console.log(' --today 仅今天');
430
- console.log(' --tag <标签> 按标签筛选');
431
- console.log(' --limit <数量> 限制数量');
432
- console.log();
433
- console.log(' tk search <关键词>');
434
- console.log(' 搜索记录');
435
- console.log();
436
- console.log(' tk sync <文件路径>');
437
- console.log(' 设置同步文件路径');
438
- console.log();
439
- console.log(' tk help');
440
- console.log(' 显示帮助');
441
- console.log();
442
- }
443
- function parseArgs(args) {
444
- const result = {
445
- command: '',
446
- positional: [],
447
- options: {}
448
- };
449
- let i = 0;
450
- while (i < args.length) {
451
- const arg = args[i];
452
- if (arg.startsWith('--')) {
453
- const key = arg.slice(2);
454
- const nextArg = args[i + 1];
455
- if (nextArg && !nextArg.startsWith('-')) {
456
- result.options[key] = nextArg;
457
- i += 2;
458
- }
459
- else {
460
- result.options[key] = true;
461
- i++;
462
- }
463
- }
464
- else if (!result.command) {
465
- result.command = arg;
466
- i++;
467
- }
468
- else {
469
- result.positional.push(arg);
470
- i++;
471
- }
472
- }
473
- return result;
474
- }
475
- // ============ Main ============
476
- async function main() {
477
- const args = process.argv.slice(2);
478
- const parsed = parseArgs(args);
479
- const { command, positional, options } = parsed;
4
+ const tui_1 = require("./tui");
5
+ const dashboard_1 = require("./tui/dashboard");
6
+ const parser_1 = require("./parser");
7
+ const data_1 = require("./data");
8
+ const i18n_1 = require("./i18n");
9
+ const start_1 = require("./commands/start");
10
+ const mark_1 = require("./commands/mark");
11
+ const stop_1 = require("./commands/stop");
12
+ const status_1 = require("./commands/status");
13
+ const list_1 = require("./commands/list");
14
+ const search_1 = require("./commands/search");
15
+ const sync_1 = require("./commands/sync");
16
+ const help_1 = require("./commands/help");
17
+ const summary_1 = require("./commands/summary");
18
+ const delete_1 = require("./commands/delete");
19
+ const resume_1 = require("./commands/resume");
20
+ const export_1 = require("./commands/export");
21
+ const pomodoro_1 = require("./commands/pomodoro");
22
+ // ============ Safe parseInt ============
23
+ function safeInt(val, fallback) {
24
+ if (typeof val !== 'string')
25
+ return fallback;
26
+ const n = parseInt(val);
27
+ return isNaN(n) || n <= 0 ? fallback : n;
28
+ }
29
+ function safeString(val) {
30
+ return typeof val === 'string' ? val : undefined;
31
+ }
32
+ // ============ Command Router ============
33
+ async function runCommand(command, positional, options) {
480
34
  switch (command) {
481
35
  case 'start':
482
- await cmdStart(positional[0] || '', {
36
+ await (0, start_1.cmdStart)(positional[0] || '', {
483
37
  tag: options.tag,
484
- estimate: options.estimate ? parseInt(options.estimate) : undefined
38
+ estimate: safeInt(options.estimate, 0) || undefined,
485
39
  });
486
40
  break;
487
41
  case 'mark':
488
- await cmdMark(positional[0] || '标记点');
42
+ await (0, mark_1.cmdMark)(positional[0] || (0, i18n_1.t)('cmd.mark.markPoint'));
489
43
  break;
490
44
  case 'stop':
491
- await cmdStop();
45
+ await (0, stop_1.cmdStop)({ reflection: safeString(options.reflection) });
492
46
  break;
493
47
  case 'status':
494
- cmdStatus();
48
+ (0, status_1.cmdStatus)();
495
49
  break;
496
50
  case 'list':
497
51
  case 'ls':
498
- cmdList({
52
+ (0, list_1.cmdList)({
499
53
  today: !!options.today,
500
- tag: options.tag,
501
- limit: options.limit ? parseInt(options.limit) : 10
54
+ tag: safeString(options.tag),
55
+ limit: options.limit ? safeInt(options.limit, 10) : 10,
502
56
  });
503
57
  break;
504
58
  case 'search':
505
- cmdSearch(positional[0] || '');
59
+ (0, search_1.cmdSearch)(positional[0] || '');
506
60
  break;
507
61
  case 'sync':
508
- cmdSync(positional[0] || '');
62
+ (0, sync_1.cmdSync)(positional[0] || '');
63
+ break;
64
+ case 'summary':
65
+ (0, summary_1.cmdSummary)({
66
+ today: !!options.today,
67
+ week: !!options.week,
68
+ month: !!options.month,
69
+ tag: safeString(options.tag),
70
+ });
71
+ break;
72
+ case 'delete':
73
+ (0, delete_1.cmdDelete)({
74
+ id: positional[0] && !positional[0].startsWith('--') ? positional[0] : undefined,
75
+ last: !!options.last,
76
+ });
77
+ break;
78
+ case 'resume':
79
+ await (0, resume_1.cmdResume)({
80
+ id: positional[0] && !positional[0].startsWith('--') ? positional[0] : undefined,
81
+ last: !!options.last,
82
+ });
83
+ break;
84
+ case 'export':
85
+ (0, export_1.cmdExport)({ format: safeString(options.format), output: safeString(options.output) });
86
+ break;
87
+ case 'pomodoro':
88
+ await (0, pomodoro_1.cmdPomodoro)(positional[0] || '', {
89
+ work: options.work ? safeInt(options.work, 25) : undefined,
90
+ break: options.break ? safeInt(options.break, 5) : undefined,
91
+ rounds: options.rounds ? safeInt(options.rounds, 4) : undefined,
92
+ tag: options.tag,
93
+ });
94
+ break;
95
+ case 'focus': {
96
+ const minutes = positional[0] ? safeInt(positional[0], 25) : 25;
97
+ const focusTask = positional.slice(1).join(' ') || (0, i18n_1.t)('cmd.focus.alias');
98
+ await (0, pomodoro_1.cmdPomodoro)(focusTask, {
99
+ work: minutes,
100
+ break: 5,
101
+ rounds: 1,
102
+ tag: options.tag,
103
+ });
509
104
  break;
105
+ }
510
106
  case 'help':
511
- case '--help':
512
- case '-h':
513
- case '':
514
- cmdHelp();
107
+ (0, help_1.cmdHelp)();
515
108
  break;
516
109
  default:
517
- console.log(`\x1b[31m未知命令: ${command}\x1b[0m`);
518
- console.log('使用 tk help 查看帮助');
110
+ console.log(`\x1b[31m${(0, i18n_1.t)('error.unknownCommand', { command })}\x1b[0m`);
111
+ console.log((0, i18n_1.t)('error.useHelp'));
112
+ }
113
+ }
114
+ // ============ Dashboard action handler ============
115
+ async function runDashboardAction(action) {
116
+ switch (action) {
117
+ case 'start': {
118
+ // For dashboard start, use a generic task - user can specify more via CLI
119
+ await (0, start_1.cmdStart)('', { tag: undefined, estimate: undefined });
120
+ break;
121
+ }
122
+ case 'focus': {
123
+ await (0, pomodoro_1.cmdPomodoro)((0, i18n_1.t)('cmd.focus.alias'), { work: 25, break: 5, rounds: 1, tag: undefined });
124
+ break;
125
+ }
126
+ case 'mark':
127
+ await (0, mark_1.cmdMark)((0, i18n_1.t)('cmd.mark.markPoint'));
128
+ break;
129
+ case 'stop':
130
+ await (0, stop_1.cmdStop)();
131
+ break;
132
+ case 'summary':
133
+ (0, summary_1.cmdSummary)({ today: true });
134
+ break;
135
+ case 'list':
136
+ (0, list_1.cmdList)({ today: true });
137
+ break;
138
+ case 'help':
139
+ (0, help_1.cmdHelp)();
140
+ break;
141
+ case 'quit':
142
+ break;
143
+ }
144
+ }
145
+ // ============ Main ============
146
+ async function main() {
147
+ const args = process.argv.slice(2);
148
+ const parsed = (0, parser_1.parseArgs)(args);
149
+ const { command, positional, options } = parsed;
150
+ // Resolve locale before any command runs
151
+ const storedData = (0, data_1.loadData)();
152
+ const locale = (0, i18n_1.resolveLocale)(options.lang, storedData.lang);
153
+ (0, i18n_1.setLocale)(locale);
154
+ // Persist language preference if --lang was explicitly given
155
+ if (options.lang) {
156
+ storedData.lang = locale;
157
+ (0, data_1.saveData)(storedData);
158
+ }
159
+ // No command → dashboard (interactive) or help (non-interactive)
160
+ if (command === '' || command === '--help' || command === '-h') {
161
+ if (command === '' && (0, tui_1.isInteractiveTerminal)()) {
162
+ const action = await (0, dashboard_1.showDashboard)();
163
+ await runDashboardAction(action);
164
+ return;
165
+ }
166
+ (0, help_1.cmdHelp)();
167
+ return;
519
168
  }
169
+ await runCommand(command, positional, parsed.options);
520
170
  }
521
171
  main().catch(console.error);
@@ -0,0 +1,9 @@
1
+ export declare const CACE_SMALL = "\n \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\n \u2502 \u25CF \u25CF \u2502\n \u2502 \u25BD \u2502\n \u2502 \u2500\u2500\u2500 \u2502\n \u2570\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u256F\n \u256D\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u256E\n \u2502 \u2554\u2550\u2550\u2550\u2550\u2557 \u2502\n \u2502 \u2551 CACE\u2551 \u2502\n \u2502 \u255A\u2550\u2550\u2550\u2550\u255D \u2502\n \u2570\u2500\u2500\u2500\u2500\u252C\u252C\u2500\u2500\u2500\u2500\u256F\n \u256D\u2500\u2500\u2518\u2514\u2500\u2500\u256E\n \u2502 \u2502\n \u2570\u2500\u2500\u252C\u252C\u2500\u2500\u256F\n \u256D\u2518\u2514\u256E";
2
+ export declare const CACE_HAPPY = "\n \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\n \u2502 \u2605 \u2605 \u2502\n \u2502 \u25BD \u2502\n \u2502 \u25E1\u25E1\u25E1 \u2502\n \u2570\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u256F\n \u256D\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u256E\n \u2502 \u2554\u2550\u2550\u2550\u2550\u2557 \u2502\n \u2502 \u2551 CACE\u2551 \u2502\n \u2502 \u255A\u2550\u2550\u2550\u2550\u255D \u2502\n \u2570\u2500\u2500\u2500\u2500\u252C\u252C\u2500\u2500\u2500\u2500\u256F\n \u256D\u2500\u2500\u2500\u2518\u2514\u2500\u2500\u2500\u256E\n \u2502 \u2502\n \u2570\u2500\u2500\u2500\u252C\u252C\u2500\u2500\u2500\u256F\n \u256D\u2518\u2514\u256E";
3
+ export declare const CACE_SLEEPY = "\n \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\n \u2502 \u2500 \u2500 \u2502\n \u2502 \u25BD \u2502\n \u2502 \uFF5E\uFF5E \u2502\n \u2570\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u256F\n \u256D\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u256E\n \u2502 \u2554\u2550\u2550\u2550\u2550\u2557 \u2502\n \u2502 \u2551CACE\u2551 \u2502\n \u2502 \u255A\u2550\u2550\u2550\u2550\u255D \u2502\n \u2570\u2500\u2500\u2500\u2500\u252C\u252C\u2500\u2500\u2500\u2500\u256F\n \u256D\u2500\u2500\u2518\u2514\u2500\u2500\u256E\n \u2502 \u2502\n \u2570\u2500\u2500\u252C\u252C\u2500\u2500\u256F\n \u256D\u2518\u2514\u256E";
4
+ export declare const CACE_FOCUSED = "\n \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\n \u2502 \u25C6 \u25C6 \u2502\n \u2502 \u25BD \u2502\n \u2502 \u25AC\u25AC\u25AC \u2502\n \u2570\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u256F\n \u256D\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u256E\n \u2502 \u2554\u2550\u2550\u2550\u2550\u2557 \u2502\n \u2502 \u2551CACE\u2551 \u2502\n \u2502 \u255A\u2550\u2550\u2550\u2550\u255D \u2502\n \u2570\u2500\u2500\u2500\u2500\u252C\u252C\u2500\u2500\u2500\u2500\u256F\n \u256D\u2500\u2500\u2518\u2514\u2500\u2500\u256E\n \u2502 \u2502\u2502 \u2502\n \u2570\u2500\u2500\u252C\u252C\u2500\u2500\u256F\n \u256D\u2518\u2514\u256E";
5
+ export declare const CACE_CELEBRATING = "\n \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E\n \u2502 \u25C9 \u25C9 \u2502\n \u2502 \u25BD \u2502\n \u2502 \u25BD\u25B3\u25BD \u2502\n \u2570\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u256F\n \u256D\u2500\u2500\u256E\u2500\u2534\u2500\u2500\u2500\u2500\u2534\u2500\u256E\u2500\u2500\u256E\n \u2502\uD83C\uDF8A \u2554\u2550\u2550\u2550\u2550\u2557 \u2502\uD83C\uDF8A\n \u2502 \u2551CACE\u2551 \u2502\n \u2570\u2500\u2500\u256E \u255A\u2550\u2550\u2550\u2550\u255D \u256D\u2500\u2500\u256F\n \u2570\u2500\u2500\u2500\u2500\u252C\u252C\u2500\u2500\u2500\u256F\n \u256D\u2500\u2500\u2500\u2518\u2514\u2500\u2500\u2500\u256E\n \u2502 \u266A \u2502\n \u2570\u2500\u2500\u2500\u252C\u252C\u2500\u2500\u2500\u256F\n \u256D\u2518\u2514\u256E";
6
+ export type CaceMood = 'normal' | 'happy' | 'sleepy' | 'focused' | 'celebrating';
7
+ export declare function getGreeting(): string;
8
+ export declare function showCaceAnimation(message?: string): Promise<void>;
9
+ export declare function showCaceSmall(status?: string, mood?: CaceMood): void;