coffee-time 1.2.0-beta.1 → 1.2.0-beta.3
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/README.md +9 -0
- package/bin/coffee-time.js +76 -9
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -34,13 +34,22 @@ Start a continuous break loop with a required interval (minutes):
|
|
|
34
34
|
coffee-time start --interval 45
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
Add a lightweight countdown ping every minute:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
coffee-time start --interval 45 --status
|
|
41
|
+
```
|
|
42
|
+
|
|
37
43
|
---
|
|
38
44
|
|
|
39
45
|
## What happens
|
|
40
46
|
|
|
41
47
|
* Prints a single startup line:
|
|
42
48
|
`Coffee breaks scheduled every 45 minutes. Press Ctrl+C to stop.`
|
|
49
|
+
* Optional status flag (`--status`) prints a countdown update every minute:
|
|
50
|
+
`⏳ Next break in 44:00`
|
|
43
51
|
* Waits 45 minutes, then triggers a break notification.
|
|
52
|
+
* After each break, countdown updates continue when `--status` is enabled.
|
|
44
53
|
* Immediately schedules the next interval and repeats until you stop it (`Ctrl+C`).
|
|
45
54
|
|
|
46
55
|
---
|
package/bin/coffee-time.js
CHANGED
|
@@ -24,11 +24,14 @@ function parseArgs(argv) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
let intervalMinutes;
|
|
27
|
+
let showStatus = false;
|
|
27
28
|
for (let i = 0; i < rest.length; i += 1) {
|
|
28
29
|
const token = rest[i];
|
|
29
30
|
if (token === '--interval') {
|
|
30
31
|
intervalMinutes = rest[i + 1];
|
|
31
32
|
i += 1;
|
|
33
|
+
} else if (token === '--status') {
|
|
34
|
+
showStatus = true;
|
|
32
35
|
} else {
|
|
33
36
|
console.error(`Unknown option: ${token}`);
|
|
34
37
|
printUsage();
|
|
@@ -48,7 +51,7 @@ function parseArgs(argv) {
|
|
|
48
51
|
process.exit(USAGE_ERROR);
|
|
49
52
|
}
|
|
50
53
|
|
|
51
|
-
return parsedInterval;
|
|
54
|
+
return { intervalMinutes: parsedInterval, showStatus };
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
function sendDesktopNotification(message) {
|
|
@@ -86,35 +89,99 @@ function attemptNotification(command, args) {
|
|
|
86
89
|
});
|
|
87
90
|
}
|
|
88
91
|
|
|
89
|
-
function notify(intervalMinutes) {
|
|
92
|
+
function notify(intervalMinutes, logLine = console.log) {
|
|
90
93
|
const message = `Time for a coffee break! (${intervalMinutes} min interval)`;
|
|
91
|
-
|
|
94
|
+
logLine(`☕ ${message}`);
|
|
92
95
|
sendDesktopNotification(message).catch(() => {});
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
function
|
|
98
|
+
function formatRemaining(remainingMs) {
|
|
99
|
+
const totalSeconds = Math.max(0, Math.ceil(remainingMs / 1000));
|
|
100
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
101
|
+
const seconds = totalSeconds % 60;
|
|
102
|
+
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function printCoffeeArt() {
|
|
106
|
+
const artLines = [
|
|
107
|
+
' ( (',
|
|
108
|
+
' ) )',
|
|
109
|
+
' ........',
|
|
110
|
+
' | |]',
|
|
111
|
+
' \\ /',
|
|
112
|
+
" '----'",
|
|
113
|
+
];
|
|
114
|
+
console.log(artLines.join('\n'));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function startLoop(intervalMinutes, options = {}) {
|
|
118
|
+
const { showStatus = false } = options;
|
|
119
|
+
let statusLength = 0;
|
|
120
|
+
let statusActive = false;
|
|
121
|
+
|
|
122
|
+
const logLine = (message) => {
|
|
123
|
+
if (statusActive) {
|
|
124
|
+
process.stdout.write('\n');
|
|
125
|
+
statusActive = false;
|
|
126
|
+
statusLength = 0;
|
|
127
|
+
}
|
|
128
|
+
console.log(message);
|
|
129
|
+
};
|
|
130
|
+
|
|
96
131
|
console.log(`Coffee breaks scheduled every ${intervalMinutes} minutes. Press Ctrl+C to stop.`);
|
|
132
|
+
printCoffeeArt();
|
|
97
133
|
|
|
134
|
+
const startedAt = Date.now();
|
|
98
135
|
const intervalMs = intervalMinutes * 60 * 1000;
|
|
99
|
-
let nextTime =
|
|
136
|
+
let nextTime = startedAt + intervalMs;
|
|
100
137
|
let timeoutId = null;
|
|
138
|
+
let statusIntervalId = null;
|
|
139
|
+
let statusTimeoutId = null;
|
|
140
|
+
|
|
141
|
+
const logStatus = () => {
|
|
142
|
+
const remaining = nextTime - Date.now();
|
|
143
|
+
const message = `⏳ Next break in ${formatRemaining(remaining)}`;
|
|
144
|
+
const paddedMessage = message.padEnd(statusLength, ' ');
|
|
145
|
+
process.stdout.write(`\r${paddedMessage}`);
|
|
146
|
+
statusLength = message.length;
|
|
147
|
+
statusActive = true;
|
|
148
|
+
};
|
|
101
149
|
|
|
102
150
|
function scheduleNext() {
|
|
103
151
|
const delay = Math.max(0, nextTime - Date.now());
|
|
104
152
|
timeoutId = setTimeout(() => {
|
|
105
|
-
notify(intervalMinutes);
|
|
153
|
+
notify(intervalMinutes, logLine);
|
|
106
154
|
nextTime += intervalMs;
|
|
155
|
+
if (showStatus) {
|
|
156
|
+
logStatus();
|
|
157
|
+
}
|
|
107
158
|
scheduleNext();
|
|
108
159
|
}, delay);
|
|
109
160
|
}
|
|
110
161
|
|
|
111
162
|
scheduleNext();
|
|
112
163
|
|
|
164
|
+
if (showStatus) {
|
|
165
|
+
const elapsed = Date.now() - startedAt;
|
|
166
|
+
const firstDelay = Math.max(0, 60 * 1000 - (elapsed % (60 * 1000)));
|
|
167
|
+
|
|
168
|
+
statusTimeoutId = setTimeout(() => {
|
|
169
|
+
logStatus();
|
|
170
|
+
statusIntervalId = setInterval(logStatus, 60 * 1000);
|
|
171
|
+
}, firstDelay);
|
|
172
|
+
}
|
|
173
|
+
|
|
113
174
|
const handleExit = () => {
|
|
114
175
|
if (timeoutId) {
|
|
115
176
|
clearTimeout(timeoutId);
|
|
116
177
|
}
|
|
117
|
-
|
|
178
|
+
if (statusTimeoutId) {
|
|
179
|
+
clearTimeout(statusTimeoutId);
|
|
180
|
+
}
|
|
181
|
+
if (statusIntervalId) {
|
|
182
|
+
clearInterval(statusIntervalId);
|
|
183
|
+
}
|
|
184
|
+
logLine('\nStopped. Stay fresh ☕');
|
|
118
185
|
process.exit(0);
|
|
119
186
|
};
|
|
120
187
|
|
|
@@ -124,8 +191,8 @@ function startLoop(intervalMinutes) {
|
|
|
124
191
|
|
|
125
192
|
function main() {
|
|
126
193
|
try {
|
|
127
|
-
const intervalMinutes = parseArgs(process.argv);
|
|
128
|
-
startLoop(intervalMinutes);
|
|
194
|
+
const { intervalMinutes, showStatus } = parseArgs(process.argv);
|
|
195
|
+
startLoop(intervalMinutes, { showStatus });
|
|
129
196
|
} catch (error) {
|
|
130
197
|
console.error('Unexpected error:', error.message);
|
|
131
198
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "1.2.0-beta.
|
|
6
|
+
"version": "1.2.0-beta.3",
|
|
7
7
|
"description": "Lightweight CLI to schedule coffee breaks at a fixed interval.",
|
|
8
8
|
"bin": {
|
|
9
9
|
"coffee-time": "./bin/coffee-time.js"
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"type": "commonjs",
|
|
13
13
|
"scripts": {
|
|
14
14
|
"start": "node ./bin/coffee-time.js"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/tborges/coffee-time"
|
|
15
19
|
},
|
|
16
20
|
"keywords": [
|
|
17
21
|
"Coffee Time",
|