@cacinie/cace-timer 1.1.1 → 1.3.2

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 -21
  2. package/README.md +491 -192
  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 -498
  34. package/dist/mascot.d.ts +9 -0
  35. package/dist/mascot.js +257 -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 +20 -4
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdDelete = cmdDelete;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const i18n_1 = require("../i18n");
7
+ function cmdDelete(options) {
8
+ const data = (0, data_1.loadData)();
9
+ if (data.history.length === 0) {
10
+ console.log();
11
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.delete.noHistory'), 'sleepy');
12
+ console.log();
13
+ return;
14
+ }
15
+ if (options.last) {
16
+ const removed = data.history.shift();
17
+ (0, data_1.saveData)(data);
18
+ console.log();
19
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.delete.deletedLast', { task: removed.task }), 'normal');
20
+ console.log();
21
+ console.log(` 📌 ${(0, i18n_1.t)('common.task')}: ${removed.task}`);
22
+ console.log(` 🆔 ${(0, i18n_1.t)('common.id')}: ${removed.id}`);
23
+ console.log();
24
+ return;
25
+ }
26
+ if (options.id) {
27
+ const idx = data.history.findIndex(s => s.id === options.id);
28
+ if (idx === -1) {
29
+ console.log();
30
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.delete.notFound'), 'sleepy');
31
+ console.log();
32
+ return;
33
+ }
34
+ const removed = data.history.splice(idx, 1)[0];
35
+ (0, data_1.saveData)(data);
36
+ console.log();
37
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.delete.deleted', { task: removed.task }), 'normal');
38
+ console.log();
39
+ console.log(` 📌 ${(0, i18n_1.t)('common.task')}: ${removed.task}`);
40
+ console.log(` 🆔 ${(0, i18n_1.t)('common.id')}: ${removed.id}`);
41
+ console.log();
42
+ return;
43
+ }
44
+ // No valid option specified
45
+ console.log();
46
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.delete.specify'), 'sleepy');
47
+ console.log();
48
+ }
@@ -0,0 +1,4 @@
1
+ export declare function cmdExport(options: {
2
+ format?: string;
3
+ output?: string;
4
+ }): void;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.cmdExport = cmdExport;
37
+ const fs = __importStar(require("fs"));
38
+ const data_1 = require("../data");
39
+ const mascot_1 = require("../mascot");
40
+ const utils_1 = require("../utils");
41
+ const i18n_1 = require("../i18n");
42
+ function cmdExport(options) {
43
+ const data = (0, data_1.loadData)();
44
+ const sessions = data.history;
45
+ if (sessions.length === 0) {
46
+ console.log();
47
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.export.noData'), 'sleepy');
48
+ console.log();
49
+ return;
50
+ }
51
+ const fmt = options.format || 'csv';
52
+ let output;
53
+ if (fmt === 'markdown' || fmt === 'md') {
54
+ output = toMarkdown(sessions);
55
+ }
56
+ else if (fmt === 'csv') {
57
+ output = toCsv(sessions);
58
+ }
59
+ else {
60
+ console.log(`\x1b[33m${(0, i18n_1.t)('cmd.export.unsupportedFormat')}\x1b[0m`);
61
+ return;
62
+ }
63
+ if (options.output) {
64
+ fs.writeFileSync(options.output, output, 'utf-8');
65
+ console.log();
66
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.export.exportedTo', { path: options.output }), 'happy');
67
+ console.log();
68
+ }
69
+ else {
70
+ process.stdout.write(output);
71
+ }
72
+ }
73
+ function toCsv(sessions) {
74
+ const header = 'ID,Task,Start,End,Duration,Tags,Marks\n';
75
+ const rows = sessions
76
+ .map(s => {
77
+ const duration = s.end
78
+ ? (0, utils_1.formatDuration)(new Date(s.end).getTime() - new Date(s.start).getTime())
79
+ : 'running';
80
+ return [
81
+ s.id,
82
+ `"${s.task.replace(/"/g, '""')}"`,
83
+ s.start,
84
+ s.end || '',
85
+ duration,
86
+ s.tags.join(';'),
87
+ s.marks.length.toString(),
88
+ ].join(',');
89
+ })
90
+ .join('\n');
91
+ return header + rows + '\n';
92
+ }
93
+ function toMarkdown(sessions) {
94
+ let md = `| # | ${(0, i18n_1.t)('common.task')} | ${(0, i18n_1.t)('common.start')} | ${(0, i18n_1.t)('common.duration')} | ${(0, i18n_1.t)('common.tags')} |\n`;
95
+ md += '|---|------|-------|----------|------|\n';
96
+ sessions.forEach((s, i) => {
97
+ const duration = s.end
98
+ ? (0, utils_1.formatDuration)(new Date(s.end).getTime() - new Date(s.start).getTime())
99
+ : (0, i18n_1.t)('common.running');
100
+ const tags = s.tags.map(tg => '#' + tg).join(' ');
101
+ md += `| ${i + 1} | ${s.task} | ${(0, utils_1.formatTime)(s.start)} | ${duration} | ${tags} |\n`;
102
+ });
103
+ return md;
104
+ }
@@ -0,0 +1 @@
1
+ export declare function cmdHelp(): void;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdHelp = cmdHelp;
4
+ const mascot_1 = require("../mascot");
5
+ const i18n_1 = require("../i18n");
6
+ function cmdHelp() {
7
+ console.log();
8
+ (0, mascot_1.showCaceSmall)('');
9
+ console.log();
10
+ console.log(' ╔═══════════════════════════════════════════╗');
11
+ console.log(` ║ ${(0, i18n_1.t)('cmd.help.title')} ║`);
12
+ console.log(' ╚═══════════════════════════════════════════╝');
13
+ console.log();
14
+ console.log(` ${(0, i18n_1.t)('cmd.help.start')}`);
15
+ console.log(` ${(0, i18n_1.t)('cmd.help.startDesc')}`);
16
+ console.log(` ${(0, i18n_1.t)('cmd.help.startTag')}`);
17
+ console.log(` ${(0, i18n_1.t)('cmd.help.startEstimate')}`);
18
+ console.log();
19
+ console.log(` ${(0, i18n_1.t)('cmd.help.mark')}`);
20
+ console.log(` ${(0, i18n_1.t)('cmd.help.markDesc')}`);
21
+ console.log();
22
+ console.log(` ${(0, i18n_1.t)('cmd.help.stop')}`);
23
+ console.log(` ${(0, i18n_1.t)('cmd.help.stopDesc')}`);
24
+ console.log();
25
+ console.log(` ${(0, i18n_1.t)('cmd.help.status')}`);
26
+ console.log(` ${(0, i18n_1.t)('cmd.help.statusDesc')}`);
27
+ console.log();
28
+ console.log(` ${(0, i18n_1.t)('cmd.help.list')}`);
29
+ console.log(` ${(0, i18n_1.t)('cmd.help.listDesc')}`);
30
+ console.log(` ${(0, i18n_1.t)('cmd.help.listToday')}`);
31
+ console.log(` ${(0, i18n_1.t)('cmd.help.listTag')}`);
32
+ console.log(` ${(0, i18n_1.t)('cmd.help.listLimit')}`);
33
+ console.log();
34
+ console.log(` ${(0, i18n_1.t)('cmd.help.search')}`);
35
+ console.log(` ${(0, i18n_1.t)('cmd.help.searchDesc')}`);
36
+ console.log();
37
+ console.log(` ${(0, i18n_1.t)('cmd.help.sync')}`);
38
+ console.log(` ${(0, i18n_1.t)('cmd.help.syncDesc')}`);
39
+ console.log();
40
+ console.log(` ${(0, i18n_1.t)('cmd.help.summary')}`);
41
+ console.log(` ${(0, i18n_1.t)('cmd.help.summaryDesc')}`);
42
+ console.log(` ${(0, i18n_1.t)('cmd.help.summaryToday')}`);
43
+ console.log(` ${(0, i18n_1.t)('cmd.help.summaryWeek')}`);
44
+ console.log(` ${(0, i18n_1.t)('cmd.help.summaryMonth')}`);
45
+ console.log(` ${(0, i18n_1.t)('cmd.help.summaryTag')}`);
46
+ console.log();
47
+ console.log(` ${(0, i18n_1.t)('cmd.help.delete')}`);
48
+ console.log(` ${(0, i18n_1.t)('cmd.help.deleteDesc')}`);
49
+ console.log();
50
+ console.log(` ${(0, i18n_1.t)('cmd.help.resume')}`);
51
+ console.log(` ${(0, i18n_1.t)('cmd.help.resumeDesc')}`);
52
+ console.log();
53
+ console.log(` ${(0, i18n_1.t)('cmd.help.export')}`);
54
+ console.log(` ${(0, i18n_1.t)('cmd.help.exportDesc')}`);
55
+ console.log(` ${(0, i18n_1.t)('cmd.help.exportFormat')}`);
56
+ console.log(` ${(0, i18n_1.t)('cmd.help.exportOutput')}`);
57
+ console.log();
58
+ console.log(` ${(0, i18n_1.t)('cmd.help.pomodoro')}`);
59
+ console.log(` ${(0, i18n_1.t)('cmd.help.pomodoroDesc')}`);
60
+ console.log(` ${(0, i18n_1.t)('cmd.help.pomodoroWork')}`);
61
+ console.log(` ${(0, i18n_1.t)('cmd.help.pomodoroBreak')}`);
62
+ console.log(` ${(0, i18n_1.t)('cmd.help.pomodoroRounds')}`);
63
+ console.log(` ${(0, i18n_1.t)('cmd.help.pomodoroTag')}`);
64
+ console.log();
65
+ console.log(` ${(0, i18n_1.t)('cmd.help.focus')}`);
66
+ console.log(` ${(0, i18n_1.t)('cmd.help.focusDesc')}`);
67
+ console.log();
68
+ console.log(` ${(0, i18n_1.t)('cmd.help.lang')}`);
69
+ console.log();
70
+ console.log(` ${(0, i18n_1.t)('cmd.help.help')}`);
71
+ console.log(` ${(0, i18n_1.t)('cmd.help.helpDesc')}`);
72
+ console.log();
73
+ }
@@ -0,0 +1,5 @@
1
+ export declare function cmdList(options: {
2
+ today?: boolean;
3
+ tag?: string;
4
+ limit?: number;
5
+ }): void;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdList = cmdList;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const utils_1 = require("../utils");
7
+ const i18n_1 = require("../i18n");
8
+ function cmdList(options) {
9
+ const data = (0, data_1.loadData)();
10
+ let sessions = data.history;
11
+ // Filter by today
12
+ if (options.today) {
13
+ const today = (0, utils_1.formatDate)(new Date().toISOString());
14
+ sessions = sessions.filter(s => (0, utils_1.formatDate)(s.start) === today);
15
+ }
16
+ // Filter by tag
17
+ if (options.tag) {
18
+ sessions = sessions.filter(s => s.tags.includes(options.tag));
19
+ }
20
+ // Limit
21
+ const limit = options.limit ?? 10;
22
+ sessions = sessions.slice(0, limit);
23
+ console.log();
24
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.list.historyTitle'));
25
+ console.log();
26
+ if (sessions.length === 0) {
27
+ console.log(` ${(0, i18n_1.t)('cmd.list.noRecords')}`);
28
+ console.log();
29
+ return;
30
+ }
31
+ sessions.forEach((session, i) => {
32
+ const duration = session.end
33
+ ? (0, utils_1.formatDuration)(new Date(session.end).getTime() - new Date(session.start).getTime())
34
+ : (0, i18n_1.t)('common.running');
35
+ console.log(` ${i + 1}. ${session.task}`);
36
+ console.log(` 📅 ${(0, utils_1.formatTime)(session.start)} | ⏱ ${duration}`);
37
+ if (session.tags.length > 0) {
38
+ console.log(` 🏷 ${session.tags.map(tg => '#' + tg).join(' ')}`);
39
+ }
40
+ console.log();
41
+ });
42
+ }
@@ -0,0 +1 @@
1
+ export declare function cmdMark(note: string): Promise<void>;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdMark = cmdMark;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const utils_1 = require("../utils");
7
+ const i18n_1 = require("../i18n");
8
+ async function cmdMark(note) {
9
+ const data = (0, data_1.loadData)();
10
+ if (!data.current) {
11
+ console.log(`\x1b[33m⚠ ${(0, i18n_1.t)('cmd.mark.noActive')}\x1b[0m`);
12
+ return;
13
+ }
14
+ const mark = {
15
+ time: new Date().toISOString(),
16
+ note: note || (0, i18n_1.t)('cmd.mark.markPoint'),
17
+ };
18
+ data.current.marks.push(mark);
19
+ (0, data_1.saveData)(data);
20
+ const elapsed = Date.now() - new Date(data.current.start).getTime();
21
+ console.log();
22
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.mark.marked'), 'happy');
23
+ console.log();
24
+ console.log(` 📍 ${(0, utils_1.formatTime)(mark.time)} - ${mark.note}`);
25
+ console.log(` ⏱ ${(0, i18n_1.t)('cmd.mark.elapsed')}: ${(0, utils_1.formatDuration)(elapsed)}`);
26
+ console.log();
27
+ }
@@ -0,0 +1,6 @@
1
+ export declare function cmdPomodoro(task: string, options: {
2
+ work?: number;
3
+ break?: number;
4
+ rounds?: number;
5
+ tag?: string | string[];
6
+ }): Promise<void>;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdPomodoro = cmdPomodoro;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const utils_1 = require("../utils");
7
+ const i18n_1 = require("../i18n");
8
+ const tui_1 = require("../tui");
9
+ const countdown_1 = require("../tui/countdown");
10
+ function getRandomEncouragement() {
11
+ const keys = [
12
+ 'cmd.focus.encourage1', 'cmd.focus.encourage2', 'cmd.focus.encourage3',
13
+ 'cmd.focus.encourage4', 'cmd.focus.encourage5', 'cmd.focus.encourage6',
14
+ ];
15
+ return (0, i18n_1.t)(keys[Math.floor(Math.random() * keys.length)]);
16
+ }
17
+ function normalizeTags(rawTag) {
18
+ if (Array.isArray(rawTag)) {
19
+ return rawTag.flatMap(tg => tg.split(',').map(s => s.trim())).filter(Boolean);
20
+ }
21
+ if (typeof rawTag === 'string') {
22
+ return rawTag
23
+ .split(',')
24
+ .map(s => s.trim())
25
+ .filter(Boolean);
26
+ }
27
+ return [];
28
+ }
29
+ function formatMsAsClock(ms) {
30
+ const totalSec = Math.floor(ms / 1000);
31
+ const min = Math.floor(totalSec / 60);
32
+ const sec = totalSec % 60;
33
+ return `${min.toString().padStart(2, '0')}:${sec.toString().padStart(2, '0')}`;
34
+ }
35
+ function runCountdown(totalMs) {
36
+ return new Promise(resolve => {
37
+ const startTime = Date.now();
38
+ const barWidth = 20;
39
+ const interval = setInterval(() => {
40
+ const elapsed = Date.now() - startTime;
41
+ const remaining = Math.max(0, totalMs - elapsed);
42
+ const progress = Math.min(1, elapsed / totalMs);
43
+ const filled = Math.floor(progress * barWidth);
44
+ const bar = '█'.repeat(filled) + '░'.repeat(barWidth - filled);
45
+ const elapsedStr = formatMsAsClock(elapsed);
46
+ const totalStr = formatMsAsClock(totalMs);
47
+ process.stdout.write(`\r [${bar}] ${elapsedStr} / ${totalStr} `);
48
+ if (elapsed >= totalMs) {
49
+ clearInterval(interval);
50
+ process.stdout.write('\n');
51
+ process.removeListener('SIGINT', onSigint);
52
+ resolve();
53
+ }
54
+ }, 500);
55
+ // Handle Ctrl+C gracefully — exit 130 (SIGINT convention), not 0.
56
+ // runCountdown is console-only (no blessed), so no raw-mode cleanup
57
+ // needed here, but exit-code must reflect user intent.
58
+ function onSigint() {
59
+ clearInterval(interval);
60
+ process.stdout.write('\n');
61
+ process.exit(130);
62
+ }
63
+ process.once('SIGINT', onSigint);
64
+ });
65
+ }
66
+ async function cmdPomodoro(task, options) {
67
+ const data = (0, data_1.loadData)();
68
+ if (data.current) {
69
+ console.log(`\x1b[33m⚠ ${(0, i18n_1.t)('common.alreadyActive')}\x1b[0m`);
70
+ return;
71
+ }
72
+ const workMin = options.work ?? 25;
73
+ const breakMin = options.break ?? 5;
74
+ const rounds = options.rounds ?? 4;
75
+ const tags = [...normalizeTags(options.tag), 'pomodoro'];
76
+ let totalWorkMs = 0;
77
+ let totalBreakMs = 0;
78
+ console.log();
79
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.pomodoro.starting'), 'happy');
80
+ console.log();
81
+ for (let round = 1; round <= rounds; round++) {
82
+ // --- Work phase ---
83
+ const workSession = {
84
+ id: (0, utils_1.generateId)(),
85
+ start: new Date().toISOString(),
86
+ task: `${task} (${(0, i18n_1.t)('cmd.pomodoro.workPhase')} R${round})`,
87
+ tags,
88
+ marks: [],
89
+ estimatedMinutes: workMin,
90
+ };
91
+ data.current = workSession;
92
+ (0, data_1.saveData)(data);
93
+ console.log(` ${(0, i18n_1.t)('cmd.pomodoro.round', { round: String(round), total: String(rounds) })} [${(0, i18n_1.t)('cmd.pomodoro.workPhase')}]`);
94
+ console.log(` ${getRandomEncouragement()}`);
95
+ if ((0, tui_1.isInteractiveTerminal)()) {
96
+ // TUI countdown with mascot
97
+ await new Promise(resolve => {
98
+ (0, countdown_1.showCountdown)({
99
+ totalMs: workMin * 60 * 1000,
100
+ label: `${(0, i18n_1.t)('cmd.pomodoro.round', { round: String(round), total: String(rounds) })} [${(0, i18n_1.t)('cmd.pomodoro.workPhase')}]`,
101
+ mascots: [mascot_1.CACE_FOCUSED, mascot_1.CACE_HAPPY],
102
+ onDone: resolve,
103
+ });
104
+ });
105
+ }
106
+ else {
107
+ await runCountdown(workMin * 60 * 1000);
108
+ }
109
+ // Stop work session
110
+ workSession.end = new Date().toISOString();
111
+ data.history.unshift(workSession);
112
+ data.current = null;
113
+ totalWorkMs += workMin * 60 * 1000;
114
+ (0, data_1.saveData)(data);
115
+ process.stdout.write('\x07'); // bell
116
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.pomodoro.workDone'), 'happy');
117
+ console.log();
118
+ if (round < rounds) {
119
+ // --- Break phase ---
120
+ console.log(` ${(0, i18n_1.t)('cmd.pomodoro.breakTime')}`);
121
+ await runCountdown(breakMin * 60 * 1000);
122
+ totalBreakMs += breakMin * 60 * 1000;
123
+ process.stdout.write('\x07');
124
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.pomodoro.breakDone'), 'normal');
125
+ console.log();
126
+ }
127
+ }
128
+ // Final summary
129
+ console.log();
130
+ console.log(` ${(0, i18n_1.t)('cmd.pomodoro.complete')}`);
131
+ console.log(` ${(0, i18n_1.t)('cmd.pomodoro.totalWork')}: ${(0, utils_1.formatDuration)(totalWorkMs)}`);
132
+ console.log(` ${(0, i18n_1.t)('cmd.pomodoro.totalBreak')}: ${(0, utils_1.formatDuration)(totalBreakMs)}`);
133
+ console.log(` ${(0, i18n_1.t)('cmd.pomodoro.roundsCompleted')}: ${rounds}`);
134
+ console.log();
135
+ }
@@ -0,0 +1,4 @@
1
+ export declare function cmdResume(options: {
2
+ id?: string;
3
+ last?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdResume = cmdResume;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const utils_1 = require("../utils");
7
+ const i18n_1 = require("../i18n");
8
+ async function cmdResume(options) {
9
+ const data = (0, data_1.loadData)();
10
+ if (data.current) {
11
+ console.log(`\x1b[33m⚠ ${(0, i18n_1.t)('common.alreadyActive')}\x1b[0m`);
12
+ return;
13
+ }
14
+ if (data.history.length === 0) {
15
+ console.log();
16
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.resume.noHistory'), 'sleepy');
17
+ console.log();
18
+ return;
19
+ }
20
+ let source;
21
+ if (options.last) {
22
+ source = data.history[0];
23
+ }
24
+ else if (options.id) {
25
+ source = data.history.find(s => s.id === options.id);
26
+ }
27
+ if (!source) {
28
+ console.log();
29
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.resume.notFound'), 'sleepy');
30
+ console.log();
31
+ return;
32
+ }
33
+ const session = {
34
+ id: (0, utils_1.generateId)(),
35
+ start: new Date().toISOString(),
36
+ task: source.task,
37
+ tags: [...source.tags],
38
+ marks: [],
39
+ estimatedMinutes: source.estimatedMinutes,
40
+ };
41
+ data.current = session;
42
+ (0, data_1.saveData)(data);
43
+ await (0, mascot_1.showCaceAnimation)(`${(0, i18n_1.t)('cmd.resume.resumed', { task: session.task })}`);
44
+ console.log();
45
+ console.log(` 📌 ${(0, i18n_1.t)('common.task')}: ${session.task}`);
46
+ if (session.tags.length > 0) {
47
+ console.log(` 🏷 ${(0, i18n_1.t)('common.tags')}: ${session.tags.join(', ')}`);
48
+ }
49
+ if (session.estimatedMinutes) {
50
+ console.log(` ⏱ ${(0, i18n_1.t)('common.estimate')}: ${session.estimatedMinutes} min`);
51
+ }
52
+ console.log(` 🕐 ${(0, i18n_1.t)('common.start')}: ${(0, utils_1.formatTime)(session.start)}`);
53
+ console.log();
54
+ }
@@ -0,0 +1 @@
1
+ export declare function cmdSearch(keyword: string): void;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdSearch = cmdSearch;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const utils_1 = require("../utils");
7
+ const i18n_1 = require("../i18n");
8
+ function cmdSearch(keyword) {
9
+ const data = (0, data_1.loadData)();
10
+ if (!keyword || keyword.trim() === '') {
11
+ console.log();
12
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.search.noMatch'), 'sleepy');
13
+ console.log();
14
+ return;
15
+ }
16
+ const results = data.history.filter(s => s.task.toLowerCase().includes(keyword.toLowerCase()) ||
17
+ s.tags.some(tg => tg.toLowerCase().includes(keyword.toLowerCase())) ||
18
+ s.marks.some(m => m.note.toLowerCase().includes(keyword.toLowerCase())));
19
+ console.log();
20
+ (0, mascot_1.showCaceSmall)((0, i18n_1.t)('cmd.search.searchFor', { keyword }));
21
+ console.log();
22
+ if (results.length === 0) {
23
+ console.log(` ${(0, i18n_1.t)('cmd.search.noMatch')}`);
24
+ console.log();
25
+ return;
26
+ }
27
+ console.log(` ${(0, i18n_1.t)('cmd.search.found', { count: results.length })}\n`);
28
+ results.forEach((session, i) => {
29
+ const duration = session.end
30
+ ? (0, utils_1.formatDuration)(new Date(session.end).getTime() - new Date(session.start).getTime())
31
+ : (0, i18n_1.t)('common.running');
32
+ console.log(` ${i + 1}. ${session.task}`);
33
+ console.log(` 📅 ${(0, utils_1.formatTime)(session.start)} | ⏱ ${duration}`);
34
+ console.log();
35
+ });
36
+ }
@@ -0,0 +1,4 @@
1
+ export declare function cmdStart(task: string, options: {
2
+ tag?: string | string[];
3
+ estimate?: number;
4
+ }): Promise<void>;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdStart = cmdStart;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const utils_1 = require("../utils");
7
+ const i18n_1 = require("../i18n");
8
+ async function cmdStart(task, options) {
9
+ const data = (0, data_1.loadData)();
10
+ if (data.current) {
11
+ console.log(`\x1b[33m⚠ ${(0, i18n_1.t)('common.alreadyActive')}\x1b[0m`);
12
+ return;
13
+ }
14
+ // Normalize tags: support --tag dev --tag api and --tag dev,api
15
+ let tags = [];
16
+ const rawTag = options.tag;
17
+ if (Array.isArray(rawTag)) {
18
+ tags = rawTag.flatMap(tag => tag.split(',').map(s => s.trim())).filter(Boolean);
19
+ }
20
+ else if (typeof rawTag === 'string') {
21
+ tags = rawTag
22
+ .split(',')
23
+ .map(s => s.trim())
24
+ .filter(Boolean);
25
+ }
26
+ const session = {
27
+ id: (0, utils_1.generateId)(),
28
+ start: new Date().toISOString(),
29
+ task: task || (0, i18n_1.t)('cmd.start.unnamedTask'),
30
+ tags,
31
+ marks: [],
32
+ estimatedMinutes: options.estimate,
33
+ };
34
+ data.current = session;
35
+ (0, data_1.saveData)(data);
36
+ await (0, mascot_1.showCaceAnimation)(`${(0, mascot_1.getGreeting)()}!${(0, i18n_1.t)('cmd.start.recording')}: ${session.task}`);
37
+ console.log();
38
+ console.log(` 📌 ${(0, i18n_1.t)('cmd.start.taskLabel')}: ${session.task}`);
39
+ if (session.tags.length > 0) {
40
+ console.log(` 🏷 ${(0, i18n_1.t)('cmd.start.tagLabel')}: ${session.tags.join(', ')}`);
41
+ }
42
+ if (session.estimatedMinutes) {
43
+ console.log(` ⏱ ${(0, i18n_1.t)('cmd.start.estimateLabel')}: ${session.estimatedMinutes} min`);
44
+ }
45
+ console.log(` 🕐 ${(0, i18n_1.t)('cmd.start.startLabel')}: ${(0, utils_1.formatTime)(session.start)}`);
46
+ console.log();
47
+ }
@@ -0,0 +1 @@
1
+ export declare function cmdStatus(): void;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cmdStatus = cmdStatus;
4
+ const data_1 = require("../data");
5
+ const mascot_1 = require("../mascot");
6
+ const utils_1 = require("../utils");
7
+ const i18n_1 = require("../i18n");
8
+ function cmdStatus() {
9
+ const data = (0, data_1.loadData)();
10
+ const level = (0, data_1.scoreToLevel)(data.score || 0);
11
+ console.log();
12
+ (0, mascot_1.showCaceSmall)('', data.current ? 'normal' : 'sleepy');
13
+ // Always show level and streak
14
+ console.log(` ${(0, i18n_1.t)('cmd.status.level', { level: String(level), score: String(data.score || 0) })}`);
15
+ if (data.streak > 1) {
16
+ console.log(` ${(0, i18n_1.t)('score.streakFire', { days: String(data.streak) })}`);
17
+ }
18
+ else if (data.streak === 1) {
19
+ console.log(` ${(0, i18n_1.t)('score.newStreak')}`);
20
+ }
21
+ else {
22
+ console.log(` ${(0, i18n_1.t)('cmd.status.noStreak')}`);
23
+ }
24
+ if (!data.current) {
25
+ console.log();
26
+ console.log(` ${(0, i18n_1.t)('common.idle')}`);
27
+ console.log(` ${(0, i18n_1.t)('cmd.status.useStartToBegin')}`);
28
+ console.log();
29
+ return;
30
+ }
31
+ const elapsed = Date.now() - new Date(data.current.start).getTime();
32
+ console.log();
33
+ console.log(` ${(0, i18n_1.t)('cmd.status.inProgress')}`);
34
+ console.log();
35
+ console.log(` 📌 ${(0, i18n_1.t)('common.task')}: ${data.current.task}`);
36
+ console.log(` 🕐 ${(0, i18n_1.t)('common.start')}: ${(0, utils_1.formatTime)(data.current.start)}`);
37
+ console.log(` ⏱ ${(0, i18n_1.t)('cmd.mark.elapsed')}: ${(0, utils_1.formatDuration)(elapsed)}`);
38
+ if (data.current.tags.length > 0) {
39
+ console.log(` 🏷 ${(0, i18n_1.t)('common.tags')}: ${data.current.tags.join(', ')}`);
40
+ }
41
+ if (data.current.marks.length > 0) {
42
+ console.log(` 📍 ${(0, i18n_1.t)('common.marks')}: ${data.current.marks.length}`);
43
+ data.current.marks.forEach((m, i) => {
44
+ console.log(` ${i + 1}. ${(0, utils_1.formatTime)(m.time)} - ${m.note}`);
45
+ });
46
+ }
47
+ console.log();
48
+ }
@@ -0,0 +1,3 @@
1
+ export declare function cmdStop(options?: {
2
+ reflection?: string;
3
+ }): Promise<void>;