@qodalis/cli-stopwatch 2.0.0-beta.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/package.json +34 -0
- package/public-api.d.mts +48 -0
- package/public-api.d.ts +48 -0
- package/public-api.js +418 -0
- package/public-api.js.map +1 -0
- package/public-api.mjs +411 -0
- package/public-api.mjs.map +1 -0
- package/umd/cli-entrypoint.global.js +3073 -0
package/public-api.mjs
ADDED
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
import { DefaultLibraryAuthor } from '@qodalis/cli-core';
|
|
2
|
+
|
|
3
|
+
// src/lib/processors/cli-stopwatch-command-processor.ts
|
|
4
|
+
|
|
5
|
+
// src/lib/version.ts
|
|
6
|
+
var LIBRARY_VERSION = "2.0.0-beta.1";
|
|
7
|
+
var API_VERSION = 2;
|
|
8
|
+
|
|
9
|
+
// src/lib/stopwatch-utils.ts
|
|
10
|
+
var MIN_INTERVAL_MS = 1e4;
|
|
11
|
+
function parseDuration(input) {
|
|
12
|
+
if (!input.trim()) return null;
|
|
13
|
+
if (/^\d+$/.test(input.trim())) {
|
|
14
|
+
const ms = parseInt(input.trim(), 10) * 1e3;
|
|
15
|
+
return ms >= MIN_INTERVAL_MS ? ms : null;
|
|
16
|
+
}
|
|
17
|
+
const pattern = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/;
|
|
18
|
+
const match = input.trim().match(pattern);
|
|
19
|
+
if (!match || !match[0] || match[0] === "") return null;
|
|
20
|
+
const h = parseInt(match[1] ?? "0", 10);
|
|
21
|
+
const m = parseInt(match[2] ?? "0", 10);
|
|
22
|
+
const s = parseInt(match[3] ?? "0", 10);
|
|
23
|
+
const total = h * 36e5 + m * 6e4 + s * 1e3;
|
|
24
|
+
return total >= MIN_INTERVAL_MS ? total : null;
|
|
25
|
+
}
|
|
26
|
+
function formatDuration(ms) {
|
|
27
|
+
const h = Math.floor(ms / 36e5);
|
|
28
|
+
const m = Math.floor(ms % 36e5 / 6e4);
|
|
29
|
+
const s = Math.floor(ms % 6e4 / 1e3);
|
|
30
|
+
const millis = ms % 1e3;
|
|
31
|
+
return [
|
|
32
|
+
String(h).padStart(2, "0"),
|
|
33
|
+
String(m).padStart(2, "0"),
|
|
34
|
+
String(s).padStart(2, "0")
|
|
35
|
+
].join(":") + "." + String(millis).padStart(3, "0");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/lib/processors/cli-stopwatch-command-processor.ts
|
|
39
|
+
var ESC = "\x1B";
|
|
40
|
+
var CSI = `${ESC}[`;
|
|
41
|
+
var ansi = {
|
|
42
|
+
clearScreen: `${CSI}2J`,
|
|
43
|
+
cursorHome: `${CSI}H`,
|
|
44
|
+
hideCursor: `${CSI}?25l`,
|
|
45
|
+
showCursor: `${CSI}?25h`,
|
|
46
|
+
cursorTo: (row, col) => `${CSI}${row};${col}H`,
|
|
47
|
+
bold: `${CSI}1m`,
|
|
48
|
+
dim: `${CSI}2m`,
|
|
49
|
+
reset: `${CSI}0m`,
|
|
50
|
+
fg: {
|
|
51
|
+
white: `${CSI}97m`,
|
|
52
|
+
cyan: `${CSI}36m`,
|
|
53
|
+
yellow: `${CSI}93m`,
|
|
54
|
+
green: `${CSI}32m`,
|
|
55
|
+
red: `${CSI}91m`,
|
|
56
|
+
gray: `${CSI}90m`,
|
|
57
|
+
brightGreen: `${CSI}92m`,
|
|
58
|
+
brightCyan: `${CSI}96m`
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var CliStopwatchTimerCommandProcessor = class {
|
|
62
|
+
constructor() {
|
|
63
|
+
this.command = "timer";
|
|
64
|
+
this.description = "Run a countdown timer (e.g. timer 5m, timer 1h30m, timer 90s)";
|
|
65
|
+
this.author = DefaultLibraryAuthor;
|
|
66
|
+
this.version = LIBRARY_VERSION;
|
|
67
|
+
this.acceptsRawInput = true;
|
|
68
|
+
this.intervalId = null;
|
|
69
|
+
this.remaining = 0;
|
|
70
|
+
this.total = 0;
|
|
71
|
+
this.running = false;
|
|
72
|
+
this.done = false;
|
|
73
|
+
this.context = null;
|
|
74
|
+
}
|
|
75
|
+
async processCommand(command, context) {
|
|
76
|
+
const input = (command.value ?? "").trim();
|
|
77
|
+
const durationMs = parseDuration(input);
|
|
78
|
+
if (!durationMs) {
|
|
79
|
+
context.writer.writeError(
|
|
80
|
+
input ? `Invalid or too-short duration "${input}". Use formats like 30s, 5m, 1h, 2h30m (minimum 10s).` : "Usage: stopwatch timer <duration> (e.g. timer 5m)"
|
|
81
|
+
);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.total = durationMs;
|
|
85
|
+
this.remaining = durationMs;
|
|
86
|
+
this.running = true;
|
|
87
|
+
this.done = false;
|
|
88
|
+
this.context = context;
|
|
89
|
+
context.enterFullScreenMode(this);
|
|
90
|
+
this.render(context);
|
|
91
|
+
this.intervalId = setInterval(() => {
|
|
92
|
+
if (!this.running) return;
|
|
93
|
+
this.remaining = Math.max(0, this.remaining - 100);
|
|
94
|
+
this.render(context);
|
|
95
|
+
if (this.remaining === 0) {
|
|
96
|
+
this.finishTimer(context);
|
|
97
|
+
}
|
|
98
|
+
}, 100);
|
|
99
|
+
}
|
|
100
|
+
async onData(data, context) {
|
|
101
|
+
if (this.done) {
|
|
102
|
+
this.exit(context);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
switch (data) {
|
|
106
|
+
case " ":
|
|
107
|
+
case "p":
|
|
108
|
+
case "P":
|
|
109
|
+
this.running = !this.running;
|
|
110
|
+
this.render(context);
|
|
111
|
+
break;
|
|
112
|
+
case "r":
|
|
113
|
+
case "R":
|
|
114
|
+
this.remaining = this.total;
|
|
115
|
+
this.running = false;
|
|
116
|
+
this.render(context);
|
|
117
|
+
break;
|
|
118
|
+
// L=lap not applicable to countdown timer
|
|
119
|
+
case "q":
|
|
120
|
+
case "Q":
|
|
121
|
+
case "":
|
|
122
|
+
this.exit(context);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
onDispose(_context) {
|
|
127
|
+
this.clearInterval();
|
|
128
|
+
}
|
|
129
|
+
onResize(_cols, _rows, context) {
|
|
130
|
+
this.render(context);
|
|
131
|
+
}
|
|
132
|
+
finishTimer(context) {
|
|
133
|
+
this.clearInterval();
|
|
134
|
+
this.running = false;
|
|
135
|
+
this.done = true;
|
|
136
|
+
this.renderDone(context);
|
|
137
|
+
}
|
|
138
|
+
exit(context) {
|
|
139
|
+
this.clearInterval();
|
|
140
|
+
this.running = false;
|
|
141
|
+
context.exitFullScreenMode();
|
|
142
|
+
if (this.done) {
|
|
143
|
+
context.writer.writeSuccess("Timer complete!");
|
|
144
|
+
} else {
|
|
145
|
+
const elapsed = this.total - this.remaining;
|
|
146
|
+
context.writer.writeln(
|
|
147
|
+
`Timer stopped. Elapsed: ${formatDuration(elapsed)} / ${formatDuration(this.total)}`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
this.context = null;
|
|
151
|
+
}
|
|
152
|
+
clearInterval() {
|
|
153
|
+
if (this.intervalId !== null) {
|
|
154
|
+
clearInterval(this.intervalId);
|
|
155
|
+
this.intervalId = null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
render(context) {
|
|
159
|
+
const cols = context.terminal.cols;
|
|
160
|
+
const rows = context.terminal.rows;
|
|
161
|
+
const centerRow = Math.floor(rows / 2);
|
|
162
|
+
const buf = [];
|
|
163
|
+
buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);
|
|
164
|
+
const title = " COUNTDOWN TIMER ";
|
|
165
|
+
const titleCol = Math.max(1, Math.floor((cols - title.length) / 2) + 1);
|
|
166
|
+
buf.push(ansi.cursorTo(centerRow - 4, titleCol));
|
|
167
|
+
buf.push(ansi.fg.cyan, ansi.bold, title, ansi.reset);
|
|
168
|
+
const timeStr = formatDuration(this.remaining);
|
|
169
|
+
const timeCol = Math.max(1, Math.floor((cols - timeStr.length) / 2) + 1);
|
|
170
|
+
buf.push(ansi.cursorTo(centerRow - 2, timeCol));
|
|
171
|
+
buf.push(ansi.bold, ansi.fg.yellow, timeStr, ansi.reset);
|
|
172
|
+
const barWidth = Math.min(50, cols - 6);
|
|
173
|
+
const fraction = this.total > 0 ? (this.total - this.remaining) / this.total : 0;
|
|
174
|
+
const filled = Math.round(fraction * barWidth);
|
|
175
|
+
const empty = barWidth - filled;
|
|
176
|
+
const barCol = Math.max(1, Math.floor((cols - barWidth - 2) / 2) + 1);
|
|
177
|
+
buf.push(ansi.cursorTo(centerRow, barCol));
|
|
178
|
+
buf.push(ansi.fg.gray, "[", ansi.reset);
|
|
179
|
+
if (filled > 0) {
|
|
180
|
+
buf.push(ansi.fg.brightGreen, "=".repeat(filled), ansi.reset);
|
|
181
|
+
}
|
|
182
|
+
if (empty > 0) {
|
|
183
|
+
buf.push(ansi.fg.gray, " ".repeat(empty), ansi.reset);
|
|
184
|
+
}
|
|
185
|
+
buf.push(ansi.fg.gray, "]", ansi.reset);
|
|
186
|
+
const pct = Math.round(fraction * 100);
|
|
187
|
+
const pctStr = `${pct}%`;
|
|
188
|
+
const pctCol = Math.max(1, Math.floor((cols - pctStr.length) / 2) + 1);
|
|
189
|
+
buf.push(ansi.cursorTo(centerRow + 1, pctCol));
|
|
190
|
+
buf.push(ansi.fg.gray, pctStr, ansi.reset);
|
|
191
|
+
buf.push(ansi.cursorTo(centerRow + 2, Math.max(1, Math.floor((cols - 8) / 2) + 1)));
|
|
192
|
+
if (!this.running) {
|
|
193
|
+
buf.push(ansi.fg.yellow, " PAUSED ", ansi.reset);
|
|
194
|
+
} else {
|
|
195
|
+
buf.push(" ");
|
|
196
|
+
}
|
|
197
|
+
const hint = "[Space/P] Pause [R] Reset [Q] Quit";
|
|
198
|
+
const hintCol = Math.max(1, Math.floor((cols - hint.length) / 2) + 1);
|
|
199
|
+
buf.push(ansi.cursorTo(centerRow + 4, hintCol));
|
|
200
|
+
buf.push(ansi.dim, hint, ansi.reset);
|
|
201
|
+
context.terminal.write(buf.join(""));
|
|
202
|
+
}
|
|
203
|
+
renderDone(context) {
|
|
204
|
+
const cols = context.terminal.cols;
|
|
205
|
+
const rows = context.terminal.rows;
|
|
206
|
+
const centerRow = Math.floor(rows / 2);
|
|
207
|
+
const buf = [];
|
|
208
|
+
buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);
|
|
209
|
+
const msg1 = "Timer complete!";
|
|
210
|
+
const msg2 = formatDuration(this.total);
|
|
211
|
+
const msg3 = "Press any key to exit";
|
|
212
|
+
buf.push(ansi.cursorTo(centerRow - 2, Math.max(1, Math.floor((cols - msg1.length) / 2) + 1)));
|
|
213
|
+
buf.push(ansi.fg.brightGreen, ansi.bold, msg1, ansi.reset);
|
|
214
|
+
buf.push(ansi.cursorTo(centerRow, Math.max(1, Math.floor((cols - msg2.length) / 2) + 1)));
|
|
215
|
+
buf.push(ansi.fg.cyan, msg2, ansi.reset);
|
|
216
|
+
buf.push(ansi.cursorTo(centerRow + 2, Math.max(1, Math.floor((cols - msg3.length) / 2) + 1)));
|
|
217
|
+
buf.push(ansi.dim, msg3, ansi.reset);
|
|
218
|
+
context.terminal.write(buf.join(""));
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
var CliStopwatchCommandProcessor = class {
|
|
222
|
+
constructor() {
|
|
223
|
+
this.command = "stopwatch";
|
|
224
|
+
this.description = "Interactive stopwatch and countdown timer";
|
|
225
|
+
this.aliases = ["sw"];
|
|
226
|
+
this.author = DefaultLibraryAuthor;
|
|
227
|
+
this.version = LIBRARY_VERSION;
|
|
228
|
+
this.processors = [
|
|
229
|
+
new CliStopwatchTimerCommandProcessor()
|
|
230
|
+
];
|
|
231
|
+
// Stopwatch state
|
|
232
|
+
this.startTime = 0;
|
|
233
|
+
this.elapsed = 0;
|
|
234
|
+
this.running = false;
|
|
235
|
+
this.laps = [];
|
|
236
|
+
this.intervalId = null;
|
|
237
|
+
this.context = null;
|
|
238
|
+
}
|
|
239
|
+
async processCommand(_command, context) {
|
|
240
|
+
this.reset();
|
|
241
|
+
this.context = context;
|
|
242
|
+
context.enterFullScreenMode(this);
|
|
243
|
+
this.startTicking(context);
|
|
244
|
+
this.render(context);
|
|
245
|
+
}
|
|
246
|
+
async onData(data, context) {
|
|
247
|
+
switch (data) {
|
|
248
|
+
case " ":
|
|
249
|
+
case "p":
|
|
250
|
+
case "P":
|
|
251
|
+
this.togglePause(context);
|
|
252
|
+
break;
|
|
253
|
+
case "l":
|
|
254
|
+
case "L":
|
|
255
|
+
this.recordLap(context);
|
|
256
|
+
break;
|
|
257
|
+
case "r":
|
|
258
|
+
case "R":
|
|
259
|
+
this.resetAndRestart(context);
|
|
260
|
+
break;
|
|
261
|
+
case "q":
|
|
262
|
+
case "Q":
|
|
263
|
+
case "":
|
|
264
|
+
this.exit(context);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
onResize(_cols, _rows, context) {
|
|
269
|
+
this.render(context);
|
|
270
|
+
}
|
|
271
|
+
onDispose(_context) {
|
|
272
|
+
this.clearInterval();
|
|
273
|
+
}
|
|
274
|
+
writeDescription(context) {
|
|
275
|
+
const { writer } = context;
|
|
276
|
+
writer.writeln(this.description);
|
|
277
|
+
writer.writeln();
|
|
278
|
+
writer.writeln("Usage:");
|
|
279
|
+
writer.writeln(" stopwatch Start interactive stopwatch");
|
|
280
|
+
writer.writeln(" stopwatch timer <duration> Run countdown timer");
|
|
281
|
+
writer.writeln();
|
|
282
|
+
writer.writeln("Duration formats: 30s, 5m, 1h, 2h30m, 1h30m45s");
|
|
283
|
+
writer.writeln();
|
|
284
|
+
writer.writeln("Stopwatch controls:");
|
|
285
|
+
writer.writeln(" [Space/P] Pause / resume");
|
|
286
|
+
writer.writeln(" [L] Record lap");
|
|
287
|
+
writer.writeln(" [R] Reset");
|
|
288
|
+
writer.writeln(" [Q/Ctrl+C] Quit");
|
|
289
|
+
}
|
|
290
|
+
// -- Internal helpers ---------------------------------------------------
|
|
291
|
+
reset() {
|
|
292
|
+
this.clearInterval();
|
|
293
|
+
this.startTime = Date.now();
|
|
294
|
+
this.elapsed = 0;
|
|
295
|
+
this.running = true;
|
|
296
|
+
this.laps = [];
|
|
297
|
+
}
|
|
298
|
+
resetAndRestart(context) {
|
|
299
|
+
this.reset();
|
|
300
|
+
this.startTicking(context);
|
|
301
|
+
this.render(context);
|
|
302
|
+
}
|
|
303
|
+
togglePause(context) {
|
|
304
|
+
if (this.running) {
|
|
305
|
+
this.elapsed += Date.now() - this.startTime;
|
|
306
|
+
this.running = false;
|
|
307
|
+
this.clearInterval();
|
|
308
|
+
} else {
|
|
309
|
+
this.startTime = Date.now();
|
|
310
|
+
this.running = true;
|
|
311
|
+
this.startTicking(context);
|
|
312
|
+
}
|
|
313
|
+
this.render(context);
|
|
314
|
+
}
|
|
315
|
+
recordLap(context) {
|
|
316
|
+
const current = this.currentElapsed();
|
|
317
|
+
this.laps.push(current);
|
|
318
|
+
this.render(context);
|
|
319
|
+
}
|
|
320
|
+
exit(context) {
|
|
321
|
+
this.clearInterval();
|
|
322
|
+
const finalTime = this.currentElapsed();
|
|
323
|
+
context.exitFullScreenMode();
|
|
324
|
+
context.writer.writeln(`Final time: ${formatDuration(finalTime)}`);
|
|
325
|
+
if (this.laps.length > 0) {
|
|
326
|
+
context.writer.writeln("Laps:");
|
|
327
|
+
this.laps.forEach((lap, i) => {
|
|
328
|
+
context.writer.writeln(` Lap ${i + 1}: ${formatDuration(lap)}`);
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
this.context = null;
|
|
332
|
+
}
|
|
333
|
+
startTicking(context) {
|
|
334
|
+
this.clearInterval();
|
|
335
|
+
this.intervalId = setInterval(() => {
|
|
336
|
+
this.render(context);
|
|
337
|
+
}, 100);
|
|
338
|
+
}
|
|
339
|
+
clearInterval() {
|
|
340
|
+
if (this.intervalId !== null) {
|
|
341
|
+
clearInterval(this.intervalId);
|
|
342
|
+
this.intervalId = null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
currentElapsed() {
|
|
346
|
+
if (this.running) {
|
|
347
|
+
return this.elapsed + (Date.now() - this.startTime);
|
|
348
|
+
}
|
|
349
|
+
return this.elapsed;
|
|
350
|
+
}
|
|
351
|
+
// -- Rendering ----------------------------------------------------------
|
|
352
|
+
render(context) {
|
|
353
|
+
const cols = context.terminal.cols;
|
|
354
|
+
const rows = context.terminal.rows;
|
|
355
|
+
const centerRow = Math.floor(rows / 2);
|
|
356
|
+
const buf = [];
|
|
357
|
+
buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);
|
|
358
|
+
const title = " STOPWATCH ";
|
|
359
|
+
const titleCol = Math.max(1, Math.floor((cols - title.length) / 2) + 1);
|
|
360
|
+
buf.push(ansi.cursorTo(centerRow - 4, titleCol));
|
|
361
|
+
buf.push(ansi.fg.cyan, ansi.bold, title, ansi.reset);
|
|
362
|
+
const timeStr = formatDuration(this.currentElapsed());
|
|
363
|
+
const timeCol = Math.max(1, Math.floor((cols - timeStr.length) / 2) + 1);
|
|
364
|
+
buf.push(ansi.cursorTo(centerRow - 2, timeCol));
|
|
365
|
+
buf.push(ansi.bold, ansi.fg.yellow, timeStr, ansi.reset);
|
|
366
|
+
const statusStr = this.running ? " RUNNING " : " PAUSED ";
|
|
367
|
+
const statusColor = this.running ? ansi.fg.brightGreen : ansi.fg.yellow;
|
|
368
|
+
const statusCol = Math.max(1, Math.floor((cols - statusStr.length) / 2) + 1);
|
|
369
|
+
buf.push(ansi.cursorTo(centerRow, statusCol));
|
|
370
|
+
buf.push(statusColor, statusStr, ansi.reset);
|
|
371
|
+
const hint = "[Space/P] Pause [L] Lap [R] Reset [Q/Ctrl+C] Quit";
|
|
372
|
+
const hintCol = Math.max(1, Math.floor((cols - hint.length) / 2) + 1);
|
|
373
|
+
buf.push(ansi.cursorTo(centerRow + 2, hintCol));
|
|
374
|
+
buf.push(ansi.dim, hint, ansi.reset);
|
|
375
|
+
if (this.laps.length > 0) {
|
|
376
|
+
const lapsToShow = this.laps.slice(-5);
|
|
377
|
+
const startIndex = this.laps.length - lapsToShow.length;
|
|
378
|
+
lapsToShow.forEach((lap, i) => {
|
|
379
|
+
const lapIndex = startIndex + i + 1;
|
|
380
|
+
const lapStr = `Lap ${lapIndex}: ${formatDuration(lap)}`;
|
|
381
|
+
const lapCol = Math.max(1, Math.floor((cols - lapStr.length) / 2) + 1);
|
|
382
|
+
buf.push(ansi.cursorTo(centerRow + 4 + i, lapCol));
|
|
383
|
+
buf.push(ansi.fg.gray, lapStr, ansi.reset);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
context.terminal.write(buf.join(""));
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// src/public-api.ts
|
|
391
|
+
var stopwatchModule = {
|
|
392
|
+
apiVersion: API_VERSION,
|
|
393
|
+
name: "@qodalis/cli-stopwatch",
|
|
394
|
+
processors: [new CliStopwatchCommandProcessor()],
|
|
395
|
+
translations: {
|
|
396
|
+
es: { "cli.stopwatch.description": "Cron\xF3metro interactivo y temporizador" },
|
|
397
|
+
fr: { "cli.stopwatch.description": "Chronom\xE8tre interactif et minuteur" },
|
|
398
|
+
de: { "cli.stopwatch.description": "Interaktive Stoppuhr und Countdown-Timer" },
|
|
399
|
+
pt: { "cli.stopwatch.description": "Cron\xF4metro interativo e temporizador" },
|
|
400
|
+
it: { "cli.stopwatch.description": "Cronometro interattivo e timer" },
|
|
401
|
+
ja: { "cli.stopwatch.description": "\u30A4\u30F3\u30BF\u30E9\u30AF\u30C6\u30A3\u30D6\u306A\u30B9\u30C8\u30C3\u30D7\u30A6\u30A9\u30C3\u30C1\u3068\u30BF\u30A4\u30DE\u30FC" },
|
|
402
|
+
ko: { "cli.stopwatch.description": "\uB300\uD654\uD615 \uC2A4\uD1B1\uC6CC\uCE58 \uBC0F \uD0C0\uC774\uBA38" },
|
|
403
|
+
zh: { "cli.stopwatch.description": "\u4EA4\u4E92\u5F0F\u79D2\u8868\u548C\u5012\u8BA1\u65F6\u5668" },
|
|
404
|
+
ru: { "cli.stopwatch.description": "\u0418\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0439 \u0441\u0435\u043A\u0443\u043D\u0434\u043E\u043C\u0435\u0440 \u0438 \u0442\u0430\u0439\u043C\u0435\u0440 \u043E\u0431\u0440\u0430\u0442\u043D\u043E\u0433\u043E \u043E\u0442\u0441\u0447\u0451\u0442\u0430" },
|
|
405
|
+
ro: { "cli.stopwatch.description": "Cronometru interactiv \u0219i num\u0103r\u0103toare invers\u0103" }
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
export { API_VERSION, CliStopwatchCommandProcessor, LIBRARY_VERSION, formatDuration, parseDuration, stopwatchModule };
|
|
410
|
+
//# sourceMappingURL=public-api.mjs.map
|
|
411
|
+
//# sourceMappingURL=public-api.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../packages/plugins/stopwatch/src/lib/version.ts","../../packages/plugins/stopwatch/src/lib/stopwatch-utils.ts","../../packages/plugins/stopwatch/src/lib/processors/cli-stopwatch-command-processor.ts","../../packages/plugins/stopwatch/src/public-api.ts"],"names":[],"mappings":"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","file":"public-api.mjs","sourcesContent":["\n// Automatically generated during build\nexport const LIBRARY_VERSION = '2.0.0-beta.1';\nexport const API_VERSION = 2;\n ","const MIN_INTERVAL_MS = 10_000; // 10 seconds minimum\n\n/**\n * Parse duration string: 30s, 5m, 1h, 2h30m, etc.\n * Returns null for invalid or too-short durations.\n */\nexport function parseDuration(input: string): number | null {\n if (!input.trim()) return null;\n // Plain number = seconds\n if (/^\\d+$/.test(input.trim())) {\n const ms = parseInt(input.trim(), 10) * 1000;\n return ms >= MIN_INTERVAL_MS ? ms : null;\n }\n const pattern = /^(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/;\n const match = input.trim().match(pattern);\n if (!match || !match[0] || match[0] === '') return null;\n const h = parseInt(match[1] ?? '0', 10);\n const m = parseInt(match[2] ?? '0', 10);\n const s = parseInt(match[3] ?? '0', 10);\n const total = h * 3_600_000 + m * 60_000 + s * 1_000;\n return total >= MIN_INTERVAL_MS ? total : null;\n}\n\n/**\n * Format milliseconds as HH:MM:SS.mmm\n */\nexport function formatDuration(ms: number): string {\n const h = Math.floor(ms / 3_600_000);\n const m = Math.floor((ms % 3_600_000) / 60_000);\n const s = Math.floor((ms % 60_000) / 1_000);\n const millis = ms % 1_000;\n return [\n String(h).padStart(2, '0'),\n String(m).padStart(2, '0'),\n String(s).padStart(2, '0'),\n ].join(':') + '.' + String(millis).padStart(3, '0');\n}\n","import {\n CliProcessCommand,\n DefaultLibraryAuthor,\n ICliCommandProcessor,\n ICliExecutionContext,\n} from '@qodalis/cli-core';\nimport { LIBRARY_VERSION } from '../version';\nimport { formatDuration, parseDuration } from '../stopwatch-utils';\n\n// -- ANSI helpers -----------------------------------------------------------\n\nconst ESC = '\\x1b';\nconst CSI = `${ESC}[`;\n\nconst ansi = {\n clearScreen: `${CSI}2J`,\n cursorHome: `${CSI}H`,\n hideCursor: `${CSI}?25l`,\n showCursor: `${CSI}?25h`,\n cursorTo: (row: number, col: number) => `${CSI}${row};${col}H`,\n bold: `${CSI}1m`,\n dim: `${CSI}2m`,\n reset: `${CSI}0m`,\n fg: {\n white: `${CSI}97m`,\n cyan: `${CSI}36m`,\n yellow: `${CSI}93m`,\n green: `${CSI}32m`,\n red: `${CSI}91m`,\n gray: `${CSI}90m`,\n brightGreen: `${CSI}92m`,\n brightCyan: `${CSI}96m`,\n },\n};\n\n// -- Timer sub-processor ----------------------------------------------------\n\nclass CliStopwatchTimerCommandProcessor implements ICliCommandProcessor {\n command = 'timer';\n description = 'Run a countdown timer (e.g. timer 5m, timer 1h30m, timer 90s)';\n author = DefaultLibraryAuthor;\n version = LIBRARY_VERSION;\n acceptsRawInput = true;\n\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private remaining = 0;\n private total = 0;\n private running = false;\n private done = false;\n private context: ICliExecutionContext | null = null;\n\n async processCommand(\n command: CliProcessCommand,\n context: ICliExecutionContext,\n ): Promise<void> {\n const input = (command.value ?? '').trim();\n const durationMs = parseDuration(input);\n\n if (!durationMs) {\n context.writer.writeError(\n input\n ? `Invalid or too-short duration \"${input}\". Use formats like 30s, 5m, 1h, 2h30m (minimum 10s).`\n : 'Usage: stopwatch timer <duration> (e.g. timer 5m)',\n );\n return;\n }\n\n this.total = durationMs;\n this.remaining = durationMs;\n this.running = true;\n this.done = false;\n this.context = context;\n\n context.enterFullScreenMode(this);\n this.render(context);\n\n this.intervalId = setInterval(() => {\n if (!this.running) return;\n this.remaining = Math.max(0, this.remaining - 100);\n this.render(context);\n\n if (this.remaining === 0) {\n this.finishTimer(context);\n }\n }, 100);\n }\n\n async onData(data: string, context: ICliExecutionContext): Promise<void> {\n if (this.done) {\n // Any key exits\n this.exit(context);\n return;\n }\n\n switch (data) {\n case ' ':\n case 'p':\n case 'P':\n this.running = !this.running;\n this.render(context);\n break;\n case 'r':\n case 'R':\n this.remaining = this.total;\n this.running = false;\n this.render(context);\n break;\n // L=lap not applicable to countdown timer\n case 'q':\n case 'Q':\n case '\\x03': // Ctrl+C\n this.exit(context);\n break;\n }\n }\n\n onDispose(_context: ICliExecutionContext): void {\n this.clearInterval();\n }\n\n onResize(\n _cols: number,\n _rows: number,\n context: ICliExecutionContext,\n ): void {\n this.render(context);\n }\n\n private finishTimer(context: ICliExecutionContext): void {\n this.clearInterval();\n this.running = false;\n this.done = true;\n this.renderDone(context);\n }\n\n private exit(context: ICliExecutionContext): void {\n this.clearInterval();\n this.running = false;\n context.exitFullScreenMode();\n if (this.done) {\n context.writer.writeSuccess('Timer complete!');\n } else {\n const elapsed = this.total - this.remaining;\n context.writer.writeln(\n `Timer stopped. Elapsed: ${formatDuration(elapsed)} / ${formatDuration(this.total)}`,\n );\n }\n this.context = null;\n }\n\n private clearInterval(): void {\n if (this.intervalId !== null) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n\n private render(context: ICliExecutionContext): void {\n const cols = context.terminal.cols;\n const rows = context.terminal.rows;\n const centerRow = Math.floor(rows / 2);\n const buf: string[] = [];\n\n buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);\n\n // Title\n const title = ' COUNTDOWN TIMER ';\n const titleCol = Math.max(1, Math.floor((cols - title.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow - 4, titleCol));\n buf.push(ansi.fg.cyan, ansi.bold, title, ansi.reset);\n\n // Time display\n const timeStr = formatDuration(this.remaining);\n const timeCol = Math.max(1, Math.floor((cols - timeStr.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow - 2, timeCol));\n buf.push(ansi.bold, ansi.fg.yellow, timeStr, ansi.reset);\n\n // Progress bar\n const barWidth = Math.min(50, cols - 6);\n const fraction = this.total > 0 ? (this.total - this.remaining) / this.total : 0;\n const filled = Math.round(fraction * barWidth);\n const empty = barWidth - filled;\n const barCol = Math.max(1, Math.floor((cols - barWidth - 2) / 2) + 1);\n\n buf.push(ansi.cursorTo(centerRow, barCol));\n buf.push(ansi.fg.gray, '[', ansi.reset);\n if (filled > 0) {\n buf.push(ansi.fg.brightGreen, '='.repeat(filled), ansi.reset);\n }\n if (empty > 0) {\n buf.push(ansi.fg.gray, ' '.repeat(empty), ansi.reset);\n }\n buf.push(ansi.fg.gray, ']', ansi.reset);\n\n // Percentage\n const pct = Math.round(fraction * 100);\n const pctStr = `${pct}%`;\n const pctCol = Math.max(1, Math.floor((cols - pctStr.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow + 1, pctCol));\n buf.push(ansi.fg.gray, pctStr, ansi.reset);\n\n // Status / paused indicator\n buf.push(ansi.cursorTo(centerRow + 2, Math.max(1, Math.floor((cols - 8) / 2) + 1)));\n if (!this.running) {\n buf.push(ansi.fg.yellow, ' PAUSED ', ansi.reset);\n } else {\n buf.push(' ');\n }\n\n // Controls hint\n const hint = '[Space/P] Pause [R] Reset [Q] Quit';\n const hintCol = Math.max(1, Math.floor((cols - hint.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow + 4, hintCol));\n buf.push(ansi.dim, hint, ansi.reset);\n\n context.terminal.write(buf.join(''));\n }\n\n private renderDone(context: ICliExecutionContext): void {\n const cols = context.terminal.cols;\n const rows = context.terminal.rows;\n const centerRow = Math.floor(rows / 2);\n const buf: string[] = [];\n\n buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);\n\n const msg1 = 'Timer complete!';\n const msg2 = formatDuration(this.total);\n const msg3 = 'Press any key to exit';\n\n buf.push(ansi.cursorTo(centerRow - 2, Math.max(1, Math.floor((cols - msg1.length) / 2) + 1)));\n buf.push(ansi.fg.brightGreen, ansi.bold, msg1, ansi.reset);\n\n buf.push(ansi.cursorTo(centerRow, Math.max(1, Math.floor((cols - msg2.length) / 2) + 1)));\n buf.push(ansi.fg.cyan, msg2, ansi.reset);\n\n buf.push(ansi.cursorTo(centerRow + 2, Math.max(1, Math.floor((cols - msg3.length) / 2) + 1)));\n buf.push(ansi.dim, msg3, ansi.reset);\n\n context.terminal.write(buf.join(''));\n }\n}\n\n// -- Stopwatch processor ----------------------------------------------------\n\nexport class CliStopwatchCommandProcessor implements ICliCommandProcessor {\n command = 'stopwatch';\n\n description = 'Interactive stopwatch and countdown timer';\n\n aliases = ['sw'];\n\n author = DefaultLibraryAuthor;\n\n version = LIBRARY_VERSION;\n\n processors: ICliCommandProcessor[] = [\n new CliStopwatchTimerCommandProcessor(),\n ];\n\n // Stopwatch state\n private startTime = 0;\n private elapsed = 0;\n private running = false;\n private laps: number[] = [];\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private context: ICliExecutionContext | null = null;\n\n async processCommand(\n _command: CliProcessCommand,\n context: ICliExecutionContext,\n ): Promise<void> {\n this.reset();\n this.context = context;\n context.enterFullScreenMode(this);\n this.startTicking(context);\n this.render(context);\n }\n\n async onData(data: string, context: ICliExecutionContext): Promise<void> {\n switch (data) {\n case ' ':\n case 'p':\n case 'P':\n this.togglePause(context);\n break;\n case 'l':\n case 'L':\n this.recordLap(context);\n break;\n case 'r':\n case 'R':\n this.resetAndRestart(context);\n break;\n case 'q':\n case 'Q':\n case '\\x03': // Ctrl+C\n this.exit(context);\n break;\n }\n }\n\n onResize(\n _cols: number,\n _rows: number,\n context: ICliExecutionContext,\n ): void {\n this.render(context);\n }\n\n onDispose(_context: ICliExecutionContext): void {\n this.clearInterval();\n }\n\n writeDescription(context: ICliExecutionContext): void {\n const { writer } = context;\n writer.writeln(this.description!);\n writer.writeln();\n writer.writeln('Usage:');\n writer.writeln(' stopwatch Start interactive stopwatch');\n writer.writeln(' stopwatch timer <duration> Run countdown timer');\n writer.writeln();\n writer.writeln('Duration formats: 30s, 5m, 1h, 2h30m, 1h30m45s');\n writer.writeln();\n writer.writeln('Stopwatch controls:');\n writer.writeln(' [Space/P] Pause / resume');\n writer.writeln(' [L] Record lap');\n writer.writeln(' [R] Reset');\n writer.writeln(' [Q/Ctrl+C] Quit');\n }\n\n // -- Internal helpers ---------------------------------------------------\n\n private reset(): void {\n this.clearInterval();\n this.startTime = Date.now();\n this.elapsed = 0;\n this.running = true;\n this.laps = [];\n }\n\n private resetAndRestart(context: ICliExecutionContext): void {\n this.reset();\n this.startTicking(context);\n this.render(context);\n }\n\n private togglePause(context: ICliExecutionContext): void {\n if (this.running) {\n // Capture elapsed before pausing\n this.elapsed += Date.now() - this.startTime;\n this.running = false;\n this.clearInterval();\n } else {\n this.startTime = Date.now();\n this.running = true;\n this.startTicking(context);\n }\n this.render(context);\n }\n\n private recordLap(context: ICliExecutionContext): void {\n const current = this.currentElapsed();\n this.laps.push(current);\n this.render(context);\n }\n\n private exit(context: ICliExecutionContext): void {\n this.clearInterval();\n const finalTime = this.currentElapsed();\n context.exitFullScreenMode();\n context.writer.writeln(`Final time: ${formatDuration(finalTime)}`);\n if (this.laps.length > 0) {\n context.writer.writeln('Laps:');\n this.laps.forEach((lap, i) => {\n context.writer.writeln(` Lap ${i + 1}: ${formatDuration(lap)}`);\n });\n }\n this.context = null;\n }\n\n private startTicking(context: ICliExecutionContext): void {\n this.clearInterval();\n this.intervalId = setInterval(() => {\n this.render(context);\n }, 100);\n }\n\n private clearInterval(): void {\n if (this.intervalId !== null) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n\n private currentElapsed(): number {\n if (this.running) {\n return this.elapsed + (Date.now() - this.startTime);\n }\n return this.elapsed;\n }\n\n // -- Rendering ----------------------------------------------------------\n\n private render(context: ICliExecutionContext): void {\n const cols = context.terminal.cols;\n const rows = context.terminal.rows;\n const centerRow = Math.floor(rows / 2);\n const buf: string[] = [];\n\n buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);\n\n // Title\n const title = ' STOPWATCH ';\n const titleCol = Math.max(1, Math.floor((cols - title.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow - 4, titleCol));\n buf.push(ansi.fg.cyan, ansi.bold, title, ansi.reset);\n\n // Main time display\n const timeStr = formatDuration(this.currentElapsed());\n const timeCol = Math.max(1, Math.floor((cols - timeStr.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow - 2, timeCol));\n buf.push(ansi.bold, ansi.fg.yellow, timeStr, ansi.reset);\n\n // Status line\n const statusStr = this.running ? ' RUNNING ' : ' PAUSED ';\n const statusColor = this.running ? ansi.fg.brightGreen : ansi.fg.yellow;\n const statusCol = Math.max(1, Math.floor((cols - statusStr.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow, statusCol));\n buf.push(statusColor, statusStr, ansi.reset);\n\n // Controls hint\n const hint = '[Space/P] Pause [L] Lap [R] Reset [Q/Ctrl+C] Quit';\n const hintCol = Math.max(1, Math.floor((cols - hint.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow + 2, hintCol));\n buf.push(ansi.dim, hint, ansi.reset);\n\n // Laps (show last 5)\n if (this.laps.length > 0) {\n const lapsToShow = this.laps.slice(-5);\n const startIndex = this.laps.length - lapsToShow.length;\n lapsToShow.forEach((lap, i) => {\n const lapIndex = startIndex + i + 1;\n const lapStr = `Lap ${lapIndex}: ${formatDuration(lap)}`;\n const lapCol = Math.max(1, Math.floor((cols - lapStr.length) / 2) + 1);\n buf.push(ansi.cursorTo(centerRow + 4 + i, lapCol));\n buf.push(ansi.fg.gray, lapStr, ansi.reset);\n });\n }\n\n context.terminal.write(buf.join(''));\n }\n}\n","/*\n * Public API Surface of stopwatch\n */\n\nexport * from './lib/processors/cli-stopwatch-command-processor';\nexport * from './lib/stopwatch-utils';\nexport * from './lib/version';\n\nimport { ICliModule } from '@qodalis/cli-core';\nimport { CliStopwatchCommandProcessor } from './lib/processors/cli-stopwatch-command-processor';\nimport { API_VERSION } from './lib/version';\n\nexport const stopwatchModule: ICliModule = {\n apiVersion: API_VERSION,\n name: '@qodalis/cli-stopwatch',\n processors: [new CliStopwatchCommandProcessor()],\n translations: {\n es: { 'cli.stopwatch.description': 'Cronómetro interactivo y temporizador' },\n fr: { 'cli.stopwatch.description': 'Chronomètre interactif et minuteur' },\n de: { 'cli.stopwatch.description': 'Interaktive Stoppuhr und Countdown-Timer' },\n pt: { 'cli.stopwatch.description': 'Cronômetro interativo e temporizador' },\n it: { 'cli.stopwatch.description': 'Cronometro interattivo e timer' },\n ja: { 'cli.stopwatch.description': 'インタラクティブなストップウォッチとタイマー' },\n ko: { 'cli.stopwatch.description': '대화형 스톱워치 및 타이머' },\n zh: { 'cli.stopwatch.description': '交互式秒表和倒计时器' },\n ru: { 'cli.stopwatch.description': 'Интерактивный секундомер и таймер обратного отсчёта' },\n ro: { 'cli.stopwatch.description': 'Cronometru interactiv și numărătoare inversă' },\n },\n};\n"]}
|