@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.
- package/LICENSE +21 -0
- package/README.md +372 -220
- package/dist/commands/delete.d.ts +4 -0
- package/dist/commands/delete.js +48 -0
- package/dist/commands/export.d.ts +4 -0
- package/dist/commands/export.js +104 -0
- package/dist/commands/help.d.ts +1 -0
- package/dist/commands/help.js +73 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.js +42 -0
- package/dist/commands/mark.d.ts +1 -0
- package/dist/commands/mark.js +27 -0
- package/dist/commands/pomodoro.d.ts +6 -0
- package/dist/commands/pomodoro.js +135 -0
- package/dist/commands/resume.d.ts +4 -0
- package/dist/commands/resume.js +54 -0
- package/dist/commands/search.d.ts +1 -0
- package/dist/commands/search.js +36 -0
- package/dist/commands/start.d.ts +4 -0
- package/dist/commands/start.js +47 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +48 -0
- package/dist/commands/stop.d.ts +3 -0
- package/dist/commands/stop.js +104 -0
- package/dist/commands/summary.d.ts +6 -0
- package/dist/commands/summary.js +128 -0
- package/dist/commands/sync.d.ts +1 -0
- package/dist/commands/sync.js +62 -0
- package/dist/data.d.ts +18 -0
- package/dist/data.js +161 -0
- package/dist/i18n.d.ts +7 -0
- package/dist/i18n.js +418 -0
- package/dist/index.js +142 -492
- package/dist/mascot.d.ts +9 -0
- package/dist/mascot.js +200 -0
- package/dist/parser.d.ts +6 -0
- package/dist/parser.js +45 -0
- package/dist/tui/countdown.d.ts +8 -0
- package/dist/tui/countdown.js +135 -0
- package/dist/tui/dashboard.d.ts +2 -0
- package/dist/tui/dashboard.js +135 -0
- package/dist/tui/index.d.ts +2 -0
- package/dist/tui/index.js +8 -0
- package/dist/tui/lifecycle.d.ts +28 -0
- package/dist/tui/lifecycle.js +82 -0
- package/dist/tui/reflection.d.ts +5 -0
- package/dist/tui/reflection.js +71 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +44 -0
- 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
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
|
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 ?
|
|
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
|
-
|
|
512
|
-
case '-h':
|
|
513
|
-
case '':
|
|
514
|
-
cmdHelp();
|
|
107
|
+
(0, help_1.cmdHelp)();
|
|
515
108
|
break;
|
|
516
109
|
default:
|
|
517
|
-
console.log(`\x1b[31m
|
|
518
|
-
console.log(
|
|
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);
|
package/dist/mascot.d.ts
ADDED
|
@@ -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;
|